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