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