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