[Lldb-commits] [lldb] r131713 - /lldb/trunk/scripts/disasm-gdb-remote.pl
Greg Clayton
gclayton at apple.com
Thu May 19 19:00:47 PDT 2011
Author: gclayton
Date: Thu May 19 21:00:47 2011
New Revision: 131713
URL: http://llvm.org/viewvc/llvm-project?rev=131713&view=rev
Log:
Added a perl script to disassemble, into human readable form, the GDB remote
packet output from "log enable gdb-remote packets". This should help people
track down and see what is going wrong more easily when you have log output
that includes GDB remote packets.
Added:
lldb/trunk/scripts/disasm-gdb-remote.pl (with props)
Added: lldb/trunk/scripts/disasm-gdb-remote.pl
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/disasm-gdb-remote.pl?rev=131713&view=auto
==============================================================================
--- lldb/trunk/scripts/disasm-gdb-remote.pl (added)
+++ lldb/trunk/scripts/disasm-gdb-remote.pl Thu May 19 21:00:47 2011
@@ -0,0 +1,1897 @@
+#!/usr/bin/perl
+
+use strict;
+
+#----------------------------------------------------------------------
+# Globals
+#----------------------------------------------------------------------
+our $unsupported_str = "UNSUPPORTED";
+our $success_str = "OK";
+our $swap = 1;
+our $addr_size = 4;
+our $thread_suffix_supported = 0;
+our $max_bytes_per_line = 32;
+our $addr_format = sprintf("0x%%%u.%ux", $addr_size*2, $addr_size*2);
+our $pid_format = "%04.4x";
+our $tid_format = "%04.4x";
+our $reg8_href = { extract => \&get8, format => "0x%2.2x" };
+our $reg16_href = { extract => \&get16, format => "0x%4.4x" };
+our $reg32_href = { extract => \&get32, format => "0x%8.8x" };
+our $reg64_href = { extract => \&get64, format => "0x%s" };
+our $reg80_href = { extract => \&get80, format => "0x%s" };
+our $reg128_href = { extract => \&get128, format => "0x%s" };
+our $float32_href = { extract => \&get32, format => "0x%8.8x" };
+our $float64_href = { extract => \&get64, format => "0x%s" };
+our $float96_href = { extract => \&get96, format => "0x%s" };
+our $curr_cmd = undef;
+our $reg_cmd_reg;
+our %reg_map = (
+ 'i386-gdb' => [
+ { name => 'eax', info => $reg32_href },
+ { name => 'ecx', info => $reg32_href },
+ { name => 'edx', info => $reg32_href },
+ { name => 'ebx', info => $reg32_href },
+ { name => 'esp', info => $reg32_href },
+ { name => 'ebp', info => $reg32_href },
+ { name => 'esi', info => $reg32_href },
+ { name => 'edi', info => $reg32_href },
+ { name => 'eip', info => $reg32_href },
+ { name => 'eflags', info => $reg32_href },
+ { name => 'cs', info => $reg32_href },
+ { name => 'ss', info => $reg32_href },
+ { name => 'ds', info => $reg32_href },
+ { name => 'es', info => $reg32_href },
+ { name => 'fs', info => $reg32_href },
+ { name => 'gs', info => $reg32_href },
+ { name => 'st0', info => $reg80_href },
+ { name => 'st1', info => $reg80_href },
+ { name => 'st2', info => $reg80_href },
+ { name => 'st3', info => $reg80_href },
+ { name => 'st4', info => $reg80_href },
+ { name => 'st5', info => $reg80_href },
+ { name => 'st6', info => $reg80_href },
+ { name => 'st7', info => $reg80_href },
+ { name => 'fctrl', info => $reg32_href },
+ { name => 'fstat', info => $reg32_href },
+ { name => 'ftag', info => $reg32_href },
+ { name => 'fiseg', info => $reg32_href },
+ { name => 'fioff', info => $reg32_href },
+ { name => 'foseg', info => $reg32_href },
+ { name => 'fooff', info => $reg32_href },
+ { name => 'fop', info => $reg32_href },
+ { name => 'xmm0', info => $reg128_href },
+ { name => 'xmm1', info => $reg128_href },
+ { name => 'xmm2', info => $reg128_href },
+ { name => 'xmm3', info => $reg128_href },
+ { name => 'xmm4', info => $reg128_href },
+ { name => 'xmm5', info => $reg128_href },
+ { name => 'xmm6', info => $reg128_href },
+ { name => 'xmm7', info => $reg128_href },
+ { name => 'mxcsr', info => $reg32_href },
+ { name => 'mm0', info => $reg64_href },
+ { name => 'mm1', info => $reg64_href },
+ { name => 'mm2', info => $reg64_href },
+ { name => 'mm3', info => $reg64_href },
+ { name => 'mm4', info => $reg64_href },
+ { name => 'mm5', info => $reg64_href },
+ { name => 'mm6', info => $reg64_href },
+ { name => 'mm7', info => $reg64_href },
+ ],
+
+ 'i386-lldb' => [
+ { name => 'eax', info => $reg32_href },
+ { name => 'ebx', info => $reg32_href },
+ { name => 'ecx', info => $reg32_href },
+ { name => 'edx', info => $reg32_href },
+ { name => 'edi', info => $reg32_href },
+ { name => 'esi', info => $reg32_href },
+ { name => 'ebp', info => $reg32_href },
+ { name => 'esp', info => $reg32_href },
+ { name => 'ss', info => $reg32_href },
+ { name => 'eflags', info => $reg32_href },
+ { name => 'eip', info => $reg32_href },
+ { name => 'cs', info => $reg32_href },
+ { name => 'ds', info => $reg32_href },
+ { name => 'es', info => $reg32_href },
+ { name => 'fs', info => $reg32_href },
+ { name => 'gs', info => $reg32_href },
+ { name => 'fctrl', info => $reg16_href },
+ { name => 'fstat', info => $reg16_href },
+ { name => 'ftag', info => $reg8_href },
+ { name => 'fop', info => $reg16_href },
+ { name => 'fioff', info => $reg32_href },
+ { name => 'fiseg', info => $reg16_href },
+ { name => 'fooff', info => $reg32_href },
+ { name => 'foseg', info => $reg16_href },
+ { name => 'mxcsr', info => $reg32_href },
+ { name => 'mxcsrmask', info => $reg32_href },
+ { name => 'stmm0', info => $reg80_href },
+ { name => 'stmm1', info => $reg80_href },
+ { name => 'stmm2', info => $reg80_href },
+ { name => 'stmm3', info => $reg80_href },
+ { name => 'stmm4', info => $reg80_href },
+ { name => 'stmm5', info => $reg80_href },
+ { name => 'stmm6', info => $reg80_href },
+ { name => 'stmm7', info => $reg80_href },
+ { name => 'xmm0', info => $reg128_href },
+ { name => 'xmm1', info => $reg128_href },
+ { name => 'xmm2', info => $reg128_href },
+ { name => 'xmm3', info => $reg128_href },
+ { name => 'xmm4', info => $reg128_href },
+ { name => 'xmm5', info => $reg128_href },
+ { name => 'xmm6', info => $reg128_href },
+ { name => 'xmm7', info => $reg128_href },
+ { name => 'trapno', info => $reg32_href },
+ { name => 'err', info => $reg32_href },
+ { name => 'faultvaddr', info => $reg32_href },
+ ],
+
+ 'arm-gdb' => [
+ { name => 'r0' , info => $reg32_href },
+ { name => 'r1' , info => $reg32_href },
+ { name => 'r2' , info => $reg32_href },
+ { name => 'r3' , info => $reg32_href },
+ { name => 'r4' , info => $reg32_href },
+ { name => 'r5' , info => $reg32_href },
+ { name => 'r6' , info => $reg32_href },
+ { name => 'r7' , info => $reg32_href },
+ { name => 'r8' , info => $reg32_href },
+ { name => 'r9' , info => $reg32_href },
+ { name => 'r10' , info => $reg32_href },
+ { name => 'r11' , info => $reg32_href },
+ { name => 'r12' , info => $reg32_href },
+ { name => 'sp' , info => $reg32_href },
+ { name => 'lr' , info => $reg32_href },
+ { name => 'pc' , info => $reg32_href },
+ { name => 'f0' , info => $float96_href },
+ { name => 'f1' , info => $float96_href },
+ { name => 'f2' , info => $float96_href },
+ { name => 'f3' , info => $float96_href },
+ { name => 'f4' , info => $float96_href },
+ { name => 'f5' , info => $float96_href },
+ { name => 'f6' , info => $float96_href },
+ { name => 'f7' , info => $float96_href },
+ { name => 'fps' , info => $reg32_href },
+ { name => 'cpsr' , info => $reg32_href },
+ { name => 's0' , info => $float32_href },
+ { name => 's1' , info => $float32_href },
+ { name => 's2' , info => $float32_href },
+ { name => 's3' , info => $float32_href },
+ { name => 's4' , info => $float32_href },
+ { name => 's5' , info => $float32_href },
+ { name => 's6' , info => $float32_href },
+ { name => 's7' , info => $float32_href },
+ { name => 's8' , info => $float32_href },
+ { name => 's9' , info => $float32_href },
+ { name => 's10' , info => $float32_href },
+ { name => 's11' , info => $float32_href },
+ { name => 's12' , info => $float32_href },
+ { name => 's13' , info => $float32_href },
+ { name => 's14' , info => $float32_href },
+ { name => 's15' , info => $float32_href },
+ { name => 's16' , info => $float32_href },
+ { name => 's17' , info => $float32_href },
+ { name => 's18' , info => $float32_href },
+ { name => 's19' , info => $float32_href },
+ { name => 's20' , info => $float32_href },
+ { name => 's21' , info => $float32_href },
+ { name => 's22' , info => $float32_href },
+ { name => 's23' , info => $float32_href },
+ { name => 's24' , info => $float32_href },
+ { name => 's25' , info => $float32_href },
+ { name => 's26' , info => $float32_href },
+ { name => 's27' , info => $float32_href },
+ { name => 's28' , info => $float32_href },
+ { name => 's29' , info => $float32_href },
+ { name => 's30' , info => $float32_href },
+ { name => 's31' , info => $float32_href },
+ { name => 'fpscr' , info => $reg32_href },
+ { name => 'd16' , info => $float64_href },
+ { name => 'd17' , info => $float64_href },
+ { name => 'd18' , info => $float64_href },
+ { name => 'd19' , info => $float64_href },
+ { name => 'd20' , info => $float64_href },
+ { name => 'd21' , info => $float64_href },
+ { name => 'd22' , info => $float64_href },
+ { name => 'd23' , info => $float64_href },
+ { name => 'd24' , info => $float64_href },
+ { name => 'd25' , info => $float64_href },
+ { name => 'd26' , info => $float64_href },
+ { name => 'd27' , info => $float64_href },
+ { name => 'd28' , info => $float64_href },
+ { name => 'd29' , info => $float64_href },
+ { name => 'd30' , info => $float64_href },
+ { name => 'd31' , info => $float64_href },
+ ],
+
+ 'x86_64-gdb' => [
+ { name => 'rax' , info => $reg64_href },
+ { name => 'rbx' , info => $reg64_href },
+ { name => 'rcx' , info => $reg64_href },
+ { name => 'rdx' , info => $reg64_href },
+ { name => 'rsi' , info => $reg64_href },
+ { name => 'rdi' , info => $reg64_href },
+ { name => 'rbp' , info => $reg64_href },
+ { name => 'rsp' , info => $reg64_href },
+ { name => 'r8' , info => $reg64_href },
+ { name => 'r9' , info => $reg64_href },
+ { name => 'r10' , info => $reg64_href },
+ { name => 'r11' , info => $reg64_href },
+ { name => 'r12' , info => $reg64_href },
+ { name => 'r13' , info => $reg64_href },
+ { name => 'r14' , info => $reg64_href },
+ { name => 'r15' , info => $reg64_href },
+ { name => 'rip' , info => $reg64_href },
+ { name => 'eflags' , info => $reg32_href },
+ { name => 'cs' , info => $reg32_href },
+ { name => 'ss' , info => $reg32_href },
+ { name => 'ds' , info => $reg32_href },
+ { name => 'es' , info => $reg32_href },
+ { name => 'fs' , info => $reg32_href },
+ { name => 'gs' , info => $reg32_href },
+ { name => 'stmm0' , info => $reg80_href },
+ { name => 'stmm1' , info => $reg80_href },
+ { name => 'stmm2' , info => $reg80_href },
+ { name => 'stmm3' , info => $reg80_href },
+ { name => 'stmm4' , info => $reg80_href },
+ { name => 'stmm5' , info => $reg80_href },
+ { name => 'stmm6' , info => $reg80_href },
+ { name => 'stmm7' , info => $reg80_href },
+ { name => 'fctrl' , info => $reg32_href },
+ { name => 'fstat' , info => $reg32_href },
+ { name => 'ftag' , info => $reg32_href },
+ { name => 'fiseg' , info => $reg32_href },
+ { name => 'fioff' , info => $reg32_href },
+ { name => 'foseg' , info => $reg32_href },
+ { name => 'fooff' , info => $reg32_href },
+ { name => 'fop' , info => $reg32_href },
+ { name => 'xmm0' , info => $reg128_href },
+ { name => 'xmm1' , info => $reg128_href },
+ { name => 'xmm2' , info => $reg128_href },
+ { name => 'xmm3' , info => $reg128_href },
+ { name => 'xmm4' , info => $reg128_href },
+ { name => 'xmm5' , info => $reg128_href },
+ { name => 'xmm6' , info => $reg128_href },
+ { name => 'xmm7' , info => $reg128_href },
+ { name => 'xmm8' , info => $reg128_href },
+ { name => 'xmm9' , info => $reg128_href },
+ { name => 'xmm10' , info => $reg128_href },
+ { name => 'xmm11' , info => $reg128_href },
+ { name => 'xmm12' , info => $reg128_href },
+ { name => 'xmm13' , info => $reg128_href },
+ { name => 'xmm14' , info => $reg128_href },
+ { name => 'xmm15' , info => $reg128_href },
+ { name => 'mxcsr' , info => $reg32_href },
+ ],
+
+ 'x86_64-lldb' => [
+ { name => 'rax' , info => $reg64_href },
+ { name => 'rbx' , info => $reg64_href },
+ { name => 'rcx' , info => $reg64_href },
+ { name => 'rdx' , info => $reg64_href },
+ { name => 'rdi' , info => $reg64_href },
+ { name => 'rsi' , info => $reg64_href },
+ { name => 'rbp' , info => $reg64_href },
+ { name => 'rsp' , info => $reg64_href },
+ { name => 'r8 ' , info => $reg64_href },
+ { name => 'r9 ' , info => $reg64_href },
+ { name => 'r10' , info => $reg64_href },
+ { name => 'r11' , info => $reg64_href },
+ { name => 'r12' , info => $reg64_href },
+ { name => 'r13' , info => $reg64_href },
+ { name => 'r14' , info => $reg64_href },
+ { name => 'r15' , info => $reg64_href },
+ { name => 'rip' , info => $reg64_href },
+ { name => 'rflags' , info => $reg64_href },
+ { name => 'cs' , info => $reg64_href },
+ { name => 'fs' , info => $reg64_href },
+ { name => 'gs' , info => $reg64_href },
+ { name => 'fctrl' , info => $reg16_href },
+ { name => 'fstat' , info => $reg16_href },
+ { name => 'ftag' , info => $reg8_href },
+ { name => 'fop' , info => $reg16_href },
+ { name => 'fioff' , info => $reg32_href },
+ { name => 'fiseg' , info => $reg16_href },
+ { name => 'fooff' , info => $reg32_href },
+ { name => 'foseg' , info => $reg16_href },
+ { name => 'mxcsr' , info => $reg32_href },
+ { name => 'mxcsrmask' , info => $reg32_href },
+ { name => 'stmm0' , info => $reg80_href },
+ { name => 'stmm1' , info => $reg80_href },
+ { name => 'stmm2' , info => $reg80_href },
+ { name => 'stmm3' , info => $reg80_href },
+ { name => 'stmm4' , info => $reg80_href },
+ { name => 'stmm5' , info => $reg80_href },
+ { name => 'stmm6' , info => $reg80_href },
+ { name => 'stmm7' , info => $reg80_href },
+ { name => 'xmm0' , info => $reg128_href },
+ { name => 'xmm1' , info => $reg128_href },
+ { name => 'xmm2' , info => $reg128_href },
+ { name => 'xmm3' , info => $reg128_href },
+ { name => 'xmm4' , info => $reg128_href },
+ { name => 'xmm5' , info => $reg128_href },
+ { name => 'xmm6' , info => $reg128_href },
+ { name => 'xmm7' , info => $reg128_href },
+ { name => 'xmm8' , info => $reg128_href },
+ { name => 'xmm9' , info => $reg128_href },
+ { name => 'xmm10' , info => $reg128_href },
+ { name => 'xmm11' , info => $reg128_href },
+ { name => 'xmm12' , info => $reg128_href },
+ { name => 'xmm13' , info => $reg128_href },
+ { name => 'xmm14' , info => $reg128_href },
+ { name => 'xmm15' , info => $reg128_href },
+ { name => 'trapno' , info => $reg32_href },
+ { name => 'err' , info => $reg32_href },
+ { name => 'faultvaddr' , info => $reg64_href },
+ ]
+);
+
+our $max_register_name_len = 0;
+calculate_max_register_name_length();
+our @point_types = ( "software_bp", "hardware_bp", "write_wp", "read_wp", "access_wp" );
+our $opt_v = 0; # verbose
+our $opt_g = 0; # debug
+our $opt_q = 0; # quiet
+our $opt_r = undef;
+use Getopt::Std;
+getopts('gvqr:');
+
+our $registers_aref = undef;
+
+if (length($opt_r))
+{
+ $registers_aref = $reg_map{$opt_r};
+}
+
+sub extract_key_value_pairs
+{
+ my $kv_href = {};
+ my $arrayref = shift;
+ my $str = join('',@$arrayref);
+ my @kv_strs = split(/;/, $str);
+ foreach my $kv_str (@kv_strs)
+ {
+ my ($key, $value) = split(/:/, $kv_str);
+ $kv_href->{$key} = $value;
+ }
+ return $kv_href;
+}
+
+sub get_thread_from_thread_suffix
+{
+ if ($thread_suffix_supported)
+ {
+ my $arrayref = shift;
+ # Skip leading semi-colon if needed
+ $$arrayref[0] == ';' and shift @$arrayref;
+ my $thread_href = extract_key_value_pairs ($arrayref);
+ if (exists $thread_href->{thread})
+ {
+ return $thread_href->{thread};
+ }
+ }
+ return undef;
+}
+
+sub calculate_max_register_name_length
+{
+ $max_register_name_len = 7;
+ foreach my $reg_href (@$registers_aref)
+ {
+ my $name_len = length($reg_href->{name});
+ if ($max_register_name_len < $name_len)
+ {
+ $max_register_name_len = $name_len;
+ }
+ }
+}
+#----------------------------------------------------------------------
+# Hash that maps command characters to the appropriate functions using
+# the command character as the key and the value being a reference to
+# the dump function for dumping the command itself.
+#----------------------------------------------------------------------
+our %cmd_callbacks =
+(
+ '?' => \&dump_last_signal_cmd,
+ 'H' => \&dump_set_thread_cmd,
+ 'T' => \&dump_thread_is_alive_cmd,
+ 'q' => \&dump_general_query_cmd,
+ 'Q' => \&dump_general_set_cmd,
+ 'g' => \&dump_read_regs_cmd,
+ 'G' => \&dump_write_regs_cmd,
+ 'p' => \&dump_read_single_register_cmd,
+ 'P' => \&dump_write_single_register_cmd,
+ 'm' => \&dump_read_mem_cmd,
+ 'M' => \&dump_write_mem_cmd,
+ 'X' => \&dump_write_mem_binary_cmd,
+ 'Z' => \&dump_bp_wp_command,
+ 'z' => \&dump_bp_wp_command,
+ 'k' => \&dump_kill_cmd,
+ 'A' => \&dump_A_command,
+ 'c' => \&dump_continue_cmd,
+ 'C' => \&dump_continue_with_signal_cmd,
+ '_M' => \&dump_allocate_memory_cmd,
+ '_m' => \&dump_deallocate_memory_cmd,
+ # extended commands
+ 'v' => \&dump_extended_cmd
+);
+
+#----------------------------------------------------------------------
+# Hash that maps command characters to the appropriate functions using
+# the command character as the key and the value being a reference to
+# the dump function for the response to the command.
+#----------------------------------------------------------------------
+our %rsp_callbacks =
+(
+ 'c' => \&dump_stop_reply_packet,
+ 'C' => \&dump_stop_reply_packet,
+ '?' => \&dump_stop_reply_packet,
+ 'T' => \&dump_thread_is_alive_rsp,
+ 'H' => \&dump_set_thread_rsp,
+ 'q' => \&dump_general_query_rsp,
+ 'g' => \&dump_read_regs_rsp,
+ 'p' => \&dump_read_single_register_rsp,
+ 'm' => \&dump_read_mem_rsp,
+ '_M' => \&dump_allocate_memory_rsp,
+
+ # extended commands
+ 'v' => \&dump_extended_rsp,
+);
+
+
+sub dump_register_value
+{
+ my $indent = shift;
+ my $arrayref = shift;
+ my $reg_num = shift;
+
+ if ($reg_num >= @$registers_aref)
+ {
+ printf("\tinvalid register index %d\n", $reg_num);
+ }
+
+ my $reg_href = $$registers_aref[$reg_num];
+ my $reg_name = $reg_href->{name};
+ if ($$arrayref[0] eq '#')
+ {
+ printf("\t%*s: error: EOS reached when trying to read register %d\n", $max_register_name_len, $reg_name, $reg_num);
+ }
+
+ my $reg_info = $reg_href->{info};
+ my $reg_extract = $reg_info->{extract};
+ my $reg_format = $reg_info->{format};
+ my $reg_val = &$reg_extract($arrayref);
+ if ($indent) {
+ printf("\t%*s = $reg_format", $max_register_name_len, $reg_name, $reg_val);
+ } else {
+ printf("%s = $reg_format", $reg_name, $reg_val);
+ }
+}
+
+#----------------------------------------------------------------------
+# Extract the command into an array of ASCII char strings for easy
+# processing
+#----------------------------------------------------------------------
+sub extract_command
+{
+ my $cmd_str = shift;
+ my @cmd_chars = split(/ */, $cmd_str);
+ if ($cmd_chars[0] ne '$')
+ {
+ # only set the current command if it isn't a reply
+ $curr_cmd = $cmd_chars[0];
+ }
+ return @cmd_chars;
+}
+
+#----------------------------------------------------------------------
+# Strip the 3 checksum array entries after we don't need them anymore
+#----------------------------------------------------------------------
+sub strip_checksum
+{
+ my $arrayref = shift;
+ splice(@$arrayref, -3);
+}
+
+#----------------------------------------------------------------------
+# Dump all strings in array by joining them together with no space
+# between them
+#----------------------------------------------------------------------
+sub dump_chars
+{
+ print join('', at _);
+}
+
+#----------------------------------------------------------------------
+# Check if the response is an error 'EXX'
+#----------------------------------------------------------------------
+sub is_error_response
+{
+ if ($_[0] eq 'E')
+ {
+ shift;
+ print "ERROR = " . join('', at _) . "\n";
+ return 1;
+ }
+ return 0;
+}
+
+#----------------------------------------------------------------------
+# 'H' command
+#----------------------------------------------------------------------
+sub dump_set_thread_cmd
+{
+ my $cmd = shift;
+ my $mod = shift;
+ print "set_thread ( $mod, " . join('', at _) . " )\n";
+}
+
+#----------------------------------------------------------------------
+# 'T' command
+#----------------------------------------------------------------------
+our $T_cmd_tid = -1;
+sub dump_thread_is_alive_cmd
+{
+ my $cmd = shift;
+ $T_cmd_tid = get_hex(\@_);
+ printf("thread_is_alive ( $tid_format )\n", $T_cmd_tid);
+}
+
+sub dump_thread_is_alive_rsp
+{
+ my $rsp = join('', at _);
+
+ printf("thread_is_alive ( $tid_format ) =>", $T_cmd_tid);
+ if ($rsp eq 'OK')
+ {
+ print " alive.\n";
+ }
+ else
+ {
+ print " dead.\n";
+ }
+}
+
+#----------------------------------------------------------------------
+# 'H' response
+#----------------------------------------------------------------------
+sub dump_set_thread_rsp
+{
+ if (!is_error_response(@_))
+ {
+ print join('', at _) . "\n";
+ }
+}
+
+#----------------------------------------------------------------------
+# 'q' command
+#----------------------------------------------------------------------
+our $gen_query_cmd;
+sub dump_general_query_cmd
+{
+ $gen_query_cmd = join('', at _);
+ if ($gen_query_cmd eq 'qC')
+ {
+ print 'get_current_pid ()';
+ }
+ elsif ($gen_query_cmd eq 'qfThreadInfo')
+ {
+ print 'get_first_active_threads ()';
+ }
+ elsif ($gen_query_cmd eq 'qsThreadInfo')
+ {
+ print 'get_subsequent_active_threads ()';
+ }
+ elsif (index($gen_query_cmd, 'qThreadExtraInfo') == 0)
+ {
+ # qThreadExtraInfo,id
+ print 'get_thread_extra_info ()';
+ }
+ elsif (index($gen_query_cmd, 'qThreadStopInfo') == 0)
+ {
+ # qThreadStopInfoXXXX
+ @_ = splice(@_, length('qThreadStopInfo'));
+ my $tid = get_addr(\@_);
+ printf('get_thread_stop_info ( thread = 0x%4.4x )', $tid);
+ }
+ elsif (index($gen_query_cmd, 'qSymbol:') == 0)
+ {
+ # qCRC:addr,length
+ print 'gdb_ready_to_serve_symbol_lookups ()';
+ }
+ elsif (index($gen_query_cmd, 'qCRC:') == 0)
+ {
+ # qCRC:addr,length
+ @_ = splice(@_, length('qCRC:'));
+ my $address = get_addr(\@_);
+ shift @_;
+ my $length = join('', @_);
+ printf("compute_crc (addr = $addr_format, length = $length)", $address);
+ }
+ elsif (index($gen_query_cmd, 'qGetTLSAddr:') == 0)
+ {
+ # qGetTLSAddr:thread-id,offset,lm
+ @_ = splice(@_, length('qGetTLSAddr:'));
+ my ($tid, $offset, $lm) = split (/,/, join('', @_));
+ print "get_thread_local_storage_addr (thread-id = $tid, offset = $offset, lm = $lm)";
+ }
+ elsif ($gen_query_cmd eq 'qOffsets')
+ {
+ print 'get_section_offsets ()';
+ }
+ elsif (index($gen_query_cmd, 'qRegisterInfo') == 0)
+ {
+ @_ = splice(@_, length('qRegisterInfo'));
+ my $reg = get_hex(\@_);
+ $reg == 0 and $registers_aref = [];
+
+ printf "get_dynamic_register_info ($reg)";
+ }
+ else
+ {
+ print $gen_query_cmd;
+ }
+ print "\n";
+}
+
+#----------------------------------------------------------------------
+# 'q' response
+#----------------------------------------------------------------------
+sub dump_general_query_rsp
+{
+ my $gen_query_rsp = join('', at _);
+
+ if ($gen_query_cmd eq 'qC' and index($gen_query_rsp, 'QC') == 0)
+ {
+ shift @_; shift @_;
+ my $pid = get_hex(\@_);
+ printf("get_current_pid () => $pid_format\n", $pid);
+ return;
+ }
+ elsif (index($gen_query_cmd, 'qRegisterInfo') == 0)
+ {
+ if (index($gen_query_rsp, 'name') == 0)
+ {
+ my @name_and_values = split (/;/, $gen_query_rsp);
+
+ my $reg_name = undef;
+ my $byte_size = 0;
+ foreach (@name_and_values)
+ {
+ my ($name, $value) = split /:/;
+ if ($name eq "name") { $reg_name = $value; }
+ elsif ($name eq "bitsize") { $byte_size = $value / 8; last; }
+ }
+ if (defined $reg_name and $byte_size > 0)
+ {
+ if ($byte_size == 4) {push @$registers_aref, { name => $reg_name, info => $reg32_href };}
+ elsif ($byte_size == 8) {push @$registers_aref, { name => $reg_name, info => $reg64_href };}
+ elsif ($byte_size == 10) {push @$registers_aref, { name => $reg_name, info => $reg80_href };}
+ elsif ($byte_size == 12) {push @$registers_aref, { name => $reg_name, info => $float96_href };}
+ elsif ($byte_size == 16) {push @$registers_aref, { name => $reg_name, info => $reg128_href };}
+ }
+ }
+ else
+ {
+ calculate_max_register_name_length();
+ }
+ }
+ elsif ($gen_query_cmd =~ 'qThreadStopInfo')
+ {
+ dump_stop_reply_packet (@_);
+ }
+ if (dump_standard_response(\@_))
+ {
+ # Do nothing...
+ }
+ else
+ {
+ print join('', at _) . "\n";
+ }
+}
+
+#----------------------------------------------------------------------
+# 'Q' command
+#----------------------------------------------------------------------
+our $gen_set_cmd;
+sub dump_general_set_cmd
+{
+ $gen_query_cmd = join('', at _);
+ if ($gen_query_cmd eq 'QStartNoAckMode')
+ {
+ print "StartNoAckMode ()"
+ }
+ elsif ($gen_query_cmd eq 'QThreadSuffixSupported')
+ {
+ $thread_suffix_supported = 1;
+ print "ThreadSuffixSupported ()"
+ }
+ elsif (index($gen_query_cmd, 'QSetMaxPayloadSize:') == 0)
+ {
+ @_ = splice(@_, length('QSetMaxPayloadSize:'));
+ my $max_payload_size = get_hex(\@_);
+ # QSetMaxPayloadSize:XXXX where XXXX is a hex length of the max
+ # packet payload size supported by gdb
+ printf("SetMaxPayloadSize ( 0x%x (%u))", $max_payload_size, $max_payload_size);
+ }
+ else
+ {
+ print $gen_query_cmd;
+ }
+ print "\n";
+}
+
+#----------------------------------------------------------------------
+# 'k' command
+#----------------------------------------------------------------------
+sub dump_kill_cmd
+{
+ my $cmd = shift;
+ print "kill (" . join('', at _) . ")\n";
+}
+
+#----------------------------------------------------------------------
+# 'g' command
+#----------------------------------------------------------------------
+sub dump_read_regs_cmd
+{
+ my $cmd = shift;
+ print "read_registers ()\n";
+}
+
+#----------------------------------------------------------------------
+# 'G' command
+#----------------------------------------------------------------------
+sub dump_write_regs_cmd
+{
+ print "write_registers:\n";
+ my $cmd = shift;
+ foreach my $reg_href (@$registers_aref)
+ {
+ last if ($_[0] eq '#');
+ my $reg_info_href = $reg_href->{info};
+ my $reg_name = $reg_href->{name};
+ my $reg_extract = $reg_info_href->{extract};
+ my $reg_format = $reg_info_href->{format};
+ my $reg_val = &$reg_extract(\@_);
+ printf("\t%*s = $reg_format\n", $max_register_name_len, $reg_name, $reg_val);
+ }
+}
+
+sub dump_read_regs_rsp
+{
+ print "read_registers () =>\n";
+ if (!is_error_response(@_))
+ {
+ # print join('', at _) . "\n";
+ foreach my $reg_href (@$registers_aref)
+ {
+ last if ($_[0] eq '#');
+ my $reg_info_href = $reg_href->{info};
+ my $reg_name = $reg_href->{name};
+ my $reg_extract = $reg_info_href->{extract};
+ my $reg_format = $reg_info_href->{format};
+ my $reg_val = &$reg_extract(\@_);
+ printf("\t%*s = $reg_format\n", $max_register_name_len, $reg_name, $reg_val);
+ }
+ }
+}
+
+sub dump_read_single_register_rsp
+{
+ dump_register_value(0, \@_, $reg_cmd_reg);
+ print "\n";
+}
+
+#----------------------------------------------------------------------
+# '_M' - allocate memory command (LLDB extension)
+#
+# Command: '_M'
+# Arg1: Hex byte size as big endian hex string
+# Separator: ','
+# Arg2: permissions as string that must be a string that contains any
+# combination of 'r' (readable) 'w' (writable) or 'x' (executable)
+#
+# Returns: The address that was allocated as a big endian hex string
+# on success, else an error "EXX" where XX are hex bytes
+# that indicate an error code.
+#
+# Examples:
+# _M10,rw # allocate 16 bytes with read + write permissions
+# _M100,rx # allocate 256 bytes with read + execute permissions
+#----------------------------------------------------------------------
+sub dump_allocate_memory_cmd
+{
+ shift; shift; # shift off the '_' and the 'M'
+ my $byte_size = get_addr(\@_);
+ shift; # Skip ','
+ printf("allocate_memory ( byte_size = %u (0x%x), permissions = %s)\n", $byte_size, $byte_size, join('', at _));
+}
+
+sub dump_allocate_memory_rsp
+{
+ if (@_ == 3 and $_[0] == 'E')
+ {
+ printf("allocated memory addr = ERROR (%s))\n", join('', at _));
+ }
+ else
+ {
+ printf("allocated memory addr = 0x%s\n", join('', at _));
+ }
+}
+
+
+#----------------------------------------------------------------------
+# '_m' - deallocate memory command (LLDB extension)
+#
+# Command: '_m'
+# Arg1: Hex address as big endian hex string
+#
+# Returns: "OK" on success "EXX" on error
+#
+# Examples:
+# _m201000 # Free previously allocated memory at address 0x201000
+#----------------------------------------------------------------------
+sub dump_deallocate_memory_cmd
+{
+ shift; shift; # shift off the '_' and the 'm'
+ printf("deallocate_memory ( addr = 0x%s)\n", join('', at _));
+}
+
+
+#----------------------------------------------------------------------
+# 'p' command
+#----------------------------------------------------------------------
+sub dump_read_single_register_cmd
+{
+ my $cmd = shift;
+ $reg_cmd_reg = get_hex(\@_);
+ my $thread = get_thread_from_thread_suffix (\@_);
+ if (defined $thread)
+ {
+ print "read_register ( reg = \"$$registers_aref[$reg_cmd_reg]->{name}\", thread = $thread )\n";
+ }
+ else
+ {
+ print "read_register ( reg = \"$$registers_aref[$reg_cmd_reg]->{name}\" )\n";
+ }
+}
+
+
+#----------------------------------------------------------------------
+# 'P' command
+#----------------------------------------------------------------------
+sub dump_write_single_register_cmd
+{
+ my $cmd = shift;
+ my $reg_num = get_hex(\@_);
+ shift (@_); # Discard the '='
+
+ print "write_register ( ";
+ dump_register_value(0, \@_, $reg_num);
+ my $thread = get_thread_from_thread_suffix (\@_);
+ if (defined $thread)
+ {
+ print ", thread = $thread";
+ }
+ print " )\n";
+}
+
+#----------------------------------------------------------------------
+# 'm' command
+#----------------------------------------------------------------------
+our $read_mem_address = 0;
+sub dump_read_mem_cmd
+{
+ my $cmd = shift;
+ $read_mem_address = get_addr(\@_);
+ shift; # Skip ','
+ printf("read_mem ( $addr_format, %s )\n", $read_mem_address, join('', at _));
+}
+
+#----------------------------------------------------------------------
+# 'm' response
+#----------------------------------------------------------------------
+sub dump_read_mem_rsp
+{
+ # If the memory read was 2 or 4 bytes, print it out in native format
+ # instead of just as bytes.
+ my $num_nibbles = @_;
+ if ($num_nibbles == 2)
+ {
+ printf(" 0x%2.2x", get8(\@_));
+ }
+ elsif ($num_nibbles == 4)
+ {
+ printf(" 0x%4.4x", get16(\@_));
+ }
+ elsif ($num_nibbles == 8)
+ {
+ printf(" 0x%8.8x", get32(\@_));
+ }
+ elsif ($num_nibbles == 16)
+ {
+ printf(" 0x%s", get64(\@_));
+ }
+ else
+ {
+ my $curr_address = $read_mem_address;
+ my $nibble;
+ my $nibble_offset = 0;
+ my $max_nibbles_per_line = 2 * $max_bytes_per_line;
+ foreach $nibble (@_)
+ {
+ if (($nibble_offset % $max_nibbles_per_line) == 0)
+ {
+ ($nibble_offset > 0) and print "\n ";
+ printf("$addr_format: ", $curr_address + $nibble_offset/2);
+ }
+ (($nibble_offset % 2) == 0) and print ' ';
+ print $nibble;
+ $nibble_offset++;
+ }
+ }
+ print "\n";
+}
+
+#----------------------------------------------------------------------
+# 'c' command
+#----------------------------------------------------------------------
+sub dump_continue_cmd
+{
+ my $cmd = shift;
+ my $address = -1;
+ if (@_)
+ {
+ my $address = get_addr(\@_);
+ printf("continue ($addr_format)\n", $address);
+ }
+ else
+ {
+ printf("continue ()\n");
+ }
+}
+
+#----------------------------------------------------------------------
+# 'Css' continue (C) with signal (ss where 'ss' is two hex digits)
+#----------------------------------------------------------------------
+sub dump_continue_with_signal_cmd
+{
+ my $cmd = shift;
+ my $address = -1;
+ my $signal = get_hex(\@_);
+ if (@_)
+ {
+ my $address = 0;
+ if (@_ && $_[0] == ';')
+ {
+ shift;
+ $address = get_addr(\@_);
+ }
+ }
+
+ if ($address != -1)
+ {
+ printf("continue_with_signal (signal = 0x%2.2x, address = $addr_format)\n", $signal, $address);
+ }
+ else
+ {
+ printf("continue_with_signal (signal = 0x%2.2x)\n", $signal);
+ }
+}
+
+#----------------------------------------------------------------------
+# 'A' command
+#----------------------------------------------------------------------
+sub dump_A_command
+{
+ my $cmd = get_exptected_char(\@_, 'A') or print "error: incorrect command letter for argument packet, exptected 'A'\n";
+ printf("set_program_arguments (\n");
+ do
+ {
+ my $arg_len = get_uint(\@_);
+ get_exptected_char(\@_, ',') or die "error: missing comma after argument length...?\n";
+ my $arg_idx = get_uint(\@_);
+ get_exptected_char(\@_, ',') or die "error: missing comma after argument number...?\n";
+
+ my $arg = '';
+ my $num_hex8_bytes = $arg_len/2;
+ for (1 .. $num_hex8_bytes)
+ {
+ $arg .= sprintf("%c", get8(\@_))
+ }
+ printf(" <%3u> argv[%u] = '%s'\n", $arg_len, $arg_idx, $arg);
+ if (@_ > 0)
+ {
+ get_exptected_char(\@_, ',') or die "error: missing comma after argument argument ASCII hex bytes...?\n";
+ }
+ } while (@_ > 0);
+ printf(" )\n");
+}
+
+
+#----------------------------------------------------------------------
+# 'z' and 'Z' command
+#----------------------------------------------------------------------
+sub dump_bp_wp_command
+{
+ my $cmd = shift;
+ my $type = shift;
+ shift; # Skip ','
+ my $address = get_addr(\@_);
+ shift; # Skip ','
+ my $length = join('', at _);
+ if ($cmd eq 'z')
+ {
+ printf("remove $point_types[$type]($addr_format, %d)\n", $address, $length);
+ }
+ else
+ {
+ printf("insert $point_types[$type]($addr_format, %d)\n", $address, $length);
+ }
+}
+
+
+#----------------------------------------------------------------------
+# 'X' command
+#----------------------------------------------------------------------
+sub dump_write_mem_binary_cmd
+{
+ my $cmd = shift;
+ my $address = get_addr(\@_);
+ shift; # Skip ','
+
+ my ($length, $binary) = split(/:/, join('', at _));
+ printf("write_mem_binary ( $addr_format, %d, %s)\n", $address, $length, $binary);
+
+}
+
+#----------------------------------------------------------------------
+# 'M' command
+#----------------------------------------------------------------------
+sub dump_write_mem_cmd
+{
+ my $cmd = shift;
+ my $address = get_addr(\@_);
+ shift; # Skip ','
+ my ($length, $hex_bytes) = split(/:/, join('', at _));
+# printf("write_mem ( $addr_format, %d, %s)\n", $address, $length, $hex_bytes);
+ printf("write_mem ( addr = $addr_format, len = %d (0x%x), bytes = ", $address, $length, $length);
+ splice(@_, 0, length($length)+1);
+
+ my $curr_address = $address;
+ my $nibble;
+ my $nibble_count = 0;
+ my $max_nibbles_per_line = 2 * $max_bytes_per_line;
+ foreach $nibble (@_)
+ {
+ (($nibble_count % 2) == 0) and print ' ';
+ print $nibble;
+ $nibble_count++;
+ }
+
+ # If the memory to write is 2 or 4 bytes, print it out in native format
+ # instead of just as bytes.
+ if (@_ == 4)
+ {
+ printf(" ( 0x%4.4x )", get16(\@_));
+ }
+ elsif (@_ == 8)
+ {
+ printf(" ( 0x%8.8x )", get32(\@_));
+ }
+ print " )\n";
+
+}
+
+#----------------------------------------------------------------------
+# 'v' command
+#----------------------------------------------------------------------
+our $extended_rsp_callback = 0;
+sub dump_extended_cmd
+{
+ $extended_rsp_callback = 0;
+ if (join('', @_[0..4]) eq "vCont")
+ {
+ dump_extended_continue_cmd(splice(@_,5));
+ }
+ elsif (join('', @_[0..11]) eq 'vAttachWait;')
+ {
+ dump_attach_wait_command (splice(@_,12));
+ }
+}
+
+#----------------------------------------------------------------------
+# 'v' response
+#----------------------------------------------------------------------
+sub dump_extended_rsp
+{
+ if ($extended_rsp_callback)
+ {
+ &$extended_rsp_callback(@_);
+ }
+ $extended_rsp_callback = 0;
+}
+
+#----------------------------------------------------------------------
+# 'vAttachWait' command
+#----------------------------------------------------------------------
+sub dump_attach_wait_command
+{
+# print "dump_extended_continue_cmd ( ";
+# dump_chars(@_);
+# print " )\n";
+ print "attach_wait ( ";
+ while (@_)
+ {
+ printf("%c", get8(\@_))
+ }
+ printf " )\n";
+
+}
+
+#----------------------------------------------------------------------
+# 'vCont' command
+#----------------------------------------------------------------------
+sub dump_extended_continue_cmd
+{
+# print "dump_extended_continue_cmd ( ";
+# dump_chars(@_);
+# print " )\n";
+ print "extended_continue ( ";
+ my $cmd = shift;
+ if ($cmd eq '?')
+ {
+ print "list supported modes )\n";
+ $extended_rsp_callback = \&dump_extended_continue_rsp;
+ }
+ elsif ($cmd eq ';')
+ {
+ $extended_rsp_callback = \&dump_stop_reply_packet;
+ my $i = 0;
+ while ($#_ >= 0)
+ {
+ if ($i > 0)
+ {
+ print ", ";
+ }
+ my $continue_cmd = shift;
+ my $tmp;
+ if ($continue_cmd eq 'c')
+ {
+ print "continue";
+ }
+ elsif ($continue_cmd eq 'C')
+ {
+ print "continue with signal ";
+ print shift;
+ print shift;
+ }
+ elsif ($continue_cmd eq 's')
+ {
+ print "step";
+ }
+ elsif ($continue_cmd eq 'S')
+ {
+ print "step with signal ";
+ print shift;
+ print shift;
+ }
+
+ if ($_[0] eq ':')
+ {
+ shift; # Skip ':'
+ print " for thread ";
+ while ($#_ >= 0)
+ {
+ $tmp = shift;
+ if (length($tmp) > 0 && $tmp ne ';') {
+ print $tmp;
+ } else {
+ last;
+ }
+ }
+ }
+ $i++;
+ }
+
+ printf " )\n";
+ }
+}
+
+#----------------------------------------------------------------------
+# 'vCont' response
+#----------------------------------------------------------------------
+sub dump_extended_continue_rsp
+{
+ print "extended_continue ( " . join('', at _) . " )\n";
+}
+
+#----------------------------------------------------------------------
+# Dump the command ascii for any unknown commands
+#----------------------------------------------------------------------
+sub dump_other_cmd
+{
+ print "other = " . join('', at _) . "\n";
+}
+
+#----------------------------------------------------------------------
+# Check to see if the response was unsupported with appropriate checksum
+#----------------------------------------------------------------------
+sub rsp_is_unsupported
+{
+ return join('', at _) eq "#00";
+}
+
+#----------------------------------------------------------------------
+# Check to see if the response was "OK" with appropriate checksum
+#----------------------------------------------------------------------
+sub rsp_is_OK
+{
+ return join('', at _) eq "OK#9a";
+}
+
+#----------------------------------------------------------------------
+# Dump a response for an unknown command
+#----------------------------------------------------------------------
+sub dump_other_rsp
+{
+ print "other = " . join('', at _) . "\n";
+}
+
+#----------------------------------------------------------------------
+# Get a byte from the ascii string assuming that the 2 nibble ascii
+# characters are in hex.
+#
+# The argument for this function needs to be a reference to an array
+# that contains single character strings and the array will get
+# updated by shifting characters off the front of it (no leading # "0x")
+#----------------------------------------------------------------------
+sub get8
+{
+ my $arrayref = shift;
+ my $val = hex(shift(@$arrayref) . shift(@$arrayref));
+ return $val;
+}
+
+#----------------------------------------------------------------------
+# Get a 16 bit integer and swap if $swap global is set to a non-zero
+# value.
+#
+# The argument for this function needs to be a reference to an array
+# that contains single character strings and the array will get
+# updated by shifting characters off the front of it (no leading # "0x")
+#----------------------------------------------------------------------
+sub get16
+{
+ my $arrayref = shift;
+ my $val = 0;
+ if ($swap)
+ {
+ $val = get8($arrayref) |
+ get8($arrayref) << 8;
+ }
+ else
+ {
+ $val = get8($arrayref) << 8 |
+ get8($arrayref) ;
+ }
+ return $val;
+}
+
+#----------------------------------------------------------------------
+# Get a 32 bit integer and swap if $swap global is set to a non-zero
+# value.
+#
+# The argument for this function needs to be a reference to an array
+# that contains single character strings and the array will get
+# updated by shifting characters off the front of it (no leading # "0x")
+#----------------------------------------------------------------------
+sub get32
+{
+ my $arrayref = shift;
+ my $val = 0;
+ if ($swap)
+ {
+ $val = get8($arrayref) |
+ get8($arrayref) << 8 |
+ get8($arrayref) << 16 |
+ get8($arrayref) << 24 ;
+ }
+ else
+ {
+ $val = get8($arrayref) << 24 |
+ get8($arrayref) << 16 |
+ get8($arrayref) << 8 |
+ get8($arrayref) ;
+ }
+ return $val;
+}
+
+#----------------------------------------------------------------------
+# Get a 64 bit hex value as a string
+#
+# The argument for this function needs to be a reference to an array
+# that contains single character strings and the array will get
+# updated by shifting characters off the front of it (no leading # "0x")
+#----------------------------------------------------------------------
+sub get64
+{
+ my $arrayref = shift;
+ my $val = '';
+ my @nibbles;
+ if ($swap)
+ {
+ push @nibbles, splice(@$arrayref, 14, 2);
+ push @nibbles, splice(@$arrayref, 12, 2);
+ push @nibbles, splice(@$arrayref, 10, 2);
+ push @nibbles, splice(@$arrayref, 8, 2);
+ push @nibbles, splice(@$arrayref, 6, 2);
+ push @nibbles, splice(@$arrayref, 4, 2);
+ push @nibbles, splice(@$arrayref, 2, 2);
+ push @nibbles, splice(@$arrayref, 0, 2);
+ }
+ else
+ {
+ (@nibbles) = splice(@$arrayref, 0, 24);
+ }
+ $val = join('', @nibbles);
+ return $val;
+}
+
+#----------------------------------------------------------------------
+# Get a 80 bit hex value as a string
+#
+# The argument for this function needs to be a reference to an array
+# that contains single character strings and the array will get
+# updated by shifting characters off the front of it (no leading # "0x")
+#----------------------------------------------------------------------
+sub get80
+{
+ my $arrayref = shift;
+ my $val = '';
+ my @nibbles;
+ if ($swap)
+ {
+ push @nibbles, splice(@$arrayref, 18, 2);
+ push @nibbles, splice(@$arrayref, 16, 2);
+ push @nibbles, splice(@$arrayref, 14, 2);
+ push @nibbles, splice(@$arrayref, 12, 2);
+ push @nibbles, splice(@$arrayref, 10, 2);
+ push @nibbles, splice(@$arrayref, 8, 2);
+ push @nibbles, splice(@$arrayref, 6, 2);
+ push @nibbles, splice(@$arrayref, 4, 2);
+ push @nibbles, splice(@$arrayref, 2, 2);
+ push @nibbles, splice(@$arrayref, 0, 2);
+ }
+ else
+ {
+ (@nibbles) = splice(@$arrayref, 0, 24);
+ }
+ $val = join('', @nibbles);
+ return $val;
+}
+
+#----------------------------------------------------------------------
+# Get a 96 bit hex value as a string
+#
+# The argument for this function needs to be a reference to an array
+# that contains single character strings and the array will get
+# updated by shifting characters off the front of it (no leading # "0x")
+#----------------------------------------------------------------------
+sub get96
+{
+ my $arrayref = shift;
+ my $val = '';
+ my @nibbles;
+ if ($swap)
+ {
+ push @nibbles, splice(@$arrayref, 22, 2);
+ push @nibbles, splice(@$arrayref, 20, 2);
+ push @nibbles, splice(@$arrayref, 18, 2);
+ push @nibbles, splice(@$arrayref, 16, 2);
+ push @nibbles, splice(@$arrayref, 14, 2);
+ push @nibbles, splice(@$arrayref, 12, 2);
+ push @nibbles, splice(@$arrayref, 10, 2);
+ push @nibbles, splice(@$arrayref, 8, 2);
+ push @nibbles, splice(@$arrayref, 6, 2);
+ push @nibbles, splice(@$arrayref, 4, 2);
+ push @nibbles, splice(@$arrayref, 2, 2);
+ push @nibbles, splice(@$arrayref, 0, 2);
+ }
+ else
+ {
+ (@nibbles) = splice(@$arrayref, 0, 24);
+ }
+ $val = join('', @nibbles);
+ return $val;
+}
+
+#----------------------------------------------------------------------
+# Get a 128 bit hex value as a string
+#
+# The argument for this function needs to be a reference to an array
+# that contains single character strings and the array will get
+# updated by shifting characters off the front of it (no leading # "0x")
+#----------------------------------------------------------------------
+sub get128
+{
+ my $arrayref = shift;
+ my $val = '';
+ my @nibbles;
+ if ($swap)
+ {
+ push @nibbles, splice(@$arrayref, 30, 2);
+ push @nibbles, splice(@$arrayref, 28, 2);
+ push @nibbles, splice(@$arrayref, 26, 2);
+ push @nibbles, splice(@$arrayref, 24, 2);
+ push @nibbles, splice(@$arrayref, 22, 2);
+ push @nibbles, splice(@$arrayref, 20, 2);
+ push @nibbles, splice(@$arrayref, 18, 2);
+ push @nibbles, splice(@$arrayref, 16, 2);
+ push @nibbles, splice(@$arrayref, 14, 2);
+ push @nibbles, splice(@$arrayref, 12, 2);
+ push @nibbles, splice(@$arrayref, 10, 2);
+ push @nibbles, splice(@$arrayref, 8, 2);
+ push @nibbles, splice(@$arrayref, 6, 2);
+ push @nibbles, splice(@$arrayref, 4, 2);
+ push @nibbles, splice(@$arrayref, 2, 2);
+ push @nibbles, splice(@$arrayref, 0, 2);
+ }
+ else
+ {
+ (@nibbles) = splice(@$arrayref, 0, 24);
+ }
+ $val = join('', @nibbles);
+ return $val;
+}
+
+#----------------------------------------------------------------------
+# Get a an unsigned integer value by grabbing items off the front of
+# the array stopping when a non-digit char string is encountered.
+#
+# The argument for this function needs to be a reference to an array
+# that contains single character strings and the array will get
+# updated by shifting characters off the front of it
+#----------------------------------------------------------------------
+sub get_uint
+{
+ my $arrayref = shift;
+ @$arrayref == 0 and return 0;
+ my $val = 0;
+ while ($$arrayref[0] =~ /[0-9]/)
+ {
+ $val = $val * 10 + int(shift(@$arrayref));
+ }
+ return $val;
+}
+
+#----------------------------------------------------------------------
+# Check the first character in the array and if it matches the expected
+# character, return that character, else return undef;
+#
+# The argument for this function needs to be a reference to an array
+# that contains single character strings and the array will get
+# updated by shifting characters off the front of it. If the expected
+# character doesn't match, it won't touch the array. If the first
+# character does match, it will shift it off and return it.
+#----------------------------------------------------------------------
+sub get_exptected_char
+{
+ my $arrayref = shift;
+ my $expected_char = shift;
+ if ($expected_char eq $$arrayref[0])
+ {
+ return shift(@$arrayref);
+ }
+ return undef;
+}
+#----------------------------------------------------------------------
+# Get a hex value by grabbing items off the front of the array and
+# stopping when a non-hex char string is encountered.
+#
+# The argument for this function needs to be a reference to an array
+# that contains single character strings and the array will get
+# updated by shifting characters off the front of it (no leading # "0x")
+#----------------------------------------------------------------------
+sub get_hex
+{
+ my $arrayref = shift;
+ my $my_swap = @_ ? shift : 0;
+ my $shift = 0;
+ my $val = 0;
+ while ($$arrayref[0] =~ /[0-9a-fA-F]/)
+ {
+ if ($my_swap)
+ {
+ my $byte = hex(shift(@$arrayref)) << 4 | hex(shift(@$arrayref));
+ $val |= $byte << $shift;
+ $shift += 8;
+ }
+ else
+ {
+ $val <<= 4;
+ $val |= hex(shift(@$arrayref));
+ }
+ }
+ return $val;
+}
+
+#----------------------------------------------------------------------
+# Get an address value by grabbing items off the front of the array.
+#
+# The argument for this function needs to be a reference to an array
+# that contains single character strings and the array will get
+# updated by shifting characters off the front of it (no leading # "0x")
+#----------------------------------------------------------------------
+sub get_addr
+{
+ get_hex(shift);
+}
+
+sub dump_stop_reply_data
+{
+ while ($#_ >= 0)
+ {
+ last unless ($_[0] ne '#');
+
+
+ my $key = '';
+ my $value = '';
+ if ($_[0] =~ /[0-9a-fA-F]/ && $_[1] =~ /[0-9a-fA-F]/)
+ {
+ my $reg_num = get8(\@_);
+ shift(@_); # Skip ':'
+ if (defined ($registers_aref) && $reg_num < @$registers_aref)
+ {
+ dump_register_value(1, \@_, $reg_num);
+ print "\n";
+ shift(@_); # Skip ';'
+ next;
+ }
+ $key = sprintf("reg %u", $reg_num);
+ }
+ my $char;
+
+ if (length($key) == 0)
+ {
+ while (1)
+ {
+ $char = shift(@_);
+ if (length($char) == 0 or $char eq ':' or $char eq '#') { last; }
+ $key .= $char;
+ }
+ }
+
+ while (1)
+ {
+ $char = shift(@_);
+ if (length($char) == 0 or $char eq ';' or $char eq '#') { last; }
+ $value .= $char;
+ }
+ printf("\t%*s = %s\n", $max_register_name_len, $key, $value);
+ }
+}
+
+#----------------------------------------------------------------------
+# Dumps a Stop Reply Packet which happens in response to a step,
+# continue, last signal, and probably a few other commands.
+#----------------------------------------------------------------------
+sub dump_stop_reply_packet
+{
+ my $what = shift(@_);
+ if ($what eq 'S')
+ {
+ print 'signal ( 0x' . shift(@_) . shift(@_) . " )\n";
+ }
+ elsif ($what eq 'T')
+ {
+ print 'signal ( 0x' . shift(@_) . shift(@_) . " )\n";
+ dump_stop_reply_data (@_);
+ }
+ elsif ($what eq 'W')
+ {
+ print 'process_exited( ' . shift(@_) . shift(@_) . " )\n";
+ }
+ elsif ($what eq 'X')
+ {
+ print 'process_terminated( ' . shift(@_) . shift(@_) . " )\n";
+ }
+ elsif ($what eq 'O')
+ {
+ my $console_output = '';
+ my $num_hex8_bytes = @_/2;
+ for (1 .. $num_hex8_bytes)
+ {
+ $console_output .= sprintf("%c", get8(\@_))
+ }
+
+ print "program_console_output('$console_output')\n";
+ }
+}
+
+#----------------------------------------------------------------------
+# '?' command
+#----------------------------------------------------------------------
+sub dump_last_signal_cmd
+{
+ my $cmd = shift;
+ print 'last_signal (' . join('', at _) . ")\n";
+}
+
+sub dump_raw_command
+{
+ my $cmd_aref = shift;
+ my $callback_ref;
+ $curr_cmd = $$cmd_aref[0];
+ $curr_cmd eq '_' and $curr_cmd .= $$cmd_aref[1];
+
+ $callback_ref = $cmd_callbacks{$curr_cmd};
+ if ($callback_ref)
+ {
+ &$callback_ref(@$cmd_aref);
+ }
+ else
+ {
+ # Strip the command byte for responses since we injected that above
+ dump_other_cmd(@$cmd_aref);
+ }
+}
+
+sub dump_standard_response
+{
+ my $cmd_aref = shift;
+
+ if (@$cmd_aref == 0)
+ {
+ print "$unsupported_str\n";
+ return 1;
+ }
+
+ my $response = join('', @$cmd_aref);
+ if ($response eq 'OK')
+ {
+ print "$success_str\n";
+ return 1;
+ }
+
+ if (index($response, 'E') == 0)
+ {
+ print "ERROR: " . substr($response, 1) . "\n";
+ return 1;
+ }
+
+ return 0;
+}
+sub dump_raw_response
+{
+ my $cmd_aref = shift;
+ my $callback_ref;
+
+ $callback_ref = $rsp_callbacks{$curr_cmd};
+
+ if ($callback_ref)
+ {
+ &$callback_ref(@$cmd_aref);
+ }
+ else
+ {
+ dump_standard_response($cmd_aref) or dump_other_rsp(@$cmd_aref);
+ }
+
+}
+#----------------------------------------------------------------------
+# Dumps any command and handles simple error checking on the responses
+# for commands that are unsupported or OK.
+#----------------------------------------------------------------------
+sub dump_command
+{
+ my $cmd_str = shift;
+
+ # Dump the original command string if verbose is on
+ if ($opt_v)
+ {
+ print "dump_command($cmd_str)\n ";
+ }
+
+ my @cmd_chars = extract_command($cmd_str);
+ my $is_cmd = 1;
+
+ my $cmd = $cmd_chars[0];
+ if ($cmd eq '$')
+ {
+ $is_cmd = 0; # Note that this is a reply
+ $cmd = $curr_cmd; # set the command byte appropriately
+ shift @cmd_chars; # remove the '$' from the cmd bytes
+ }
+
+ # Check for common responses across all commands and handle them
+ # if we can
+ if ( $is_cmd == 0 )
+ {
+ if (rsp_is_unsupported(@cmd_chars))
+ {
+ print "$unsupported_str\n";
+ return;
+ }
+ elsif (rsp_is_OK(@cmd_chars))
+ {
+ print "$success_str\n";
+ return;
+ }
+ # Strip the checksum information for responses
+ strip_checksum(\@cmd_chars);
+ }
+
+ my $callback_ref;
+ if ($is_cmd) {
+ $callback_ref = $cmd_callbacks{$cmd};
+ } else {
+ $callback_ref = $rsp_callbacks{$cmd};
+ }
+
+ if ($callback_ref)
+ {
+ &$callback_ref(@cmd_chars);
+ }
+ else
+ {
+ # Strip the command byte for responses since we injected that above
+ if ($is_cmd) {
+ dump_other_cmd(@cmd_chars);
+ } else {
+ dump_other_rsp(@cmd_chars);
+ }
+
+ }
+}
+
+
+#----------------------------------------------------------------------
+# Process a gdbserver log line by looking for getpkt and putkpt and
+# tossing any other lines.
+#----------------------------------------------------------------------
+sub process_log_line
+{
+ my $line = shift;
+ #($opt_v and $opt_g) and print "# $line";
+ my $extract_cmd = 0;
+ if ($line =~ /getpkt /)
+ {
+ $extract_cmd = 1;
+ print "\n--> ";
+ }
+ elsif ($line =~ /putpkt /)
+ {
+ $extract_cmd = 1;
+ print "<-- ";
+ }
+ elsif ($line =~ /.*Sent: \[[0-9]+\.[0-9]+[:0-9]*\] (.*)/)
+ {
+ $opt_g and print "maintenance dump-packets command: $1\n";
+ my @raw_cmd_bytes = split(/ */, $1);
+ print "\n--> ";
+ dump_raw_command(\@raw_cmd_bytes);
+ process_log_line($2);
+ }
+ elsif ($line =~ /.*Recvd: \[[0-9]+\.[0-9]+[:0-9]*\] (.*)/)
+ {
+ $opt_g and print "maintenance dump-packets reply: $1\n";
+ my @raw_rsp_bytes = split(/ */, $1);
+ print "<-- ";
+ dump_raw_response(\@raw_rsp_bytes);
+ print "\n";
+ }
+ elsif ($line =~ /getpkt: (.*)/)
+ {
+ if ($1 =~ /\$([^#]+)#[0-9a-fA-F]{2}/)
+ {
+ $opt_g and print "command: $1\n";
+ my @raw_cmd_bytes = split(/ */, $1);
+ print "--> ";
+ dump_raw_command(\@raw_cmd_bytes);
+ }
+ elsif ($1 =~ /\+/)
+ {
+ #print "--> ACK\n";
+ }
+ elsif ($1 =~ /-/)
+ {
+ #print "--> NACK\n";
+ }
+ }
+ elsif ($line =~ /putpkt: (.*)/)
+ {
+ if ($1 =~ /\$([^#]+)#[0-9a-fA-F]{2}/)
+ {
+ $opt_g and print "response: $1\n";
+ my @raw_rsp_bytes = split(/ */, $1);
+ print "<-- ";
+ dump_raw_response(\@raw_rsp_bytes);
+ print "\n";
+ }
+ elsif ($1 =~ /\+/)
+ {
+ #print "<-- ACK\n";
+ }
+ elsif ($1 =~ /-/)
+ {
+ #print "<-- NACK\n";
+ }
+ }
+ elsif ($line =~ /send packet: (.*)/)
+ {
+ if ($1 =~ /\$([^#]+)#[0-9a-fA-F]{2}/)
+ {
+ $opt_g and print "command: $1\n";
+ my @raw_cmd_bytes = split(/ */, $1);
+ print "--> ";
+ dump_raw_command(\@raw_cmd_bytes);
+ }
+ elsif ($1 =~ /\+/)
+ {
+ #print "--> ACK\n";
+ }
+ elsif ($1 =~ /-/)
+ {
+ #print "--> NACK\n";
+ }
+ }
+ elsif ($line =~ /read packet: (.*)/)
+ {
+ if ($1 =~ /\$([^#]+)#[0-9a-fA-F]{2}/)
+ {
+ $opt_g and print "response: $1\n";
+ my @raw_rsp_bytes = split(/ */, $1);
+ print "<-- ";
+ dump_raw_response(\@raw_rsp_bytes);
+ print "\n";
+ }
+ elsif ($1 =~ /\+/)
+ {
+ #print "<-- ACK\n";
+ }
+ elsif ($1 =~ /-/)
+ {
+ #print "<-- NACK\n";
+ }
+ }
+ elsif ($line =~ /Sending packet: \$([^#]+)#[0-9a-fA-F]{2}\.\.\.(.*)/)
+ {
+ $opt_g and print "command: $1\n";
+ my @raw_cmd_bytes = split(/ */, $1);
+ print "\n--> ";
+ dump_raw_command(\@raw_cmd_bytes);
+ process_log_line($2);
+ }
+ elsif ($line =~ /Packet received: (.*)/)
+ {
+ $opt_g and print "response: $1\n";
+ my @raw_rsp_bytes = split(/ */, $1);
+ print "<-- ";
+ dump_raw_response(\@raw_rsp_bytes);
+ print "\n";
+ }
+
+ if ($extract_cmd)
+ {
+ my $beg = index($line, '("') + 2;
+ my $end = rindex($line, '");');
+ dump_command(substr($line, $beg, $end - $beg));
+ }
+}
+
+
+our $line_num = 0;
+while(<>)
+{
+ $line_num++;
+ $opt_q or printf("# %5d: $_", $line_num);
+ process_log_line($_);
+}
+
+
+
+
+
+
Propchange: lldb/trunk/scripts/disasm-gdb-remote.pl
------------------------------------------------------------------------------
svn:executable = *
More information about the lldb-commits
mailing list