blob: 84788de49a12dada614d621205d3e95d92a7d40a [file] [log] [blame]
Greg Claytone51dc6f2011-05-20 02:00:47 +00001#!/usr/bin/perl
2
3use strict;
4
5#----------------------------------------------------------------------
6# Globals
7#----------------------------------------------------------------------
8our $unsupported_str = "UNSUPPORTED";
9our $success_str = "OK";
10our $swap = 1;
11our $addr_size = 4;
12our $thread_suffix_supported = 0;
13our $max_bytes_per_line = 32;
14our $addr_format = sprintf("0x%%%u.%ux", $addr_size*2, $addr_size*2);
15our $pid_format = "%04.4x";
16our $tid_format = "%04.4x";
17our $reg8_href = { extract => \&get8, format => "0x%2.2x" };
18our $reg16_href = { extract => \&get16, format => "0x%4.4x" };
19our $reg32_href = { extract => \&get32, format => "0x%8.8x" };
20our $reg64_href = { extract => \&get64, format => "0x%s" };
21our $reg80_href = { extract => \&get80, format => "0x%s" };
22our $reg128_href = { extract => \&get128, format => "0x%s" };
23our $float32_href = { extract => \&get32, format => "0x%8.8x" };
24our $float64_href = { extract => \&get64, format => "0x%s" };
25our $float96_href = { extract => \&get96, format => "0x%s" };
26our $curr_cmd = undef;
27our $reg_cmd_reg;
28our %reg_map = (
29 'i386-gdb' => [
30 { name => 'eax', info => $reg32_href },
31 { name => 'ecx', info => $reg32_href },
32 { name => 'edx', info => $reg32_href },
33 { name => 'ebx', info => $reg32_href },
34 { name => 'esp', info => $reg32_href },
35 { name => 'ebp', info => $reg32_href },
36 { name => 'esi', info => $reg32_href },
37 { name => 'edi', info => $reg32_href },
38 { name => 'eip', info => $reg32_href },
39 { name => 'eflags', info => $reg32_href },
40 { name => 'cs', info => $reg32_href },
41 { name => 'ss', info => $reg32_href },
42 { name => 'ds', info => $reg32_href },
43 { name => 'es', info => $reg32_href },
44 { name => 'fs', info => $reg32_href },
45 { name => 'gs', info => $reg32_href },
46 { name => 'st0', info => $reg80_href },
47 { name => 'st1', info => $reg80_href },
48 { name => 'st2', info => $reg80_href },
49 { name => 'st3', info => $reg80_href },
50 { name => 'st4', info => $reg80_href },
51 { name => 'st5', info => $reg80_href },
52 { name => 'st6', info => $reg80_href },
53 { name => 'st7', info => $reg80_href },
54 { name => 'fctrl', info => $reg32_href },
55 { name => 'fstat', info => $reg32_href },
56 { name => 'ftag', info => $reg32_href },
57 { name => 'fiseg', info => $reg32_href },
58 { name => 'fioff', info => $reg32_href },
59 { name => 'foseg', info => $reg32_href },
60 { name => 'fooff', info => $reg32_href },
61 { name => 'fop', info => $reg32_href },
62 { name => 'xmm0', info => $reg128_href },
63 { name => 'xmm1', info => $reg128_href },
64 { name => 'xmm2', info => $reg128_href },
65 { name => 'xmm3', info => $reg128_href },
66 { name => 'xmm4', info => $reg128_href },
67 { name => 'xmm5', info => $reg128_href },
68 { name => 'xmm6', info => $reg128_href },
69 { name => 'xmm7', info => $reg128_href },
70 { name => 'mxcsr', info => $reg32_href },
71 { name => 'mm0', info => $reg64_href },
72 { name => 'mm1', info => $reg64_href },
73 { name => 'mm2', info => $reg64_href },
74 { name => 'mm3', info => $reg64_href },
75 { name => 'mm4', info => $reg64_href },
76 { name => 'mm5', info => $reg64_href },
77 { name => 'mm6', info => $reg64_href },
78 { name => 'mm7', info => $reg64_href },
79 ],
80
81 'i386-lldb' => [
82 { name => 'eax', info => $reg32_href },
83 { name => 'ebx', info => $reg32_href },
84 { name => 'ecx', info => $reg32_href },
85 { name => 'edx', info => $reg32_href },
86 { name => 'edi', info => $reg32_href },
87 { name => 'esi', info => $reg32_href },
88 { name => 'ebp', info => $reg32_href },
89 { name => 'esp', info => $reg32_href },
90 { name => 'ss', info => $reg32_href },
91 { name => 'eflags', info => $reg32_href },
92 { name => 'eip', info => $reg32_href },
93 { name => 'cs', info => $reg32_href },
94 { name => 'ds', info => $reg32_href },
95 { name => 'es', info => $reg32_href },
96 { name => 'fs', info => $reg32_href },
97 { name => 'gs', info => $reg32_href },
98 { name => 'fctrl', info => $reg16_href },
99 { name => 'fstat', info => $reg16_href },
100 { name => 'ftag', info => $reg8_href },
101 { name => 'fop', info => $reg16_href },
102 { name => 'fioff', info => $reg32_href },
103 { name => 'fiseg', info => $reg16_href },
104 { name => 'fooff', info => $reg32_href },
105 { name => 'foseg', info => $reg16_href },
106 { name => 'mxcsr', info => $reg32_href },
107 { name => 'mxcsrmask', info => $reg32_href },
108 { name => 'stmm0', info => $reg80_href },
109 { name => 'stmm1', info => $reg80_href },
110 { name => 'stmm2', info => $reg80_href },
111 { name => 'stmm3', info => $reg80_href },
112 { name => 'stmm4', info => $reg80_href },
113 { name => 'stmm5', info => $reg80_href },
114 { name => 'stmm6', info => $reg80_href },
115 { name => 'stmm7', info => $reg80_href },
116 { name => 'xmm0', info => $reg128_href },
117 { name => 'xmm1', info => $reg128_href },
118 { name => 'xmm2', info => $reg128_href },
119 { name => 'xmm3', info => $reg128_href },
120 { name => 'xmm4', info => $reg128_href },
121 { name => 'xmm5', info => $reg128_href },
122 { name => 'xmm6', info => $reg128_href },
123 { name => 'xmm7', info => $reg128_href },
124 { name => 'trapno', info => $reg32_href },
125 { name => 'err', info => $reg32_href },
126 { name => 'faultvaddr', info => $reg32_href },
127 ],
128
129 'arm-gdb' => [
130 { name => 'r0' , info => $reg32_href },
131 { name => 'r1' , info => $reg32_href },
132 { name => 'r2' , info => $reg32_href },
133 { name => 'r3' , info => $reg32_href },
134 { name => 'r4' , info => $reg32_href },
135 { name => 'r5' , info => $reg32_href },
136 { name => 'r6' , info => $reg32_href },
137 { name => 'r7' , info => $reg32_href },
138 { name => 'r8' , info => $reg32_href },
139 { name => 'r9' , info => $reg32_href },
140 { name => 'r10' , info => $reg32_href },
141 { name => 'r11' , info => $reg32_href },
142 { name => 'r12' , info => $reg32_href },
143 { name => 'sp' , info => $reg32_href },
144 { name => 'lr' , info => $reg32_href },
145 { name => 'pc' , info => $reg32_href },
146 { name => 'f0' , info => $float96_href },
147 { name => 'f1' , info => $float96_href },
148 { name => 'f2' , info => $float96_href },
149 { name => 'f3' , info => $float96_href },
150 { name => 'f4' , info => $float96_href },
151 { name => 'f5' , info => $float96_href },
152 { name => 'f6' , info => $float96_href },
153 { name => 'f7' , info => $float96_href },
154 { name => 'fps' , info => $reg32_href },
155 { name => 'cpsr' , info => $reg32_href },
156 { name => 's0' , info => $float32_href },
157 { name => 's1' , info => $float32_href },
158 { name => 's2' , info => $float32_href },
159 { name => 's3' , info => $float32_href },
160 { name => 's4' , info => $float32_href },
161 { name => 's5' , info => $float32_href },
162 { name => 's6' , info => $float32_href },
163 { name => 's7' , info => $float32_href },
164 { name => 's8' , info => $float32_href },
165 { name => 's9' , info => $float32_href },
166 { name => 's10' , info => $float32_href },
167 { name => 's11' , info => $float32_href },
168 { name => 's12' , info => $float32_href },
169 { name => 's13' , info => $float32_href },
170 { name => 's14' , info => $float32_href },
171 { name => 's15' , info => $float32_href },
172 { name => 's16' , info => $float32_href },
173 { name => 's17' , info => $float32_href },
174 { name => 's18' , info => $float32_href },
175 { name => 's19' , info => $float32_href },
176 { name => 's20' , info => $float32_href },
177 { name => 's21' , info => $float32_href },
178 { name => 's22' , info => $float32_href },
179 { name => 's23' , info => $float32_href },
180 { name => 's24' , info => $float32_href },
181 { name => 's25' , info => $float32_href },
182 { name => 's26' , info => $float32_href },
183 { name => 's27' , info => $float32_href },
184 { name => 's28' , info => $float32_href },
185 { name => 's29' , info => $float32_href },
186 { name => 's30' , info => $float32_href },
187 { name => 's31' , info => $float32_href },
188 { name => 'fpscr' , info => $reg32_href },
189 { name => 'd16' , info => $float64_href },
190 { name => 'd17' , info => $float64_href },
191 { name => 'd18' , info => $float64_href },
192 { name => 'd19' , info => $float64_href },
193 { name => 'd20' , info => $float64_href },
194 { name => 'd21' , info => $float64_href },
195 { name => 'd22' , info => $float64_href },
196 { name => 'd23' , info => $float64_href },
197 { name => 'd24' , info => $float64_href },
198 { name => 'd25' , info => $float64_href },
199 { name => 'd26' , info => $float64_href },
200 { name => 'd27' , info => $float64_href },
201 { name => 'd28' , info => $float64_href },
202 { name => 'd29' , info => $float64_href },
203 { name => 'd30' , info => $float64_href },
204 { name => 'd31' , info => $float64_href },
205 ],
206
207 'x86_64-gdb' => [
208 { name => 'rax' , info => $reg64_href },
209 { name => 'rbx' , info => $reg64_href },
210 { name => 'rcx' , info => $reg64_href },
211 { name => 'rdx' , info => $reg64_href },
212 { name => 'rsi' , info => $reg64_href },
213 { name => 'rdi' , info => $reg64_href },
214 { name => 'rbp' , info => $reg64_href },
215 { name => 'rsp' , info => $reg64_href },
216 { name => 'r8' , info => $reg64_href },
217 { name => 'r9' , info => $reg64_href },
218 { name => 'r10' , info => $reg64_href },
219 { name => 'r11' , info => $reg64_href },
220 { name => 'r12' , info => $reg64_href },
221 { name => 'r13' , info => $reg64_href },
222 { name => 'r14' , info => $reg64_href },
223 { name => 'r15' , info => $reg64_href },
224 { name => 'rip' , info => $reg64_href },
225 { name => 'eflags' , info => $reg32_href },
226 { name => 'cs' , info => $reg32_href },
227 { name => 'ss' , info => $reg32_href },
228 { name => 'ds' , info => $reg32_href },
229 { name => 'es' , info => $reg32_href },
230 { name => 'fs' , info => $reg32_href },
231 { name => 'gs' , info => $reg32_href },
232 { name => 'stmm0' , info => $reg80_href },
233 { name => 'stmm1' , info => $reg80_href },
234 { name => 'stmm2' , info => $reg80_href },
235 { name => 'stmm3' , info => $reg80_href },
236 { name => 'stmm4' , info => $reg80_href },
237 { name => 'stmm5' , info => $reg80_href },
238 { name => 'stmm6' , info => $reg80_href },
239 { name => 'stmm7' , info => $reg80_href },
240 { name => 'fctrl' , info => $reg32_href },
241 { name => 'fstat' , info => $reg32_href },
242 { name => 'ftag' , info => $reg32_href },
243 { name => 'fiseg' , info => $reg32_href },
244 { name => 'fioff' , info => $reg32_href },
245 { name => 'foseg' , info => $reg32_href },
246 { name => 'fooff' , info => $reg32_href },
247 { name => 'fop' , info => $reg32_href },
248 { name => 'xmm0' , info => $reg128_href },
249 { name => 'xmm1' , info => $reg128_href },
250 { name => 'xmm2' , info => $reg128_href },
251 { name => 'xmm3' , info => $reg128_href },
252 { name => 'xmm4' , info => $reg128_href },
253 { name => 'xmm5' , info => $reg128_href },
254 { name => 'xmm6' , info => $reg128_href },
255 { name => 'xmm7' , info => $reg128_href },
256 { name => 'xmm8' , info => $reg128_href },
257 { name => 'xmm9' , info => $reg128_href },
258 { name => 'xmm10' , info => $reg128_href },
259 { name => 'xmm11' , info => $reg128_href },
260 { name => 'xmm12' , info => $reg128_href },
261 { name => 'xmm13' , info => $reg128_href },
262 { name => 'xmm14' , info => $reg128_href },
263 { name => 'xmm15' , info => $reg128_href },
264 { name => 'mxcsr' , info => $reg32_href },
265 ],
266
267 'x86_64-lldb' => [
268 { name => 'rax' , info => $reg64_href },
269 { name => 'rbx' , info => $reg64_href },
270 { name => 'rcx' , info => $reg64_href },
271 { name => 'rdx' , info => $reg64_href },
272 { name => 'rdi' , info => $reg64_href },
273 { name => 'rsi' , info => $reg64_href },
274 { name => 'rbp' , info => $reg64_href },
275 { name => 'rsp' , info => $reg64_href },
276 { name => 'r8 ' , info => $reg64_href },
277 { name => 'r9 ' , info => $reg64_href },
278 { name => 'r10' , info => $reg64_href },
279 { name => 'r11' , info => $reg64_href },
280 { name => 'r12' , info => $reg64_href },
281 { name => 'r13' , info => $reg64_href },
282 { name => 'r14' , info => $reg64_href },
283 { name => 'r15' , info => $reg64_href },
284 { name => 'rip' , info => $reg64_href },
285 { name => 'rflags' , info => $reg64_href },
286 { name => 'cs' , info => $reg64_href },
287 { name => 'fs' , info => $reg64_href },
288 { name => 'gs' , info => $reg64_href },
289 { name => 'fctrl' , info => $reg16_href },
290 { name => 'fstat' , info => $reg16_href },
291 { name => 'ftag' , info => $reg8_href },
292 { name => 'fop' , info => $reg16_href },
293 { name => 'fioff' , info => $reg32_href },
294 { name => 'fiseg' , info => $reg16_href },
295 { name => 'fooff' , info => $reg32_href },
296 { name => 'foseg' , info => $reg16_href },
297 { name => 'mxcsr' , info => $reg32_href },
298 { name => 'mxcsrmask' , info => $reg32_href },
299 { name => 'stmm0' , info => $reg80_href },
300 { name => 'stmm1' , info => $reg80_href },
301 { name => 'stmm2' , info => $reg80_href },
302 { name => 'stmm3' , info => $reg80_href },
303 { name => 'stmm4' , info => $reg80_href },
304 { name => 'stmm5' , info => $reg80_href },
305 { name => 'stmm6' , info => $reg80_href },
306 { name => 'stmm7' , info => $reg80_href },
307 { name => 'xmm0' , info => $reg128_href },
308 { name => 'xmm1' , info => $reg128_href },
309 { name => 'xmm2' , info => $reg128_href },
310 { name => 'xmm3' , info => $reg128_href },
311 { name => 'xmm4' , info => $reg128_href },
312 { name => 'xmm5' , info => $reg128_href },
313 { name => 'xmm6' , info => $reg128_href },
314 { name => 'xmm7' , info => $reg128_href },
315 { name => 'xmm8' , info => $reg128_href },
316 { name => 'xmm9' , info => $reg128_href },
317 { name => 'xmm10' , info => $reg128_href },
318 { name => 'xmm11' , info => $reg128_href },
319 { name => 'xmm12' , info => $reg128_href },
320 { name => 'xmm13' , info => $reg128_href },
321 { name => 'xmm14' , info => $reg128_href },
322 { name => 'xmm15' , info => $reg128_href },
323 { name => 'trapno' , info => $reg32_href },
324 { name => 'err' , info => $reg32_href },
325 { name => 'faultvaddr' , info => $reg64_href },
326 ]
327);
328
329our $max_register_name_len = 0;
330calculate_max_register_name_length();
331our @point_types = ( "software_bp", "hardware_bp", "write_wp", "read_wp", "access_wp" );
332our $opt_v = 0; # verbose
333our $opt_g = 0; # debug
334our $opt_q = 0; # quiet
335our $opt_r = undef;
336use Getopt::Std;
337getopts('gvqr:');
338
339our $registers_aref = undef;
340
341if (length($opt_r))
342{
343 $registers_aref = $reg_map{$opt_r};
344}
345
346sub extract_key_value_pairs
347{
348 my $kv_href = {};
349 my $arrayref = shift;
350 my $str = join('',@$arrayref);
351 my @kv_strs = split(/;/, $str);
352 foreach my $kv_str (@kv_strs)
353 {
354 my ($key, $value) = split(/:/, $kv_str);
355 $kv_href->{$key} = $value;
356 }
357 return $kv_href;
358}
359
360sub get_thread_from_thread_suffix
361{
362 if ($thread_suffix_supported)
363 {
364 my $arrayref = shift;
365 # Skip leading semi-colon if needed
366 $$arrayref[0] == ';' and shift @$arrayref;
367 my $thread_href = extract_key_value_pairs ($arrayref);
368 if (exists $thread_href->{thread})
369 {
370 return $thread_href->{thread};
371 }
372 }
373 return undef;
374}
375
376sub calculate_max_register_name_length
377{
378 $max_register_name_len = 7;
379 foreach my $reg_href (@$registers_aref)
380 {
381 my $name_len = length($reg_href->{name});
382 if ($max_register_name_len < $name_len)
383 {
384 $max_register_name_len = $name_len;
385 }
386 }
387}
388#----------------------------------------------------------------------
389# Hash that maps command characters to the appropriate functions using
390# the command character as the key and the value being a reference to
391# the dump function for dumping the command itself.
392#----------------------------------------------------------------------
393our %cmd_callbacks =
394(
395 '?' => \&dump_last_signal_cmd,
396 'H' => \&dump_set_thread_cmd,
397 'T' => \&dump_thread_is_alive_cmd,
398 'q' => \&dump_general_query_cmd,
399 'Q' => \&dump_general_set_cmd,
400 'g' => \&dump_read_regs_cmd,
401 'G' => \&dump_write_regs_cmd,
402 'p' => \&dump_read_single_register_cmd,
403 'P' => \&dump_write_single_register_cmd,
404 'm' => \&dump_read_mem_cmd,
405 'M' => \&dump_write_mem_cmd,
406 'X' => \&dump_write_mem_binary_cmd,
407 'Z' => \&dump_bp_wp_command,
408 'z' => \&dump_bp_wp_command,
409 'k' => \&dump_kill_cmd,
410 'A' => \&dump_A_command,
411 'c' => \&dump_continue_cmd,
412 'C' => \&dump_continue_with_signal_cmd,
413 '_M' => \&dump_allocate_memory_cmd,
414 '_m' => \&dump_deallocate_memory_cmd,
415 # extended commands
416 'v' => \&dump_extended_cmd
417);
418
419#----------------------------------------------------------------------
420# Hash that maps command characters to the appropriate functions using
421# the command character as the key and the value being a reference to
422# the dump function for the response to the command.
423#----------------------------------------------------------------------
424our %rsp_callbacks =
425(
426 'c' => \&dump_stop_reply_packet,
427 'C' => \&dump_stop_reply_packet,
428 '?' => \&dump_stop_reply_packet,
429 'T' => \&dump_thread_is_alive_rsp,
430 'H' => \&dump_set_thread_rsp,
431 'q' => \&dump_general_query_rsp,
432 'g' => \&dump_read_regs_rsp,
433 'p' => \&dump_read_single_register_rsp,
434 'm' => \&dump_read_mem_rsp,
435 '_M' => \&dump_allocate_memory_rsp,
436
437 # extended commands
438 'v' => \&dump_extended_rsp,
439);
440
441
442sub dump_register_value
443{
444 my $indent = shift;
445 my $arrayref = shift;
446 my $reg_num = shift;
447
448 if ($reg_num >= @$registers_aref)
449 {
450 printf("\tinvalid register index %d\n", $reg_num);
451 }
452
453 my $reg_href = $$registers_aref[$reg_num];
454 my $reg_name = $reg_href->{name};
455 if ($$arrayref[0] eq '#')
456 {
457 printf("\t%*s: error: EOS reached when trying to read register %d\n", $max_register_name_len, $reg_name, $reg_num);
458 }
459
460 my $reg_info = $reg_href->{info};
461 my $reg_extract = $reg_info->{extract};
462 my $reg_format = $reg_info->{format};
463 my $reg_val = &$reg_extract($arrayref);
464 if ($indent) {
465 printf("\t%*s = $reg_format", $max_register_name_len, $reg_name, $reg_val);
466 } else {
467 printf("%s = $reg_format", $reg_name, $reg_val);
468 }
469}
470
471#----------------------------------------------------------------------
472# Extract the command into an array of ASCII char strings for easy
473# processing
474#----------------------------------------------------------------------
475sub extract_command
476{
477 my $cmd_str = shift;
478 my @cmd_chars = split(/ */, $cmd_str);
479 if ($cmd_chars[0] ne '$')
480 {
481 # only set the current command if it isn't a reply
482 $curr_cmd = $cmd_chars[0];
483 }
484 return @cmd_chars;
485}
486
487#----------------------------------------------------------------------
488# Strip the 3 checksum array entries after we don't need them anymore
489#----------------------------------------------------------------------
490sub strip_checksum
491{
492 my $arrayref = shift;
493 splice(@$arrayref, -3);
494}
495
496#----------------------------------------------------------------------
497# Dump all strings in array by joining them together with no space
498# between them
499#----------------------------------------------------------------------
500sub dump_chars
501{
502 print join('',@_);
503}
504
505#----------------------------------------------------------------------
506# Check if the response is an error 'EXX'
507#----------------------------------------------------------------------
508sub is_error_response
509{
510 if ($_[0] eq 'E')
511 {
512 shift;
513 print "ERROR = " . join('',@_) . "\n";
514 return 1;
515 }
516 return 0;
517}
518
519#----------------------------------------------------------------------
520# 'H' command
521#----------------------------------------------------------------------
522sub dump_set_thread_cmd
523{
524 my $cmd = shift;
525 my $mod = shift;
526 print "set_thread ( $mod, " . join('',@_) . " )\n";
527}
528
529#----------------------------------------------------------------------
530# 'T' command
531#----------------------------------------------------------------------
532our $T_cmd_tid = -1;
533sub dump_thread_is_alive_cmd
534{
535 my $cmd = shift;
536 $T_cmd_tid = get_hex(\@_);
537 printf("thread_is_alive ( $tid_format )\n", $T_cmd_tid);
538}
539
540sub dump_thread_is_alive_rsp
541{
542 my $rsp = join('',@_);
543
544 printf("thread_is_alive ( $tid_format ) =>", $T_cmd_tid);
545 if ($rsp eq 'OK')
546 {
547 print " alive.\n";
548 }
549 else
550 {
551 print " dead.\n";
552 }
553}
554
555#----------------------------------------------------------------------
556# 'H' response
557#----------------------------------------------------------------------
558sub dump_set_thread_rsp
559{
560 if (!is_error_response(@_))
561 {
562 print join('',@_) . "\n";
563 }
564}
565
566#----------------------------------------------------------------------
567# 'q' command
568#----------------------------------------------------------------------
569our $gen_query_cmd;
570sub dump_general_query_cmd
571{
572 $gen_query_cmd = join('',@_);
573 if ($gen_query_cmd eq 'qC')
574 {
575 print 'get_current_pid ()';
576 }
577 elsif ($gen_query_cmd eq 'qfThreadInfo')
578 {
579 print 'get_first_active_threads ()';
580 }
581 elsif ($gen_query_cmd eq 'qsThreadInfo')
582 {
583 print 'get_subsequent_active_threads ()';
584 }
585 elsif (index($gen_query_cmd, 'qThreadExtraInfo') == 0)
586 {
587 # qThreadExtraInfo,id
588 print 'get_thread_extra_info ()';
589 }
590 elsif (index($gen_query_cmd, 'qThreadStopInfo') == 0)
591 {
592 # qThreadStopInfoXXXX
593 @_ = splice(@_, length('qThreadStopInfo'));
594 my $tid = get_addr(\@_);
595 printf('get_thread_stop_info ( thread = 0x%4.4x )', $tid);
596 }
597 elsif (index($gen_query_cmd, 'qSymbol:') == 0)
598 {
599 # qCRC:addr,length
600 print 'gdb_ready_to_serve_symbol_lookups ()';
601 }
602 elsif (index($gen_query_cmd, 'qCRC:') == 0)
603 {
604 # qCRC:addr,length
605 @_ = splice(@_, length('qCRC:'));
606 my $address = get_addr(\@_);
607 shift @_;
608 my $length = join('', @_);
609 printf("compute_crc (addr = $addr_format, length = $length)", $address);
610 }
611 elsif (index($gen_query_cmd, 'qGetTLSAddr:') == 0)
612 {
613 # qGetTLSAddr:thread-id,offset,lm
614 @_ = splice(@_, length('qGetTLSAddr:'));
615 my ($tid, $offset, $lm) = split (/,/, join('', @_));
616 print "get_thread_local_storage_addr (thread-id = $tid, offset = $offset, lm = $lm)";
617 }
618 elsif ($gen_query_cmd eq 'qOffsets')
619 {
620 print 'get_section_offsets ()';
621 }
622 elsif (index($gen_query_cmd, 'qRegisterInfo') == 0)
623 {
624 @_ = splice(@_, length('qRegisterInfo'));
625 my $reg = get_hex(\@_);
626 $reg == 0 and $registers_aref = [];
627
628 printf "get_dynamic_register_info ($reg)";
629 }
630 else
631 {
632 print $gen_query_cmd;
633 }
634 print "\n";
635}
636
637#----------------------------------------------------------------------
638# 'q' response
639#----------------------------------------------------------------------
640sub dump_general_query_rsp
641{
642 my $gen_query_rsp = join('',@_);
643
644 if ($gen_query_cmd eq 'qC' and index($gen_query_rsp, 'QC') == 0)
645 {
646 shift @_; shift @_;
647 my $pid = get_hex(\@_);
648 printf("get_current_pid () => $pid_format\n", $pid);
649 return;
650 }
651 elsif (index($gen_query_cmd, 'qRegisterInfo') == 0)
652 {
653 if (index($gen_query_rsp, 'name') == 0)
654 {
655 my @name_and_values = split (/;/, $gen_query_rsp);
656
657 my $reg_name = undef;
658 my $byte_size = 0;
659 foreach (@name_and_values)
660 {
661 my ($name, $value) = split /:/;
662 if ($name eq "name") { $reg_name = $value; }
663 elsif ($name eq "bitsize") { $byte_size = $value / 8; last; }
664 }
665 if (defined $reg_name and $byte_size > 0)
666 {
667 if ($byte_size == 4) {push @$registers_aref, { name => $reg_name, info => $reg32_href };}
668 elsif ($byte_size == 8) {push @$registers_aref, { name => $reg_name, info => $reg64_href };}
669 elsif ($byte_size == 10) {push @$registers_aref, { name => $reg_name, info => $reg80_href };}
670 elsif ($byte_size == 12) {push @$registers_aref, { name => $reg_name, info => $float96_href };}
671 elsif ($byte_size == 16) {push @$registers_aref, { name => $reg_name, info => $reg128_href };}
672 }
673 }
674 else
675 {
676 calculate_max_register_name_length();
677 }
678 }
679 elsif ($gen_query_cmd =~ 'qThreadStopInfo')
680 {
681 dump_stop_reply_packet (@_);
682 }
683 if (dump_standard_response(\@_))
684 {
685 # Do nothing...
686 }
687 else
688 {
689 print join('',@_) . "\n";
690 }
691}
692
693#----------------------------------------------------------------------
694# 'Q' command
695#----------------------------------------------------------------------
696our $gen_set_cmd;
697sub dump_general_set_cmd
698{
699 $gen_query_cmd = join('',@_);
700 if ($gen_query_cmd eq 'QStartNoAckMode')
701 {
702 print "StartNoAckMode ()"
703 }
704 elsif ($gen_query_cmd eq 'QThreadSuffixSupported')
705 {
706 $thread_suffix_supported = 1;
707 print "ThreadSuffixSupported ()"
708 }
709 elsif (index($gen_query_cmd, 'QSetMaxPayloadSize:') == 0)
710 {
711 @_ = splice(@_, length('QSetMaxPayloadSize:'));
712 my $max_payload_size = get_hex(\@_);
713 # QSetMaxPayloadSize:XXXX where XXXX is a hex length of the max
714 # packet payload size supported by gdb
715 printf("SetMaxPayloadSize ( 0x%x (%u))", $max_payload_size, $max_payload_size);
716 }
717 else
718 {
719 print $gen_query_cmd;
720 }
721 print "\n";
722}
723
724#----------------------------------------------------------------------
725# 'k' command
726#----------------------------------------------------------------------
727sub dump_kill_cmd
728{
729 my $cmd = shift;
730 print "kill (" . join('',@_) . ")\n";
731}
732
733#----------------------------------------------------------------------
734# 'g' command
735#----------------------------------------------------------------------
736sub dump_read_regs_cmd
737{
738 my $cmd = shift;
739 print "read_registers ()\n";
740}
741
742#----------------------------------------------------------------------
743# 'G' command
744#----------------------------------------------------------------------
745sub dump_write_regs_cmd
746{
747 print "write_registers:\n";
748 my $cmd = shift;
749 foreach my $reg_href (@$registers_aref)
750 {
751 last if ($_[0] eq '#');
752 my $reg_info_href = $reg_href->{info};
753 my $reg_name = $reg_href->{name};
754 my $reg_extract = $reg_info_href->{extract};
755 my $reg_format = $reg_info_href->{format};
756 my $reg_val = &$reg_extract(\@_);
757 printf("\t%*s = $reg_format\n", $max_register_name_len, $reg_name, $reg_val);
758 }
759}
760
761sub dump_read_regs_rsp
762{
763 print "read_registers () =>\n";
764 if (!is_error_response(@_))
765 {
766 # print join('',@_) . "\n";
767 foreach my $reg_href (@$registers_aref)
768 {
769 last if ($_[0] eq '#');
770 my $reg_info_href = $reg_href->{info};
771 my $reg_name = $reg_href->{name};
772 my $reg_extract = $reg_info_href->{extract};
773 my $reg_format = $reg_info_href->{format};
774 my $reg_val = &$reg_extract(\@_);
775 printf("\t%*s = $reg_format\n", $max_register_name_len, $reg_name, $reg_val);
776 }
777 }
778}
779
780sub dump_read_single_register_rsp
781{
782 dump_register_value(0, \@_, $reg_cmd_reg);
783 print "\n";
784}
785
786#----------------------------------------------------------------------
787# '_M' - allocate memory command (LLDB extension)
788#
789# Command: '_M'
790# Arg1: Hex byte size as big endian hex string
791# Separator: ','
792# Arg2: permissions as string that must be a string that contains any
793# combination of 'r' (readable) 'w' (writable) or 'x' (executable)
794#
795# Returns: The address that was allocated as a big endian hex string
796# on success, else an error "EXX" where XX are hex bytes
797# that indicate an error code.
798#
799# Examples:
800# _M10,rw # allocate 16 bytes with read + write permissions
801# _M100,rx # allocate 256 bytes with read + execute permissions
802#----------------------------------------------------------------------
803sub dump_allocate_memory_cmd
804{
805 shift; shift; # shift off the '_' and the 'M'
806 my $byte_size = get_addr(\@_);
807 shift; # Skip ','
808 printf("allocate_memory ( byte_size = %u (0x%x), permissions = %s)\n", $byte_size, $byte_size, join('',@_));
809}
810
811sub dump_allocate_memory_rsp
812{
813 if (@_ == 3 and $_[0] == 'E')
814 {
815 printf("allocated memory addr = ERROR (%s))\n", join('',@_));
816 }
817 else
818 {
819 printf("allocated memory addr = 0x%s\n", join('',@_));
820 }
821}
822
823
824#----------------------------------------------------------------------
825# '_m' - deallocate memory command (LLDB extension)
826#
827# Command: '_m'
828# Arg1: Hex address as big endian hex string
829#
830# Returns: "OK" on success "EXX" on error
831#
832# Examples:
833# _m201000 # Free previously allocated memory at address 0x201000
834#----------------------------------------------------------------------
835sub dump_deallocate_memory_cmd
836{
837 shift; shift; # shift off the '_' and the 'm'
838 printf("deallocate_memory ( addr = 0x%s)\n", join('',@_));
839}
840
841
842#----------------------------------------------------------------------
843# 'p' command
844#----------------------------------------------------------------------
845sub dump_read_single_register_cmd
846{
847 my $cmd = shift;
848 $reg_cmd_reg = get_hex(\@_);
849 my $thread = get_thread_from_thread_suffix (\@_);
850 if (defined $thread)
851 {
852 print "read_register ( reg = \"$$registers_aref[$reg_cmd_reg]->{name}\", thread = $thread )\n";
853 }
854 else
855 {
856 print "read_register ( reg = \"$$registers_aref[$reg_cmd_reg]->{name}\" )\n";
857 }
858}
859
860
861#----------------------------------------------------------------------
862# 'P' command
863#----------------------------------------------------------------------
864sub dump_write_single_register_cmd
865{
866 my $cmd = shift;
867 my $reg_num = get_hex(\@_);
868 shift (@_); # Discard the '='
869
870 print "write_register ( ";
871 dump_register_value(0, \@_, $reg_num);
872 my $thread = get_thread_from_thread_suffix (\@_);
873 if (defined $thread)
874 {
875 print ", thread = $thread";
876 }
877 print " )\n";
878}
879
880#----------------------------------------------------------------------
881# 'm' command
882#----------------------------------------------------------------------
883our $read_mem_address = 0;
884sub dump_read_mem_cmd
885{
886 my $cmd = shift;
887 $read_mem_address = get_addr(\@_);
888 shift; # Skip ','
889 printf("read_mem ( $addr_format, %s )\n", $read_mem_address, join('',@_));
890}
891
892#----------------------------------------------------------------------
893# 'm' response
894#----------------------------------------------------------------------
895sub dump_read_mem_rsp
896{
897 # If the memory read was 2 or 4 bytes, print it out in native format
898 # instead of just as bytes.
899 my $num_nibbles = @_;
900 if ($num_nibbles == 2)
901 {
902 printf(" 0x%2.2x", get8(\@_));
903 }
904 elsif ($num_nibbles == 4)
905 {
906 printf(" 0x%4.4x", get16(\@_));
907 }
908 elsif ($num_nibbles == 8)
909 {
910 printf(" 0x%8.8x", get32(\@_));
911 }
912 elsif ($num_nibbles == 16)
913 {
914 printf(" 0x%s", get64(\@_));
915 }
916 else
917 {
918 my $curr_address = $read_mem_address;
919 my $nibble;
920 my $nibble_offset = 0;
921 my $max_nibbles_per_line = 2 * $max_bytes_per_line;
922 foreach $nibble (@_)
923 {
924 if (($nibble_offset % $max_nibbles_per_line) == 0)
925 {
926 ($nibble_offset > 0) and print "\n ";
927 printf("$addr_format: ", $curr_address + $nibble_offset/2);
928 }
929 (($nibble_offset % 2) == 0) and print ' ';
930 print $nibble;
931 $nibble_offset++;
932 }
933 }
934 print "\n";
935}
936
937#----------------------------------------------------------------------
938# 'c' command
939#----------------------------------------------------------------------
940sub dump_continue_cmd
941{
942 my $cmd = shift;
943 my $address = -1;
944 if (@_)
945 {
946 my $address = get_addr(\@_);
947 printf("continue ($addr_format)\n", $address);
948 }
949 else
950 {
951 printf("continue ()\n");
952 }
953}
954
955#----------------------------------------------------------------------
956# 'Css' continue (C) with signal (ss where 'ss' is two hex digits)
957#----------------------------------------------------------------------
958sub dump_continue_with_signal_cmd
959{
960 my $cmd = shift;
961 my $address = -1;
962 my $signal = get_hex(\@_);
963 if (@_)
964 {
965 my $address = 0;
966 if (@_ && $_[0] == ';')
967 {
968 shift;
969 $address = get_addr(\@_);
970 }
971 }
972
973 if ($address != -1)
974 {
975 printf("continue_with_signal (signal = 0x%2.2x, address = $addr_format)\n", $signal, $address);
976 }
977 else
978 {
979 printf("continue_with_signal (signal = 0x%2.2x)\n", $signal);
980 }
981}
982
983#----------------------------------------------------------------------
984# 'A' command
985#----------------------------------------------------------------------
986sub dump_A_command
987{
988 my $cmd = get_exptected_char(\@_, 'A') or print "error: incorrect command letter for argument packet, exptected 'A'\n";
989 printf("set_program_arguments (\n");
990 do
991 {
992 my $arg_len = get_uint(\@_);
993 get_exptected_char(\@_, ',') or die "error: missing comma after argument length...?\n";
994 my $arg_idx = get_uint(\@_);
995 get_exptected_char(\@_, ',') or die "error: missing comma after argument number...?\n";
996
997 my $arg = '';
998 my $num_hex8_bytes = $arg_len/2;
999 for (1 .. $num_hex8_bytes)
1000 {
1001 $arg .= sprintf("%c", get8(\@_))
1002 }
1003 printf(" <%3u> argv[%u] = '%s'\n", $arg_len, $arg_idx, $arg);
1004 if (@_ > 0)
1005 {
1006 get_exptected_char(\@_, ',') or die "error: missing comma after argument argument ASCII hex bytes...?\n";
1007 }
1008 } while (@_ > 0);
1009 printf(" )\n");
1010}
1011
1012
1013#----------------------------------------------------------------------
1014# 'z' and 'Z' command
1015#----------------------------------------------------------------------
1016sub dump_bp_wp_command
1017{
1018 my $cmd = shift;
1019 my $type = shift;
1020 shift; # Skip ','
1021 my $address = get_addr(\@_);
1022 shift; # Skip ','
1023 my $length = join('',@_);
1024 if ($cmd eq 'z')
1025 {
1026 printf("remove $point_types[$type]($addr_format, %d)\n", $address, $length);
1027 }
1028 else
1029 {
1030 printf("insert $point_types[$type]($addr_format, %d)\n", $address, $length);
1031 }
1032}
1033
1034
1035#----------------------------------------------------------------------
1036# 'X' command
1037#----------------------------------------------------------------------
1038sub dump_write_mem_binary_cmd
1039{
1040 my $cmd = shift;
1041 my $address = get_addr(\@_);
1042 shift; # Skip ','
1043
1044 my ($length, $binary) = split(/:/, join('',@_));
1045 printf("write_mem_binary ( $addr_format, %d, %s)\n", $address, $length, $binary);
1046
1047}
1048
1049#----------------------------------------------------------------------
1050# 'M' command
1051#----------------------------------------------------------------------
1052sub dump_write_mem_cmd
1053{
1054 my $cmd = shift;
1055 my $address = get_addr(\@_);
1056 shift; # Skip ','
1057 my ($length, $hex_bytes) = split(/:/, join('',@_));
1058# printf("write_mem ( $addr_format, %d, %s)\n", $address, $length, $hex_bytes);
1059 printf("write_mem ( addr = $addr_format, len = %d (0x%x), bytes = ", $address, $length, $length);
1060 splice(@_, 0, length($length)+1);
1061
1062 my $curr_address = $address;
1063 my $nibble;
1064 my $nibble_count = 0;
1065 my $max_nibbles_per_line = 2 * $max_bytes_per_line;
1066 foreach $nibble (@_)
1067 {
1068 (($nibble_count % 2) == 0) and print ' ';
1069 print $nibble;
1070 $nibble_count++;
1071 }
1072
1073 # If the memory to write is 2 or 4 bytes, print it out in native format
1074 # instead of just as bytes.
1075 if (@_ == 4)
1076 {
1077 printf(" ( 0x%4.4x )", get16(\@_));
1078 }
1079 elsif (@_ == 8)
1080 {
1081 printf(" ( 0x%8.8x )", get32(\@_));
1082 }
1083 print " )\n";
1084
1085}
1086
1087#----------------------------------------------------------------------
1088# 'v' command
1089#----------------------------------------------------------------------
1090our $extended_rsp_callback = 0;
1091sub dump_extended_cmd
1092{
1093 $extended_rsp_callback = 0;
1094 if (join('', @_[0..4]) eq "vCont")
1095 {
1096 dump_extended_continue_cmd(splice(@_,5));
1097 }
1098 elsif (join('', @_[0..11]) eq 'vAttachWait;')
1099 {
1100 dump_attach_wait_command (splice(@_,12));
1101 }
1102}
1103
1104#----------------------------------------------------------------------
1105# 'v' response
1106#----------------------------------------------------------------------
1107sub dump_extended_rsp
1108{
1109 if ($extended_rsp_callback)
1110 {
1111 &$extended_rsp_callback(@_);
1112 }
1113 $extended_rsp_callback = 0;
1114}
1115
1116#----------------------------------------------------------------------
1117# 'vAttachWait' command
1118#----------------------------------------------------------------------
1119sub dump_attach_wait_command
1120{
1121# print "dump_extended_continue_cmd ( ";
1122# dump_chars(@_);
1123# print " )\n";
1124 print "attach_wait ( ";
1125 while (@_)
1126 {
1127 printf("%c", get8(\@_))
1128 }
1129 printf " )\n";
1130
1131}
1132
1133#----------------------------------------------------------------------
1134# 'vCont' command
1135#----------------------------------------------------------------------
1136sub dump_extended_continue_cmd
1137{
1138# print "dump_extended_continue_cmd ( ";
1139# dump_chars(@_);
1140# print " )\n";
1141 print "extended_continue ( ";
1142 my $cmd = shift;
1143 if ($cmd eq '?')
1144 {
1145 print "list supported modes )\n";
1146 $extended_rsp_callback = \&dump_extended_continue_rsp;
1147 }
1148 elsif ($cmd eq ';')
1149 {
1150 $extended_rsp_callback = \&dump_stop_reply_packet;
1151 my $i = 0;
1152 while ($#_ >= 0)
1153 {
1154 if ($i > 0)
1155 {
1156 print ", ";
1157 }
1158 my $continue_cmd = shift;
1159 my $tmp;
1160 if ($continue_cmd eq 'c')
1161 {
1162 print "continue";
1163 }
1164 elsif ($continue_cmd eq 'C')
1165 {
1166 print "continue with signal ";
1167 print shift;
1168 print shift;
1169 }
1170 elsif ($continue_cmd eq 's')
1171 {
1172 print "step";
1173 }
1174 elsif ($continue_cmd eq 'S')
1175 {
1176 print "step with signal ";
1177 print shift;
1178 print shift;
1179 }
1180
1181 if ($_[0] eq ':')
1182 {
1183 shift; # Skip ':'
1184 print " for thread ";
1185 while ($#_ >= 0)
1186 {
1187 $tmp = shift;
1188 if (length($tmp) > 0 && $tmp ne ';') {
1189 print $tmp;
1190 } else {
1191 last;
1192 }
1193 }
1194 }
1195 $i++;
1196 }
1197
1198 printf " )\n";
1199 }
1200}
1201
1202#----------------------------------------------------------------------
1203# 'vCont' response
1204#----------------------------------------------------------------------
1205sub dump_extended_continue_rsp
1206{
1207 print "extended_continue ( " . join('',@_) . " )\n";
1208}
1209
1210#----------------------------------------------------------------------
1211# Dump the command ascii for any unknown commands
1212#----------------------------------------------------------------------
1213sub dump_other_cmd
1214{
1215 print "other = " . join('',@_) . "\n";
1216}
1217
1218#----------------------------------------------------------------------
1219# Check to see if the response was unsupported with appropriate checksum
1220#----------------------------------------------------------------------
1221sub rsp_is_unsupported
1222{
1223 return join('',@_) eq "#00";
1224}
1225
1226#----------------------------------------------------------------------
1227# Check to see if the response was "OK" with appropriate checksum
1228#----------------------------------------------------------------------
1229sub rsp_is_OK
1230{
1231 return join('',@_) eq "OK#9a";
1232}
1233
1234#----------------------------------------------------------------------
1235# Dump a response for an unknown command
1236#----------------------------------------------------------------------
1237sub dump_other_rsp
1238{
1239 print "other = " . join('',@_) . "\n";
1240}
1241
1242#----------------------------------------------------------------------
1243# Get a byte from the ascii string assuming that the 2 nibble ascii
1244# characters are in hex.
1245#
1246# The argument for this function needs to be a reference to an array
1247# that contains single character strings and the array will get
1248# updated by shifting characters off the front of it (no leading # "0x")
1249#----------------------------------------------------------------------
1250sub get8
1251{
1252 my $arrayref = shift;
1253 my $val = hex(shift(@$arrayref) . shift(@$arrayref));
1254 return $val;
1255}
1256
1257#----------------------------------------------------------------------
1258# Get a 16 bit integer and swap if $swap global is set to a non-zero
1259# value.
1260#
1261# The argument for this function needs to be a reference to an array
1262# that contains single character strings and the array will get
1263# updated by shifting characters off the front of it (no leading # "0x")
1264#----------------------------------------------------------------------
1265sub get16
1266{
1267 my $arrayref = shift;
1268 my $val = 0;
1269 if ($swap)
1270 {
1271 $val = get8($arrayref) |
1272 get8($arrayref) << 8;
1273 }
1274 else
1275 {
1276 $val = get8($arrayref) << 8 |
1277 get8($arrayref) ;
1278 }
1279 return $val;
1280}
1281
1282#----------------------------------------------------------------------
1283# Get a 32 bit integer and swap if $swap global is set to a non-zero
1284# value.
1285#
1286# The argument for this function needs to be a reference to an array
1287# that contains single character strings and the array will get
1288# updated by shifting characters off the front of it (no leading # "0x")
1289#----------------------------------------------------------------------
1290sub get32
1291{
1292 my $arrayref = shift;
1293 my $val = 0;
1294 if ($swap)
1295 {
1296 $val = get8($arrayref) |
1297 get8($arrayref) << 8 |
1298 get8($arrayref) << 16 |
1299 get8($arrayref) << 24 ;
1300 }
1301 else
1302 {
1303 $val = get8($arrayref) << 24 |
1304 get8($arrayref) << 16 |
1305 get8($arrayref) << 8 |
1306 get8($arrayref) ;
1307 }
1308 return $val;
1309}
1310
1311#----------------------------------------------------------------------
1312# Get a 64 bit hex value as a string
1313#
1314# The argument for this function needs to be a reference to an array
1315# that contains single character strings and the array will get
1316# updated by shifting characters off the front of it (no leading # "0x")
1317#----------------------------------------------------------------------
1318sub get64
1319{
1320 my $arrayref = shift;
1321 my $val = '';
1322 my @nibbles;
1323 if ($swap)
1324 {
1325 push @nibbles, splice(@$arrayref, 14, 2);
1326 push @nibbles, splice(@$arrayref, 12, 2);
1327 push @nibbles, splice(@$arrayref, 10, 2);
1328 push @nibbles, splice(@$arrayref, 8, 2);
1329 push @nibbles, splice(@$arrayref, 6, 2);
1330 push @nibbles, splice(@$arrayref, 4, 2);
1331 push @nibbles, splice(@$arrayref, 2, 2);
1332 push @nibbles, splice(@$arrayref, 0, 2);
1333 }
1334 else
1335 {
1336 (@nibbles) = splice(@$arrayref, 0, 24);
1337 }
1338 $val = join('', @nibbles);
1339 return $val;
1340}
1341
1342#----------------------------------------------------------------------
1343# Get a 80 bit hex value as a string
1344#
1345# The argument for this function needs to be a reference to an array
1346# that contains single character strings and the array will get
1347# updated by shifting characters off the front of it (no leading # "0x")
1348#----------------------------------------------------------------------
1349sub get80
1350{
1351 my $arrayref = shift;
1352 my $val = '';
1353 my @nibbles;
1354 if ($swap)
1355 {
1356 push @nibbles, splice(@$arrayref, 18, 2);
1357 push @nibbles, splice(@$arrayref, 16, 2);
1358 push @nibbles, splice(@$arrayref, 14, 2);
1359 push @nibbles, splice(@$arrayref, 12, 2);
1360 push @nibbles, splice(@$arrayref, 10, 2);
1361 push @nibbles, splice(@$arrayref, 8, 2);
1362 push @nibbles, splice(@$arrayref, 6, 2);
1363 push @nibbles, splice(@$arrayref, 4, 2);
1364 push @nibbles, splice(@$arrayref, 2, 2);
1365 push @nibbles, splice(@$arrayref, 0, 2);
1366 }
1367 else
1368 {
1369 (@nibbles) = splice(@$arrayref, 0, 24);
1370 }
1371 $val = join('', @nibbles);
1372 return $val;
1373}
1374
1375#----------------------------------------------------------------------
1376# Get a 96 bit hex value as a string
1377#
1378# The argument for this function needs to be a reference to an array
1379# that contains single character strings and the array will get
1380# updated by shifting characters off the front of it (no leading # "0x")
1381#----------------------------------------------------------------------
1382sub get96
1383{
1384 my $arrayref = shift;
1385 my $val = '';
1386 my @nibbles;
1387 if ($swap)
1388 {
1389 push @nibbles, splice(@$arrayref, 22, 2);
1390 push @nibbles, splice(@$arrayref, 20, 2);
1391 push @nibbles, splice(@$arrayref, 18, 2);
1392 push @nibbles, splice(@$arrayref, 16, 2);
1393 push @nibbles, splice(@$arrayref, 14, 2);
1394 push @nibbles, splice(@$arrayref, 12, 2);
1395 push @nibbles, splice(@$arrayref, 10, 2);
1396 push @nibbles, splice(@$arrayref, 8, 2);
1397 push @nibbles, splice(@$arrayref, 6, 2);
1398 push @nibbles, splice(@$arrayref, 4, 2);
1399 push @nibbles, splice(@$arrayref, 2, 2);
1400 push @nibbles, splice(@$arrayref, 0, 2);
1401 }
1402 else
1403 {
1404 (@nibbles) = splice(@$arrayref, 0, 24);
1405 }
1406 $val = join('', @nibbles);
1407 return $val;
1408}
1409
1410#----------------------------------------------------------------------
1411# Get a 128 bit hex value as a string
1412#
1413# The argument for this function needs to be a reference to an array
1414# that contains single character strings and the array will get
1415# updated by shifting characters off the front of it (no leading # "0x")
1416#----------------------------------------------------------------------
1417sub get128
1418{
1419 my $arrayref = shift;
1420 my $val = '';
1421 my @nibbles;
1422 if ($swap)
1423 {
1424 push @nibbles, splice(@$arrayref, 30, 2);
1425 push @nibbles, splice(@$arrayref, 28, 2);
1426 push @nibbles, splice(@$arrayref, 26, 2);
1427 push @nibbles, splice(@$arrayref, 24, 2);
1428 push @nibbles, splice(@$arrayref, 22, 2);
1429 push @nibbles, splice(@$arrayref, 20, 2);
1430 push @nibbles, splice(@$arrayref, 18, 2);
1431 push @nibbles, splice(@$arrayref, 16, 2);
1432 push @nibbles, splice(@$arrayref, 14, 2);
1433 push @nibbles, splice(@$arrayref, 12, 2);
1434 push @nibbles, splice(@$arrayref, 10, 2);
1435 push @nibbles, splice(@$arrayref, 8, 2);
1436 push @nibbles, splice(@$arrayref, 6, 2);
1437 push @nibbles, splice(@$arrayref, 4, 2);
1438 push @nibbles, splice(@$arrayref, 2, 2);
1439 push @nibbles, splice(@$arrayref, 0, 2);
1440 }
1441 else
1442 {
1443 (@nibbles) = splice(@$arrayref, 0, 24);
1444 }
1445 $val = join('', @nibbles);
1446 return $val;
1447}
1448
1449#----------------------------------------------------------------------
1450# Get a an unsigned integer value by grabbing items off the front of
1451# the array stopping when a non-digit char string is encountered.
1452#
1453# The argument for this function needs to be a reference to an array
1454# that contains single character strings and the array will get
1455# updated by shifting characters off the front of it
1456#----------------------------------------------------------------------
1457sub get_uint
1458{
1459 my $arrayref = shift;
1460 @$arrayref == 0 and return 0;
1461 my $val = 0;
1462 while ($$arrayref[0] =~ /[0-9]/)
1463 {
1464 $val = $val * 10 + int(shift(@$arrayref));
1465 }
1466 return $val;
1467}
1468
1469#----------------------------------------------------------------------
1470# Check the first character in the array and if it matches the expected
1471# character, return that character, else return undef;
1472#
1473# The argument for this function needs to be a reference to an array
1474# that contains single character strings and the array will get
1475# updated by shifting characters off the front of it. If the expected
1476# character doesn't match, it won't touch the array. If the first
1477# character does match, it will shift it off and return it.
1478#----------------------------------------------------------------------
1479sub get_exptected_char
1480{
1481 my $arrayref = shift;
1482 my $expected_char = shift;
1483 if ($expected_char eq $$arrayref[0])
1484 {
1485 return shift(@$arrayref);
1486 }
1487 return undef;
1488}
1489#----------------------------------------------------------------------
1490# Get a hex value by grabbing items off the front of the array and
1491# stopping when a non-hex char string is encountered.
1492#
1493# The argument for this function needs to be a reference to an array
1494# that contains single character strings and the array will get
1495# updated by shifting characters off the front of it (no leading # "0x")
1496#----------------------------------------------------------------------
1497sub get_hex
1498{
1499 my $arrayref = shift;
1500 my $my_swap = @_ ? shift : 0;
1501 my $shift = 0;
1502 my $val = 0;
1503 while ($$arrayref[0] =~ /[0-9a-fA-F]/)
1504 {
1505 if ($my_swap)
1506 {
1507 my $byte = hex(shift(@$arrayref)) << 4 | hex(shift(@$arrayref));
1508 $val |= $byte << $shift;
1509 $shift += 8;
1510 }
1511 else
1512 {
1513 $val <<= 4;
1514 $val |= hex(shift(@$arrayref));
1515 }
1516 }
1517 return $val;
1518}
1519
1520#----------------------------------------------------------------------
1521# Get an address value by grabbing items off the front of the array.
1522#
1523# The argument for this function needs to be a reference to an array
1524# that contains single character strings and the array will get
1525# updated by shifting characters off the front of it (no leading # "0x")
1526#----------------------------------------------------------------------
1527sub get_addr
1528{
1529 get_hex(shift);
1530}
1531
1532sub dump_stop_reply_data
1533{
1534 while ($#_ >= 0)
1535 {
1536 last unless ($_[0] ne '#');
1537
1538
1539 my $key = '';
1540 my $value = '';
1541 if ($_[0] =~ /[0-9a-fA-F]/ && $_[1] =~ /[0-9a-fA-F]/)
1542 {
1543 my $reg_num = get8(\@_);
1544 shift(@_); # Skip ':'
1545 if (defined ($registers_aref) && $reg_num < @$registers_aref)
1546 {
1547 dump_register_value(1, \@_, $reg_num);
1548 print "\n";
1549 shift(@_); # Skip ';'
1550 next;
1551 }
1552 $key = sprintf("reg %u", $reg_num);
1553 }
1554 my $char;
1555
1556 if (length($key) == 0)
1557 {
1558 while (1)
1559 {
1560 $char = shift(@_);
1561 if (length($char) == 0 or $char eq ':' or $char eq '#') { last; }
1562 $key .= $char;
1563 }
1564 }
1565
1566 while (1)
1567 {
1568 $char = shift(@_);
1569 if (length($char) == 0 or $char eq ';' or $char eq '#') { last; }
1570 $value .= $char;
1571 }
1572 printf("\t%*s = %s\n", $max_register_name_len, $key, $value);
1573 }
1574}
1575
1576#----------------------------------------------------------------------
1577# Dumps a Stop Reply Packet which happens in response to a step,
1578# continue, last signal, and probably a few other commands.
1579#----------------------------------------------------------------------
1580sub dump_stop_reply_packet
1581{
1582 my $what = shift(@_);
1583 if ($what eq 'S')
1584 {
1585 print 'signal ( 0x' . shift(@_) . shift(@_) . " )\n";
1586 }
1587 elsif ($what eq 'T')
1588 {
1589 print 'signal ( 0x' . shift(@_) . shift(@_) . " )\n";
1590 dump_stop_reply_data (@_);
1591 }
1592 elsif ($what eq 'W')
1593 {
1594 print 'process_exited( ' . shift(@_) . shift(@_) . " )\n";
1595 }
1596 elsif ($what eq 'X')
1597 {
1598 print 'process_terminated( ' . shift(@_) . shift(@_) . " )\n";
1599 }
1600 elsif ($what eq 'O')
1601 {
1602 my $console_output = '';
1603 my $num_hex8_bytes = @_/2;
1604 for (1 .. $num_hex8_bytes)
1605 {
1606 $console_output .= sprintf("%c", get8(\@_))
1607 }
1608
1609 print "program_console_output('$console_output')\n";
1610 }
1611}
1612
1613#----------------------------------------------------------------------
1614# '?' command
1615#----------------------------------------------------------------------
1616sub dump_last_signal_cmd
1617{
1618 my $cmd = shift;
1619 print 'last_signal (' . join('',@_) . ")\n";
1620}
1621
1622sub dump_raw_command
1623{
1624 my $cmd_aref = shift;
1625 my $callback_ref;
1626 $curr_cmd = $$cmd_aref[0];
1627 $curr_cmd eq '_' and $curr_cmd .= $$cmd_aref[1];
1628
1629 $callback_ref = $cmd_callbacks{$curr_cmd};
1630 if ($callback_ref)
1631 {
1632 &$callback_ref(@$cmd_aref);
1633 }
1634 else
1635 {
1636 # Strip the command byte for responses since we injected that above
1637 dump_other_cmd(@$cmd_aref);
1638 }
1639}
1640
1641sub dump_standard_response
1642{
1643 my $cmd_aref = shift;
1644
1645 if (@$cmd_aref == 0)
1646 {
1647 print "$unsupported_str\n";
1648 return 1;
1649 }
1650
1651 my $response = join('', @$cmd_aref);
1652 if ($response eq 'OK')
1653 {
1654 print "$success_str\n";
1655 return 1;
1656 }
1657
1658 if (index($response, 'E') == 0)
1659 {
1660 print "ERROR: " . substr($response, 1) . "\n";
1661 return 1;
1662 }
1663
1664 return 0;
1665}
1666sub dump_raw_response
1667{
1668 my $cmd_aref = shift;
1669 my $callback_ref;
1670
1671 $callback_ref = $rsp_callbacks{$curr_cmd};
1672
1673 if ($callback_ref)
1674 {
1675 &$callback_ref(@$cmd_aref);
1676 }
1677 else
1678 {
1679 dump_standard_response($cmd_aref) or dump_other_rsp(@$cmd_aref);
1680 }
1681
1682}
1683#----------------------------------------------------------------------
1684# Dumps any command and handles simple error checking on the responses
1685# for commands that are unsupported or OK.
1686#----------------------------------------------------------------------
1687sub dump_command
1688{
1689 my $cmd_str = shift;
1690
1691 # Dump the original command string if verbose is on
1692 if ($opt_v)
1693 {
1694 print "dump_command($cmd_str)\n ";
1695 }
1696
1697 my @cmd_chars = extract_command($cmd_str);
1698 my $is_cmd = 1;
1699
1700 my $cmd = $cmd_chars[0];
1701 if ($cmd eq '$')
1702 {
1703 $is_cmd = 0; # Note that this is a reply
1704 $cmd = $curr_cmd; # set the command byte appropriately
1705 shift @cmd_chars; # remove the '$' from the cmd bytes
1706 }
1707
1708 # Check for common responses across all commands and handle them
1709 # if we can
1710 if ( $is_cmd == 0 )
1711 {
1712 if (rsp_is_unsupported(@cmd_chars))
1713 {
1714 print "$unsupported_str\n";
1715 return;
1716 }
1717 elsif (rsp_is_OK(@cmd_chars))
1718 {
1719 print "$success_str\n";
1720 return;
1721 }
1722 # Strip the checksum information for responses
1723 strip_checksum(\@cmd_chars);
1724 }
1725
1726 my $callback_ref;
1727 if ($is_cmd) {
1728 $callback_ref = $cmd_callbacks{$cmd};
1729 } else {
1730 $callback_ref = $rsp_callbacks{$cmd};
1731 }
1732
1733 if ($callback_ref)
1734 {
1735 &$callback_ref(@cmd_chars);
1736 }
1737 else
1738 {
1739 # Strip the command byte for responses since we injected that above
1740 if ($is_cmd) {
1741 dump_other_cmd(@cmd_chars);
1742 } else {
1743 dump_other_rsp(@cmd_chars);
1744 }
1745
1746 }
1747}
1748
1749
1750#----------------------------------------------------------------------
1751# Process a gdbserver log line by looking for getpkt and putkpt and
1752# tossing any other lines.
1753#----------------------------------------------------------------------
1754sub process_log_line
1755{
1756 my $line = shift;
1757 #($opt_v and $opt_g) and print "# $line";
1758 my $extract_cmd = 0;
1759 if ($line =~ /getpkt /)
1760 {
1761 $extract_cmd = 1;
1762 print "\n--> ";
1763 }
1764 elsif ($line =~ /putpkt /)
1765 {
1766 $extract_cmd = 1;
1767 print "<-- ";
1768 }
1769 elsif ($line =~ /.*Sent: \[[0-9]+\.[0-9]+[:0-9]*\] (.*)/)
1770 {
1771 $opt_g and print "maintenance dump-packets command: $1\n";
1772 my @raw_cmd_bytes = split(/ */, $1);
1773 print "\n--> ";
1774 dump_raw_command(\@raw_cmd_bytes);
1775 process_log_line($2);
1776 }
1777 elsif ($line =~ /.*Recvd: \[[0-9]+\.[0-9]+[:0-9]*\] (.*)/)
1778 {
1779 $opt_g and print "maintenance dump-packets reply: $1\n";
1780 my @raw_rsp_bytes = split(/ */, $1);
1781 print "<-- ";
1782 dump_raw_response(\@raw_rsp_bytes);
1783 print "\n";
1784 }
1785 elsif ($line =~ /getpkt: (.*)/)
1786 {
1787 if ($1 =~ /\$([^#]+)#[0-9a-fA-F]{2}/)
1788 {
1789 $opt_g and print "command: $1\n";
1790 my @raw_cmd_bytes = split(/ */, $1);
1791 print "--> ";
1792 dump_raw_command(\@raw_cmd_bytes);
1793 }
1794 elsif ($1 =~ /\+/)
1795 {
1796 #print "--> ACK\n";
1797 }
1798 elsif ($1 =~ /-/)
1799 {
1800 #print "--> NACK\n";
1801 }
1802 }
1803 elsif ($line =~ /putpkt: (.*)/)
1804 {
1805 if ($1 =~ /\$([^#]+)#[0-9a-fA-F]{2}/)
1806 {
1807 $opt_g and print "response: $1\n";
1808 my @raw_rsp_bytes = split(/ */, $1);
1809 print "<-- ";
1810 dump_raw_response(\@raw_rsp_bytes);
1811 print "\n";
1812 }
1813 elsif ($1 =~ /\+/)
1814 {
1815 #print "<-- ACK\n";
1816 }
1817 elsif ($1 =~ /-/)
1818 {
1819 #print "<-- NACK\n";
1820 }
1821 }
1822 elsif ($line =~ /send packet: (.*)/)
1823 {
1824 if ($1 =~ /\$([^#]+)#[0-9a-fA-F]{2}/)
1825 {
1826 $opt_g and print "command: $1\n";
1827 my @raw_cmd_bytes = split(/ */, $1);
1828 print "--> ";
1829 dump_raw_command(\@raw_cmd_bytes);
1830 }
1831 elsif ($1 =~ /\+/)
1832 {
1833 #print "--> ACK\n";
1834 }
1835 elsif ($1 =~ /-/)
1836 {
1837 #print "--> NACK\n";
1838 }
1839 }
1840 elsif ($line =~ /read packet: (.*)/)
1841 {
1842 if ($1 =~ /\$([^#]+)#[0-9a-fA-F]{2}/)
1843 {
1844 $opt_g and print "response: $1\n";
1845 my @raw_rsp_bytes = split(/ */, $1);
1846 print "<-- ";
1847 dump_raw_response(\@raw_rsp_bytes);
1848 print "\n";
1849 }
1850 elsif ($1 =~ /\+/)
1851 {
1852 #print "<-- ACK\n";
1853 }
1854 elsif ($1 =~ /-/)
1855 {
1856 #print "<-- NACK\n";
1857 }
1858 }
1859 elsif ($line =~ /Sending packet: \$([^#]+)#[0-9a-fA-F]{2}\.\.\.(.*)/)
1860 {
1861 $opt_g and print "command: $1\n";
1862 my @raw_cmd_bytes = split(/ */, $1);
1863 print "\n--> ";
1864 dump_raw_command(\@raw_cmd_bytes);
1865 process_log_line($2);
1866 }
1867 elsif ($line =~ /Packet received: (.*)/)
1868 {
1869 $opt_g and print "response: $1\n";
1870 my @raw_rsp_bytes = split(/ */, $1);
1871 print "<-- ";
1872 dump_raw_response(\@raw_rsp_bytes);
1873 print "\n";
1874 }
1875
1876 if ($extract_cmd)
1877 {
1878 my $beg = index($line, '("') + 2;
1879 my $end = rindex($line, '");');
1880 dump_command(substr($line, $beg, $end - $beg));
1881 }
1882}
1883
1884
1885our $line_num = 0;
1886while(<>)
1887{
1888 $line_num++;
1889 $opt_q or printf("# %5d: $_", $line_num);
1890 process_log_line($_);
1891}
1892
1893
1894
1895
1896
1897