| #!/usr/bin/env perl | 
 |  | 
 | use strict; | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Globals | 
 | #---------------------------------------------------------------------- | 
 | our $unimplemented_str = "UNIMPLEMENTED"; | 
 | our $success_str = "OK"; | 
 | our $swap = 1; | 
 | our $addr_size = 4; | 
 | our $thread_suffix_supported = 0; | 
 | our $max_bytes_per_line = 32; | 
 | our $addr_format = sprintf("0x%%%u.%ux", $addr_size*2, $addr_size*2); | 
 | our $pid_format = "%04.4x"; | 
 | our $tid_format = "%04.4x"; | 
 | our $reg8_href = { extract => \&get8, format => "0x%2.2x" }; | 
 | our $reg16_href = { extract => \&get16, format => "0x%4.4x" }; | 
 | our $reg32_href = { extract => \&get32, format => "0x%8.8x" }; | 
 | our $reg64_href = { extract => \&get64, format => "0x%s" }; | 
 | our $reg80_href = { extract => \&get80, format => "0x%s" }; | 
 | our $reg128_href = { extract => \&get128, format => "0x%s" }; | 
 | our $reg256_href = { extract => \&get256, format => "0x%s" }; | 
 | our $float32_href = { extract => \&get32, format => "0x%8.8x" }; | 
 | our $float64_href = { extract => \&get64, format => "0x%s" }; | 
 | our $float96_href = { extract => \&get96, format => "0x%s" }; | 
 | our $curr_cmd = undef; | 
 | our $curr_full_cmd = undef; | 
 | our %packet_times; | 
 | our $curr_time = 0.0; | 
 | our $last_time = 0.0; | 
 | our $base_time = 0.0; | 
 | our $packet_start_time = 0.0; | 
 | our $reg_cmd_reg; | 
 | our %reg_map = ( | 
 | 	'i386-gdb' => [  | 
 | 	    { name => 'eax',    info => $reg32_href     }, | 
 |         { name => 'ecx',    info => $reg32_href     }, | 
 |         { name => 'edx',    info => $reg32_href     }, | 
 |         { name => 'ebx',    info => $reg32_href     }, | 
 |         { name => 'esp',    info => $reg32_href     }, | 
 |         { name => 'ebp',    info => $reg32_href     }, | 
 |         { name => 'esi',    info => $reg32_href     }, | 
 |         { name => 'edi',    info => $reg32_href     }, | 
 |         { name => 'eip',    info => $reg32_href     }, | 
 |         { name => 'eflags', info => $reg32_href     }, | 
 |         { name => 'cs',     info => $reg32_href     }, | 
 |         { name => 'ss',     info => $reg32_href     }, | 
 |         { name => 'ds',     info => $reg32_href     }, | 
 |         { name => 'es',     info => $reg32_href     }, | 
 |         { name => 'fs',     info => $reg32_href     }, | 
 |         { name => 'gs',     info => $reg32_href     }, | 
 |         { name => 'st0',    info => $reg80_href     }, | 
 |         { name => 'st1',    info => $reg80_href     }, | 
 |         { name => 'st2',    info => $reg80_href     }, | 
 |         { name => 'st3',    info => $reg80_href     }, | 
 |         { name => 'st4',    info => $reg80_href     }, | 
 |         { name => 'st5',    info => $reg80_href     }, | 
 |         { name => 'st6',    info => $reg80_href     }, | 
 |         { name => 'st7',    info => $reg80_href     }, | 
 |         { name => 'fctrl',  info => $reg32_href     }, | 
 |         { name => 'fstat',  info => $reg32_href     }, | 
 |         { name => 'ftag',   info => $reg32_href     }, | 
 |         { name => 'fiseg',  info => $reg32_href     }, | 
 |         { name => 'fioff',  info => $reg32_href     }, | 
 |         { name => 'foseg',  info => $reg32_href     }, | 
 |         { name => 'fooff',  info => $reg32_href     }, | 
 |         { name => 'fop',    info => $reg32_href     }, | 
 |     	{ name => 'xmm0',   info => $reg128_href    }, | 
 |     	{ name => 'xmm1',   info => $reg128_href    }, | 
 |     	{ name => 'xmm2',   info => $reg128_href    }, | 
 |     	{ name => 'xmm3',   info => $reg128_href    }, | 
 |     	{ name => 'xmm4',   info => $reg128_href    }, | 
 |     	{ name => 'xmm5',   info => $reg128_href    }, | 
 |     	{ name => 'xmm6',   info => $reg128_href    }, | 
 |     	{ name => 'xmm7',   info => $reg128_href    }, | 
 |     	{ name => 'mxcsr',  info => $reg32_href     }, | 
 |         { name => 'mm0',    info => $reg64_href     }, | 
 |         { name => 'mm1',    info => $reg64_href     }, | 
 |         { name => 'mm2',    info => $reg64_href     }, | 
 |         { name => 'mm3',    info => $reg64_href     }, | 
 |         { name => 'mm4',    info => $reg64_href     }, | 
 |         { name => 'mm5',    info => $reg64_href     }, | 
 |         { name => 'mm6',    info => $reg64_href     }, | 
 |         { name => 'mm7',    info => $reg64_href     }, | 
 |     ], | 
 |      | 
 |     'i386-lldb' => [ | 
 |         { name => 'eax',          info => $reg32_href   }, | 
 |         { name => 'ebx',          info => $reg32_href   }, | 
 |         { name => 'ecx',          info => $reg32_href   }, | 
 |         { name => 'edx',          info => $reg32_href   }, | 
 |         { name => 'edi',          info => $reg32_href   }, | 
 |         { name => 'esi',          info => $reg32_href   }, | 
 |         { name => 'ebp',          info => $reg32_href   }, | 
 |         { name => 'esp',          info => $reg32_href   }, | 
 |         { name => 'ss',           info => $reg32_href   }, | 
 |         { name => 'eflags',       info => $reg32_href   }, | 
 |         { name => 'eip',          info => $reg32_href   }, | 
 |         { name => 'cs',           info => $reg32_href   }, | 
 |         { name => 'ds',           info => $reg32_href   }, | 
 |         { name => 'es',           info => $reg32_href   }, | 
 |         { name => 'fs',           info => $reg32_href   }, | 
 |         { name => 'gs',           info => $reg32_href   }, | 
 |     	{ name => 'fctrl',        info => $reg16_href   }, | 
 |     	{ name => 'fstat',        info => $reg16_href   }, | 
 |     	{ name => 'ftag',         info => $reg8_href    }, | 
 |     	{ name => 'fop',          info => $reg16_href   }, | 
 |     	{ name => 'fioff',        info => $reg32_href   }, | 
 |     	{ name => 'fiseg',        info => $reg16_href   }, | 
 |     	{ name => 'fooff',        info => $reg32_href   }, | 
 |     	{ name => 'foseg',        info => $reg16_href   }, | 
 |     	{ name => 'mxcsr',        info => $reg32_href   }, | 
 |     	{ name => 'mxcsrmask',    info => $reg32_href   }, | 
 |     	{ name => 'stmm0',        info => $reg80_href   }, | 
 |     	{ name => 'stmm1',        info => $reg80_href   }, | 
 |     	{ name => 'stmm2',        info => $reg80_href   }, | 
 |     	{ name => 'stmm3',        info => $reg80_href   }, | 
 |     	{ name => 'stmm4',        info => $reg80_href   }, | 
 |     	{ name => 'stmm5',        info => $reg80_href   }, | 
 |     	{ name => 'stmm6',        info => $reg80_href   }, | 
 |     	{ name => 'stmm7',        info => $reg80_href   }, | 
 |     	{ name => 'xmm0',         info => $reg128_href  }, | 
 |     	{ name => 'xmm1',         info => $reg128_href  }, | 
 |     	{ name => 'xmm2',         info => $reg128_href  }, | 
 |     	{ name => 'xmm3',         info => $reg128_href  }, | 
 |     	{ name => 'xmm4',         info => $reg128_href  }, | 
 |     	{ name => 'xmm5',         info => $reg128_href  }, | 
 |     	{ name => 'xmm6',         info => $reg128_href  }, | 
 |     	{ name => 'xmm7',         info => $reg128_href  }, | 
 |     	{ name => 'trapno',       info => $reg32_href   }, | 
 |     	{ name => 'err',          info => $reg32_href   }, | 
 |     	{ name => 'faultvaddr',   info => $reg32_href   }, | 
 |     ], | 
 |      | 
 |     'arm-gdb' => [ | 
 |         { name => 'r0'      , info => $reg32_href   }, | 
 |         { name => 'r1'      , info => $reg32_href   }, | 
 |         { name => 'r2'      , info => $reg32_href   }, | 
 |         { name => 'r3'      , info => $reg32_href   }, | 
 |         { name => 'r4'      , info => $reg32_href   }, | 
 |         { name => 'r5'      , info => $reg32_href   }, | 
 |         { name => 'r6'      , info => $reg32_href   }, | 
 |         { name => 'r7'      , info => $reg32_href   }, | 
 |         { name => 'r8'      , info => $reg32_href   }, | 
 |         { name => 'r9'      , info => $reg32_href   }, | 
 |         { name => 'r10'     , info => $reg32_href   }, | 
 |         { name => 'r11'     , info => $reg32_href   }, | 
 |         { name => 'r12'     , info => $reg32_href   }, | 
 |         { name => 'sp'      , info => $reg32_href   }, | 
 |         { name => 'lr'      , info => $reg32_href   }, | 
 |         { name => 'pc'      , info => $reg32_href   }, | 
 |         { name => 'f0'      , info => $float96_href }, | 
 |         { name => 'f1'      , info => $float96_href }, | 
 |         { name => 'f2'      , info => $float96_href }, | 
 |         { name => 'f3'      , info => $float96_href }, | 
 |         { name => 'f4'      , info => $float96_href }, | 
 |         { name => 'f5'      , info => $float96_href }, | 
 |         { name => 'f6'      , info => $float96_href }, | 
 |         { name => 'f7'      , info => $float96_href }, | 
 |         { name => 'fps'     , info => $reg32_href   }, | 
 |         { name => 'cpsr'    , info => $reg32_href   }, | 
 |         { name => 's0'      , info => $float32_href }, | 
 |         { name => 's1'      , info => $float32_href }, | 
 |         { name => 's2'      , info => $float32_href }, | 
 |         { name => 's3'      , info => $float32_href }, | 
 |         { name => 's4'      , info => $float32_href }, | 
 |         { name => 's5'      , info => $float32_href }, | 
 |         { name => 's6'      , info => $float32_href }, | 
 |         { name => 's7'      , info => $float32_href }, | 
 |         { name => 's8'      , info => $float32_href }, | 
 |         { name => 's9'      , info => $float32_href }, | 
 |         { name => 's10'     , info => $float32_href }, | 
 |         { name => 's11'     , info => $float32_href }, | 
 |         { name => 's12'     , info => $float32_href }, | 
 |         { name => 's13'     , info => $float32_href }, | 
 |         { name => 's14'     , info => $float32_href }, | 
 |         { name => 's15'     , info => $float32_href }, | 
 |         { name => 's16'     , info => $float32_href }, | 
 |         { name => 's17'     , info => $float32_href }, | 
 |         { name => 's18'     , info => $float32_href }, | 
 |         { name => 's19'     , info => $float32_href }, | 
 |         { name => 's20'     , info => $float32_href }, | 
 |         { name => 's21'     , info => $float32_href }, | 
 |         { name => 's22'     , info => $float32_href }, | 
 |         { name => 's23'     , info => $float32_href },  | 
 |         { name => 's24'     , info => $float32_href }, | 
 |         { name => 's25'     , info => $float32_href }, | 
 |         { name => 's26'     , info => $float32_href }, | 
 |         { name => 's27'     , info => $float32_href }, | 
 |         { name => 's28'     , info => $float32_href }, | 
 |         { name => 's29'     , info => $float32_href }, | 
 |         { name => 's30'     , info => $float32_href }, | 
 |         { name => 's31'     , info => $float32_href }, | 
 |         { name => 'fpscr'   , info => $reg32_href   }, | 
 |         { name => 'd16'     , info => $float64_href }, | 
 |         { name => 'd17'     , info => $float64_href }, | 
 |         { name => 'd18'     , info => $float64_href }, | 
 |         { name => 'd19'     , info => $float64_href }, | 
 |         { name => 'd20'     , info => $float64_href }, | 
 |         { name => 'd21'     , info => $float64_href }, | 
 |         { name => 'd22'     , info => $float64_href }, | 
 |         { name => 'd23'     , info => $float64_href },  | 
 |         { name => 'd24'     , info => $float64_href }, | 
 |         { name => 'd25'     , info => $float64_href }, | 
 |         { name => 'd26'     , info => $float64_href }, | 
 |         { name => 'd27'     , info => $float64_href }, | 
 |         { name => 'd28'     , info => $float64_href }, | 
 |         { name => 'd29'     , info => $float64_href }, | 
 |         { name => 'd30'     , info => $float64_href }, | 
 |         { name => 'd31'     , info => $float64_href }, | 
 |     ], | 
 |      | 
 |      | 
 |     'arm-lldb' => [ | 
 |         { name => 'r0'      , info => $reg32_href   }, | 
 |         { name => 'r1'      , info => $reg32_href   }, | 
 |         { name => 'r2'      , info => $reg32_href   }, | 
 |         { name => 'r3'      , info => $reg32_href   }, | 
 |         { name => 'r4'      , info => $reg32_href   }, | 
 |         { name => 'r5'      , info => $reg32_href   }, | 
 |         { name => 'r6'      , info => $reg32_href   }, | 
 |         { name => 'r7'      , info => $reg32_href   }, | 
 |         { name => 'r8'      , info => $reg32_href   }, | 
 |         { name => 'r9'      , info => $reg32_href   }, | 
 |         { name => 'r10'     , info => $reg32_href   }, | 
 |         { name => 'r11'     , info => $reg32_href   }, | 
 |         { name => 'r12'     , info => $reg32_href   }, | 
 |         { name => 'sp'      , info => $reg32_href   }, | 
 |         { name => 'lr'      , info => $reg32_href   }, | 
 |         { name => 'pc'      , info => $reg32_href   }, | 
 |         { name => 'cpsr'    , info => $reg32_href   }, | 
 |         { name => 's0'      , info => $float32_href }, | 
 |         { name => 's1'      , info => $float32_href }, | 
 |         { name => 's2'      , info => $float32_href }, | 
 |         { name => 's3'      , info => $float32_href }, | 
 |         { name => 's4'      , info => $float32_href }, | 
 |         { name => 's5'      , info => $float32_href }, | 
 |         { name => 's6'      , info => $float32_href }, | 
 |         { name => 's7'      , info => $float32_href }, | 
 |         { name => 's8'      , info => $float32_href }, | 
 |         { name => 's9'      , info => $float32_href }, | 
 |         { name => 's10'     , info => $float32_href }, | 
 |         { name => 's11'     , info => $float32_href }, | 
 |         { name => 's12'     , info => $float32_href }, | 
 |         { name => 's13'     , info => $float32_href }, | 
 |         { name => 's14'     , info => $float32_href }, | 
 |         { name => 's15'     , info => $float32_href }, | 
 |         { name => 's16'     , info => $float32_href }, | 
 |         { name => 's17'     , info => $float32_href }, | 
 |         { name => 's18'     , info => $float32_href }, | 
 |         { name => 's19'     , info => $float32_href }, | 
 |         { name => 's20'     , info => $float32_href }, | 
 |         { name => 's21'     , info => $float32_href }, | 
 |         { name => 's22'     , info => $float32_href }, | 
 |         { name => 's23'     , info => $float32_href },  | 
 |         { name => 's24'     , info => $float32_href }, | 
 |         { name => 's25'     , info => $float32_href }, | 
 |         { name => 's26'     , info => $float32_href }, | 
 |         { name => 's27'     , info => $float32_href }, | 
 |         { name => 's28'     , info => $float32_href }, | 
 |         { name => 's29'     , info => $float32_href }, | 
 |         { name => 's30'     , info => $float32_href }, | 
 |         { name => 's31'     , info => $float32_href }, | 
 |         { name => 'd0'      , info => $float64_href }, | 
 |         { name => 'd1'      , info => $float64_href }, | 
 |         { name => 'd2'      , info => $float64_href }, | 
 |         { name => 'd3'      , info => $float64_href }, | 
 |         { name => 'd4'      , info => $float64_href }, | 
 |         { name => 'd5'      , info => $float64_href }, | 
 |         { name => 'd6'      , info => $float64_href }, | 
 |         { name => 'd7'      , info => $float64_href }, | 
 |         { name => 'd8'      , info => $float64_href }, | 
 |         { name => 'd9'      , info => $float64_href }, | 
 |         { name => 'd10'     , info => $float64_href }, | 
 |         { name => 'd11'     , info => $float64_href }, | 
 |         { name => 'd12'     , info => $float64_href }, | 
 |         { name => 'd13'     , info => $float64_href }, | 
 |         { name => 'd14'     , info => $float64_href }, | 
 |         { name => 'd15'     , info => $float64_href }, | 
 |         { name => 'd16'     , info => $float64_href }, | 
 |         { name => 'd17'     , info => $float64_href }, | 
 |         { name => 'd18'     , info => $float64_href }, | 
 |         { name => 'd19'     , info => $float64_href }, | 
 |         { name => 'd20'     , info => $float64_href }, | 
 |         { name => 'd21'     , info => $float64_href }, | 
 |         { name => 'd22'     , info => $float64_href }, | 
 |         { name => 'd23'     , info => $float64_href },  | 
 |         { name => 'd24'     , info => $float64_href }, | 
 |         { name => 'd25'     , info => $float64_href }, | 
 |         { name => 'd26'     , info => $float64_href }, | 
 |         { name => 'd27'     , info => $float64_href }, | 
 |         { name => 'd28'     , info => $float64_href }, | 
 |         { name => 'd29'     , info => $float64_href }, | 
 |         { name => 'd30'     , info => $float64_href }, | 
 |         { name => 'd31'     , info => $float64_href }, | 
 |         { name => 'fpscr'   , info => $reg32_href   }, | 
 |         { name => 'exc'     , info => $reg32_href   }, | 
 |         { name => 'fsr'     , info => $reg32_href   }, | 
 |         { name => 'far'     , info => $reg32_href   }, | 
 |     ],     | 
 |      | 
 |     'x86_64-gdb' => [ | 
 |     	{ name => 'rax'		, info => $reg64_href   }, | 
 |     	{ name => 'rbx'     , info => $reg64_href   }, | 
 |     	{ name => 'rcx'     , info => $reg64_href   }, | 
 |     	{ name => 'rdx'     , info => $reg64_href   }, | 
 |     	{ name => 'rsi'     , info => $reg64_href   }, | 
 |     	{ name => 'rdi'     , info => $reg64_href   }, | 
 |     	{ name => 'rbp'     , info => $reg64_href   }, | 
 |     	{ name => 'rsp'     , info => $reg64_href   }, | 
 |     	{ name => 'r8'      , info => $reg64_href   }, | 
 |     	{ name => 'r9'      , info => $reg64_href   }, | 
 |     	{ name => 'r10'     , info => $reg64_href   }, | 
 |     	{ name => 'r11'     , info => $reg64_href   }, | 
 |     	{ name => 'r12'     , info => $reg64_href   }, | 
 |     	{ name => 'r13'     , info => $reg64_href   }, | 
 |     	{ name => 'r14'     , info => $reg64_href   }, | 
 |     	{ name => 'r15'     , info => $reg64_href   }, | 
 |     	{ name => 'rip'     , info => $reg64_href   }, | 
 |     	{ name => 'eflags'  , info => $reg32_href   }, | 
 |     	{ name => 'cs'      , info => $reg32_href   }, | 
 |     	{ name => 'ss'      , info => $reg32_href   }, | 
 |     	{ name => 'ds'      , info => $reg32_href   }, | 
 |     	{ name => 'es'      , info => $reg32_href   }, | 
 |     	{ name => 'fs'      , info => $reg32_href   }, | 
 |     	{ name => 'gs'      , info => $reg32_href   }, | 
 |     	{ name => 'stmm0'   , info => $reg80_href   }, | 
 |     	{ name => 'stmm1'   , info => $reg80_href   }, | 
 |     	{ name => 'stmm2'   , info => $reg80_href   }, | 
 |     	{ name => 'stmm3'   , info => $reg80_href   }, | 
 |     	{ name => 'stmm4'   , info => $reg80_href   }, | 
 |     	{ name => 'stmm5'   , info => $reg80_href   }, | 
 |     	{ name => 'stmm6'   , info => $reg80_href   }, | 
 |     	{ name => 'stmm7'   , info => $reg80_href   }, | 
 |     	{ name => 'fctrl'   , info => $reg32_href   }, | 
 |     	{ name => 'fstat'   , info => $reg32_href   }, | 
 |     	{ name => 'ftag'    , info => $reg32_href   }, | 
 |     	{ name => 'fiseg'   , info => $reg32_href   }, | 
 |     	{ name => 'fioff'   , info => $reg32_href   }, | 
 |     	{ name => 'foseg'   , info => $reg32_href   }, | 
 |     	{ name => 'fooff'   , info => $reg32_href   },       | 
 |     	{ name => 'fop'     , info => $reg32_href   }, | 
 |     	{ name => 'xmm0'	, info => $reg128_href  }, | 
 |     	{ name => 'xmm1'    , info => $reg128_href  }, | 
 |     	{ name => 'xmm2'    , info => $reg128_href  }, | 
 |     	{ name => 'xmm3'    , info => $reg128_href  }, | 
 |     	{ name => 'xmm4'    , info => $reg128_href  }, | 
 |     	{ name => 'xmm5'    , info => $reg128_href  }, | 
 |     	{ name => 'xmm6'    , info => $reg128_href  }, | 
 |     	{ name => 'xmm7'    , info => $reg128_href  }, | 
 |     	{ name => 'xmm8'    , info => $reg128_href  }, | 
 |     	{ name => 'xmm9'    , info => $reg128_href  }, | 
 |     	{ name => 'xmm10'   , info => $reg128_href  }, | 
 |     	{ name => 'xmm11'   , info => $reg128_href  }, | 
 |     	{ name => 'xmm12'   , info => $reg128_href  }, | 
 |     	{ name => 'xmm13'   , info => $reg128_href  }, | 
 |     	{ name => 'xmm14'   , info => $reg128_href  }, | 
 |     	{ name => 'xmm15'   , info => $reg128_href	}, | 
 |     	{ name => 'mxcsr'   , info => $reg32_href	}, | 
 |     ], | 
 |  | 
 |     'x86_64-lldb' => [ | 
 |         { name => 'rax'		    , info => $reg64_href   }, | 
 |         { name => 'rbx'		    , info => $reg64_href   }, | 
 |         { name => 'rcx'		    , info => $reg64_href   }, | 
 |         { name => 'rdx'		    , info => $reg64_href   }, | 
 |         { name => 'rdi'		    , info => $reg64_href   }, | 
 |         { name => 'rsi'		    , info => $reg64_href   }, | 
 |         { name => 'rbp'		    , info => $reg64_href   }, | 
 |         { name => 'rsp'		    , info => $reg64_href   }, | 
 |         { name => 'r8 '		    , info => $reg64_href   }, | 
 |         { name => 'r9 '		    , info => $reg64_href   }, | 
 |         { name => 'r10'		    , info => $reg64_href   }, | 
 |         { name => 'r11'		    , info => $reg64_href   }, | 
 |         { name => 'r12'		    , info => $reg64_href   }, | 
 |         { name => 'r13'		    , info => $reg64_href   }, | 
 |         { name => 'r14'		    , info => $reg64_href   }, | 
 |         { name => 'r15'		    , info => $reg64_href   }, | 
 |         { name => 'rip'		    , info => $reg64_href   }, | 
 |         { name => 'rflags'	    , info => $reg64_href   }, | 
 |         { name => 'cs'		    , info => $reg64_href   }, | 
 |         { name => 'fs'		    , info => $reg64_href   }, | 
 |         { name => 'gs'		    , info => $reg64_href   }, | 
 |         { name => 'fctrl'       , info => $reg16_href   }, | 
 |         { name => 'fstat'       , info => $reg16_href   }, | 
 |         { name => 'ftag'        , info => $reg8_href    }, | 
 |         { name => 'fop'         , info => $reg16_href   }, | 
 |         { name => 'fioff'       , info => $reg32_href   }, | 
 |         { name => 'fiseg'       , info => $reg16_href   }, | 
 |         { name => 'fooff'       , info => $reg32_href   }, | 
 |         { name => 'foseg'       , info => $reg16_href   }, | 
 |         { name => 'mxcsr'       , info => $reg32_href   }, | 
 |         { name => 'mxcsrmask'   , info => $reg32_href   }, | 
 |         { name => 'stmm0'       , info => $reg80_href   }, | 
 |         { name => 'stmm1'       , info => $reg80_href   }, | 
 |         { name => 'stmm2'       , info => $reg80_href   }, | 
 |         { name => 'stmm3'       , info => $reg80_href   }, | 
 |         { name => 'stmm4'       , info => $reg80_href   }, | 
 |         { name => 'stmm5'       , info => $reg80_href   }, | 
 |         { name => 'stmm6'       , info => $reg80_href   }, | 
 |         { name => 'stmm7'       , info => $reg80_href   }, | 
 |         { name => 'xmm0'	    , info => $reg128_href  }, | 
 |         { name => 'xmm1'	    , info => $reg128_href  }, | 
 |         { name => 'xmm2'	    , info => $reg128_href  }, | 
 |         { name => 'xmm3'	    , info => $reg128_href  }, | 
 |         { name => 'xmm4'	    , info => $reg128_href  }, | 
 |         { name => 'xmm5'	    , info => $reg128_href  }, | 
 |         { name => 'xmm6'	    , info => $reg128_href  }, | 
 |         { name => 'xmm7'	    , info => $reg128_href  }, | 
 |         { name => 'xmm8'	    , info => $reg128_href  }, | 
 |         { name => 'xmm9'	    , info => $reg128_href  }, | 
 |         { name => 'xmm10'	    , info => $reg128_href  }, | 
 |         { name => 'xmm11'	    , info => $reg128_href  }, | 
 |         { name => 'xmm12'	    , info => $reg128_href  }, | 
 |         { name => 'xmm13'	    , info => $reg128_href  }, | 
 |         { name => 'xmm14'	    , info => $reg128_href  }, | 
 |         { name => 'xmm15'	    , info => $reg128_href  }, | 
 |         { name => 'trapno'      , info => $reg32_href   }, | 
 |         { name => 'err'         , info => $reg32_href   }, | 
 |         { name => 'faultvaddr'	, info => $reg64_href   }, | 
 |     ] | 
 | ); | 
 |  | 
 | our $max_register_name_len = 0; | 
 | calculate_max_register_name_length(); | 
 | our @point_types = ( "software_bp", "hardware_bp", "write_wp", "read_wp", "access_wp" ); | 
 | our $opt_v = 0;	# verbose | 
 | our $opt_g = 0;	# debug | 
 | our $opt_q = 0;	# quiet | 
 | our $opt_r = undef; | 
 | use Getopt::Std; | 
 | getopts('gvqr:');  | 
 |  | 
 | our $registers_aref = undef; | 
 |  | 
 | if (length($opt_r)) | 
 | { | 
 | 	if (exists $reg_map{$opt_r}) | 
 | 	{ | 
 | 	    $registers_aref = $reg_map{$opt_r};		 | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		die "Can't get registers group for '$opt_r'\n"; | 
 | 	} | 
 | } | 
 |  | 
 | sub extract_key_value_pairs  | 
 | { | 
 |     my $kv_href = {}; | 
 |     my $arrayref = shift; | 
 |     my $str = join('',@$arrayref); | 
 |     my @kv_strs = split(/;/, $str); | 
 |     foreach my $kv_str (@kv_strs) | 
 |     { | 
 |         my ($key, $value) = split(/:/, $kv_str); | 
 |         $kv_href->{$key} = $value; | 
 |     } | 
 |     return $kv_href; | 
 | } | 
 |  | 
 | sub get_thread_from_thread_suffix | 
 | { | 
 |     if ($thread_suffix_supported) | 
 |     { | 
 |         my $arrayref = shift; | 
 |         # Skip leading semi-colon if needed | 
 |         $$arrayref[0] == ';' and shift @$arrayref; | 
 |         my $thread_href = extract_key_value_pairs ($arrayref); | 
 |         if (exists $thread_href->{thread}) | 
 |         { | 
 |             return $thread_href->{thread}; | 
 |         } | 
 |     } | 
 |     return undef; | 
 | } | 
 |  | 
 | sub calculate_max_register_name_length | 
 | { | 
 | 	$max_register_name_len = 7; | 
 | 	foreach my $reg_href (@$registers_aref) | 
 | 	{ | 
 | 		my $name_len = length($reg_href->{name}); | 
 | 		if ($max_register_name_len < $name_len) | 
 | 		{ | 
 | 			$max_register_name_len = $name_len;			 | 
 | 		} | 
 | 	} | 
 | } | 
 | #---------------------------------------------------------------------- | 
 | # Hash that maps command characters to the appropriate functions using | 
 | # the command character as the key and the value being a reference to | 
 | # the dump function for dumping the command itself. | 
 | #---------------------------------------------------------------------- | 
 | our %cmd_callbacks =  | 
 | ( | 
 | 	'?' => \&dump_last_signal_cmd, | 
 | 	'H' => \&dump_set_thread_cmd, | 
 | 	'T' => \&dump_thread_is_alive_cmd, | 
 | 	'q' => \&dump_general_query_cmd, | 
 | 	'Q' => \&dump_general_set_cmd, | 
 | 	'g' => \&dump_read_regs_cmd, | 
 | 	'G' => \&dump_write_regs_cmd, | 
 | 	'p' => \&dump_read_single_register_cmd, | 
 | 	'P' => \&dump_write_single_register_cmd,	 | 
 | 	'm' => \&dump_read_mem_cmd, | 
 | 	'M' => \&dump_write_mem_cmd, | 
 | 	'X' => \&dump_write_mem_binary_cmd, | 
 | 	'Z' => \&dump_bp_wp_command, | 
 | 	'z' => \&dump_bp_wp_command, | 
 | 	'k' => \&dump_kill_cmd, | 
 | 	'A' => \&dump_A_command, | 
 | 	'c' => \&dump_continue_cmd, | 
 | 	's' => \&dump_continue_cmd, | 
 | 	'C' => \&dump_continue_with_signal_cmd, | 
 | 	'S' => \&dump_continue_with_signal_cmd, | 
 | 	'_M' => \&dump_allocate_memory_cmd, | 
 | 	'_m' => \&dump_deallocate_memory_cmd, | 
 | 	# extended commands | 
 | 	'v' => \&dump_extended_cmd | 
 | ); | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Hash that maps command characters to the appropriate functions using | 
 | # the command character as the key and the value being a reference to | 
 | # the dump function for the response to the command. | 
 | #---------------------------------------------------------------------- | 
 | our %rsp_callbacks =  | 
 | ( | 
 | 	'c' => \&dump_stop_reply_packet, | 
 | 	's' => \&dump_stop_reply_packet, | 
 | 	'C' => \&dump_stop_reply_packet, | 
 | 	'?' => \&dump_stop_reply_packet, | 
 | 	'T' => \&dump_thread_is_alive_rsp, | 
 | 	'H' => \&dump_set_thread_rsp, | 
 | 	'q' => \&dump_general_query_rsp, | 
 | 	'g' => \&dump_read_regs_rsp, | 
 | 	'p' => \&dump_read_single_register_rsp, | 
 | 	'm' => \&dump_read_mem_rsp, | 
 | 	'_M' => \&dump_allocate_memory_rsp, | 
 |  | 
 | 	# extended commands | 
 | 	'v' => \&dump_extended_rsp, | 
 | ); | 
 |  | 
 |  | 
 | sub dump_register_value | 
 | { | 
 |     my $indent = shift; | 
 | 	my $arrayref = shift; | 
 | 	my $reg_num = shift; | 
 |  | 
 |     if ($reg_num >= @$registers_aref) | 
 |     { | 
 |         printf("\tinvalid register index %d\n", $reg_num); | 
 |         return; | 
 |     } | 
 |      | 
 |     my $reg_href = $$registers_aref[$reg_num]; | 
 |     my $reg_name = $reg_href->{name}; | 
 | 	if ($$arrayref[0] eq '#') | 
 | 	{ | 
 |         printf("\t%*s: error: EOS reached when trying to read register %d\n", $max_register_name_len, $reg_name, $reg_num); | 
 | 	} | 
 | 	 | 
 |     my $reg_info = $reg_href->{info}; | 
 |     my $reg_extract = $reg_info->{extract}; | 
 |     my $reg_format = $reg_info->{format}; | 
 |     my $reg_val = &$reg_extract($arrayref); | 
 |     if ($indent) { | 
 |     	printf("\t%*s = $reg_format", $max_register_name_len, $reg_name, $reg_val);         | 
 |     } else { | 
 |     	printf("%s = $reg_format", $reg_name, $reg_val);         | 
 |     } | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Extract the command into an array of ASCII char strings for easy | 
 | # processing | 
 | #---------------------------------------------------------------------- | 
 | sub extract_command | 
 | { | 
 | 	my $cmd_str = shift; | 
 | 	my @cmd_chars = split(/ */, $cmd_str); | 
 | 	if ($cmd_chars[0] ne '$') | 
 | 	{ | 
 | 		# only set the current command if it isn't a reply | 
 | 		$curr_cmd = $cmd_chars[0];  | 
 | 	} | 
 | 	return @cmd_chars; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Strip the 3 checksum array entries after we don't need them anymore | 
 | #---------------------------------------------------------------------- | 
 | sub strip_checksum | 
 | { | 
 | 	my $arrayref = shift; | 
 | 	splice(@$arrayref, -3); | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Dump all strings in array by joining them together with no space  | 
 | # between them | 
 | #---------------------------------------------------------------------- | 
 | sub dump_chars | 
 | { | 
 | 	print join('',@_); | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Check if the response is an error 'EXX' | 
 | #---------------------------------------------------------------------- | 
 | sub is_error_response | 
 | { | 
 | 	if ($_[0] eq 'E') | 
 | 	{ | 
 | 		shift; | 
 | 		print "ERROR = " . join('',@_) . "\n"; | 
 | 		return 1; | 
 | 	} | 
 | 	return 0; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'H' command | 
 | #---------------------------------------------------------------------- | 
 | sub dump_set_thread_cmd | 
 | { | 
 | 	my $cmd = shift; | 
 | 	my $mod = shift; | 
 | 	print "set_thread ( $mod, " . join('',@_) . " )\n"; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'T' command | 
 | #---------------------------------------------------------------------- | 
 | our $T_cmd_tid = -1; | 
 | sub dump_thread_is_alive_cmd | 
 | { | 
 | 	my $cmd = shift; | 
 | 	$T_cmd_tid = get_hex(\@_); | 
 | 	printf("thread_is_alive ( $tid_format )\n", $T_cmd_tid); | 
 | } | 
 |  | 
 | sub dump_thread_is_alive_rsp | 
 | { | 
 | 	my $rsp = join('',@_); | 
 | 	 | 
 | 	printf("thread_is_alive ( $tid_format ) =>", $T_cmd_tid); | 
 | 	if ($rsp eq 'OK') | 
 | 	{ | 
 | 		print " alive.\n"; | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		print " dead.\n"; | 
 | 	} | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'H' response | 
 | #---------------------------------------------------------------------- | 
 | sub dump_set_thread_rsp | 
 | { | 
 | 	if (!is_error_response(@_)) | 
 | 	{ | 
 | 		print join('',@_) . "\n"; | 
 | 	} | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'q' command | 
 | #---------------------------------------------------------------------- | 
 | our $gen_query_cmd; | 
 | our $qRegisterInfo_reg_num = -1; | 
 | sub dump_general_query_cmd | 
 | { | 
 | 	$gen_query_cmd = join('',@_); | 
 | 	if ($gen_query_cmd eq 'qC') | 
 | 	{ | 
 | 		print 'get_current_pid ()'; | 
 | 	} | 
 | 	elsif ($gen_query_cmd eq 'qfThreadInfo') | 
 | 	{ | 
 | 		print 'get_first_active_threads ()'; | 
 | 	} | 
 | 	elsif ($gen_query_cmd eq 'qsThreadInfo') | 
 | 	{ | 
 | 		print 'get_subsequent_active_threads ()'; | 
 | 	} | 
 | 	elsif (index($gen_query_cmd, 'qThreadExtraInfo') == 0) | 
 | 	{ | 
 | 		# qThreadExtraInfo,id | 
 | 		print 'get_thread_extra_info ()'; | 
 | 	} | 
 | 	elsif (index($gen_query_cmd, 'qThreadStopInfo') == 0) | 
 | 	{ | 
 | 		# qThreadStopInfoXXXX | 
 | 		@_ = splice(@_, length('qThreadStopInfo')); | 
 | 		my $tid = get_addr(\@_); | 
 | 		printf('get_thread_stop_info ( thread = 0x%4.4x )', $tid); | 
 | 	} | 
 | 	elsif (index($gen_query_cmd, 'qSymbol:') == 0) | 
 | 	{ | 
 | 		# qCRC:addr,length | 
 | 		print 'gdb_ready_to_serve_symbol_lookups ()'; | 
 | 	} | 
 | 	elsif (index($gen_query_cmd, 'qCRC:') == 0) | 
 | 	{ | 
 | 		# qCRC:addr,length | 
 | 		@_ = splice(@_, length('qCRC:')); | 
 | 		my $address = get_addr(\@_); | 
 | 		shift @_; | 
 | 		my $length = join('', @_); | 
 | 		printf("compute_crc (addr = $addr_format, length = $length)", $address); | 
 | 	} | 
 | 	elsif (index($gen_query_cmd, 'qGetTLSAddr:') == 0) | 
 | 	{ | 
 | 		# qGetTLSAddr:thread-id,offset,lm | 
 | 		@_ = splice(@_, length('qGetTLSAddr:')); | 
 | 		my ($tid, $offset, $lm) = split (/,/, join('', @_)); | 
 | 		print "get_thread_local_storage_addr (thread-id = $tid, offset = $offset, lm = $lm)"; | 
 | 	} | 
 | 	elsif ($gen_query_cmd eq 'qOffsets') | 
 | 	{ | 
 | 		print 'get_section_offsets ()'; | 
 | 	} | 
 | 	elsif (index($gen_query_cmd, 'qRegisterInfo') == 0) | 
 | 	{ | 
 | 		@_ = splice(@_, length('qRegisterInfo')); | 
 | 		$qRegisterInfo_reg_num = get_hex(\@_); | 
 | 		 | 
 | 		printf "get_dynamic_register_info ($qRegisterInfo_reg_num)"; | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		print $gen_query_cmd; | 
 | 	} | 
 | 	print "\n"; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'q' response | 
 | #---------------------------------------------------------------------- | 
 | sub dump_general_query_rsp | 
 | { | 
 | 	my $gen_query_rsp = join('',@_); | 
 | 	my $gen_query_rsp_len = length ($gen_query_rsp); | 
 | 	if ($gen_query_cmd eq 'qC' and index($gen_query_rsp, 'QC') == 0) | 
 | 	{ | 
 | 		shift @_; shift @_; | 
 | 		my $pid = get_hex(\@_); | 
 | 		printf("pid = $pid_format\n", $pid); | 
 | 		return; | 
 | 	} | 
 | 	elsif (index($gen_query_cmd, 'qRegisterInfo') == 0) | 
 | 	{ | 
 | 		if ($gen_query_rsp_len == 0) | 
 | 		{ | 
 | 			print "$unimplemented_str\n";			 | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			if (index($gen_query_rsp, 'name') == 0) | 
 | 			{ | 
 | 				$qRegisterInfo_reg_num == 0 and $registers_aref = []; | 
 |  | 
 | 				my @name_and_values = split (/;/, $gen_query_rsp); | 
 | 			 | 
 | 				my $reg_name = undef; | 
 | 				my $byte_size = 0; | 
 | 				my $pseudo = 0; | 
 | 				foreach (@name_and_values) | 
 | 				{ | 
 | 					my ($name, $value) = split /:/;				 | 
 | 					if    ($name eq "name") { $reg_name = $value; } | 
 | 					elsif ($name eq "bitsize") { $byte_size = $value / 8; } | 
 | 					elsif ($name eq "container-regs") { $pseudo = 1; } | 
 | 				} | 
 | 				if (defined $reg_name and $byte_size > 0) | 
 | 				{ | 
 | 					if    ($byte_size == 4)  {push @$registers_aref, { name => $reg_name, info => $reg32_href   , pseudo => $pseudo };} | 
 | 					elsif ($byte_size == 8)  {push @$registers_aref, { name => $reg_name, info => $reg64_href   , pseudo => $pseudo };} | 
 | 					elsif ($byte_size == 1)  {push @$registers_aref, { name => $reg_name, info => $reg8_href    , pseudo => $pseudo };} | 
 | 					elsif ($byte_size == 2)  {push @$registers_aref, { name => $reg_name, info => $reg16_href   , pseudo => $pseudo };} | 
 | 					elsif ($byte_size == 10) {push @$registers_aref, { name => $reg_name, info => $reg80_href   , pseudo => $pseudo };} | 
 | 					elsif ($byte_size == 12) {push @$registers_aref, { name => $reg_name, info => $float96_href , pseudo => $pseudo };} | 
 | 					elsif ($byte_size == 16) {push @$registers_aref, { name => $reg_name, info => $reg128_href  , pseudo => $pseudo };} | 
 | 					elsif ($byte_size == 32) {push @$registers_aref, { name => $reg_name, info => $reg256_href  , pseudo => $pseudo };} | 
 | 				} | 
 | 			} | 
 | 			elsif ($gen_query_rsp_len == 3 and index($gen_query_rsp, 'E') == 0) | 
 | 			{ | 
 | 				calculate_max_register_name_length(); | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	elsif ($gen_query_cmd =~ 'qThreadStopInfo') | 
 | 	{ | 
 | 		dump_stop_reply_packet (@_); | 
 | 	} | 
 | 	if (dump_standard_response(\@_)) | 
 | 	{ | 
 | 		# Do nothing... | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		print join('',@_) . "\n"; | 
 | 	} | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'Q' command | 
 | #---------------------------------------------------------------------- | 
 | our $gen_set_cmd; | 
 | sub dump_general_set_cmd | 
 | { | 
 | 	$gen_query_cmd = join('',@_); | 
 | 	if ($gen_query_cmd eq 'QStartNoAckMode') | 
 | 	{ | 
 | 		print "StartNoAckMode ()" | 
 | 	} | 
 | 	elsif ($gen_query_cmd eq 'QThreadSuffixSupported') | 
 | 	{ | 
 | 	    $thread_suffix_supported = 1; | 
 | 		print "ThreadSuffixSupported ()" | 
 | 	} | 
 | 	elsif (index($gen_query_cmd, 'QSetMaxPayloadSize:') == 0) | 
 | 	{ | 
 | 		@_ = splice(@_, length('QSetMaxPayloadSize:')); | 
 | 		my $max_payload_size = get_hex(\@_); | 
 | 		# QSetMaxPayloadSize:XXXX  where XXXX is a hex length of the max | 
 | 		# packet payload size supported by gdb | 
 | 		printf("SetMaxPayloadSize ( 0x%x (%u))", $max_payload_size, $max_payload_size); | 
 | 	} | 
 | 	elsif (index ($gen_query_cmd, 'QSetSTDIN:') == 0) | 
 | 	{ | 
 | 		@_ = splice(@_, length('QSetSTDIN:')); | 
 | 		printf ("SetSTDIN (path ='%s')\n", get_hex_string (\@_)); | 
 | 	} | 
 | 	elsif (index ($gen_query_cmd, 'QSetSTDOUT:') == 0) | 
 | 	{ | 
 | 		@_ = splice(@_, length('QSetSTDOUT:')); | 
 | 		printf ("SetSTDOUT (path ='%s')\n", get_hex_string (\@_)); | 
 | 	} | 
 | 	elsif (index ($gen_query_cmd, 'QSetSTDERR:') == 0) | 
 | 	{ | 
 | 		@_ = splice(@_, length('QSetSTDERR:')); | 
 | 		printf ("SetSTDERR (path ='%s')\n", get_hex_string (\@_)); | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		print $gen_query_cmd; | 
 | 	} | 
 | 	print "\n"; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'k' command | 
 | #---------------------------------------------------------------------- | 
 | sub dump_kill_cmd | 
 | { | 
 | 	my $cmd = shift; | 
 | 	print "kill (" . join('',@_) . ")\n"; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'g' command | 
 | #---------------------------------------------------------------------- | 
 | sub dump_read_regs_cmd | 
 | { | 
 | 	my $cmd = shift; | 
 | 	print "read_registers ()\n"; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'G' command | 
 | #---------------------------------------------------------------------- | 
 | sub dump_write_regs_cmd | 
 | { | 
 | 	print "write_registers:\n"; | 
 | 	my $cmd = shift; | 
 |     foreach my $reg_href (@$registers_aref) | 
 |     { | 
 | 		last if ($_[0] eq '#'); | 
 | 		if ($reg_href->{pseudo} == 0) | 
 | 		{ | 
 |             my $reg_info_href = $reg_href->{info}; | 
 |             my $reg_name = $reg_href->{name}; | 
 |             my $reg_extract = $reg_info_href->{extract}; | 
 |             my $reg_format = $reg_info_href->{format}; | 
 |             my $reg_val = &$reg_extract(\@_); | 
 |     		printf("\t%*s = $reg_format\n", $max_register_name_len, $reg_name, $reg_val);		     | 
 | 		} | 
 | 	}			 | 
 | } | 
 |  | 
 | sub dump_read_regs_rsp | 
 | { | 
 | 	print "read_registers () =>\n"; | 
 | 	if (!is_error_response(@_)) | 
 | 	{ | 
 | 	#	print join('',@_) . "\n"; | 
 | 	    foreach my $reg_href (@$registers_aref) | 
 | 	    { | 
 | 			last if ($_[0] eq '#'); | 
 |     		if ($reg_href->{pseudo} == 0) | 
 |     		{ | 
 |     	        my $reg_info_href = $reg_href->{info}; | 
 |     	        my $reg_name = $reg_href->{name}; | 
 |     	        my $reg_extract = $reg_info_href->{extract}; | 
 |                 my $reg_format = $reg_info_href->{format}; | 
 |                 my $reg_val = &$reg_extract(\@_); | 
 |     			printf("\t%*s = $reg_format\n", $max_register_name_len, $reg_name, $reg_val); | 
 | 			} | 
 | 		}			 | 
 | 	} | 
 | } | 
 |  | 
 | sub dump_read_single_register_rsp | 
 | { | 
 |     dump_register_value(0, \@_, $reg_cmd_reg); | 
 |     print "\n"; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # '_M' - allocate memory command (LLDB extension) | 
 | # | 
 | #   Command: '_M' | 
 | #      Arg1: Hex byte size as big endian hex string | 
 | # Separator: ',' | 
 | #      Arg2: permissions as string that must be a string that contains any | 
 | #            combination of 'r' (readable) 'w' (writable) or 'x' (executable) | 
 | # | 
 | #   Returns: The address that was allocated as a big endian hex string | 
 | #            on success, else an error "EXX" where XX are hex bytes | 
 | #            that indicate an error code. | 
 | # | 
 | # Examples: | 
 | #   _M10,rw     # allocate 16 bytes with read + write permissions | 
 | #   _M100,rx    # allocate 256 bytes with read + execute permissions | 
 | #---------------------------------------------------------------------- | 
 | sub dump_allocate_memory_cmd | 
 | { | 
 | 	shift; shift; # shift off the '_' and the 'M' | 
 | 	my $byte_size = get_addr(\@_); | 
 | 	shift;	# Skip ',' | 
 | 	printf("allocate_memory ( byte_size = %u (0x%x), permissions = %s)\n", $byte_size, $byte_size, join('',@_)); | 
 | } | 
 |  | 
 | sub dump_allocate_memory_rsp | 
 | { | 
 |     if (@_ == 3 and $_[0] == 'E') | 
 |     { | 
 | 	    printf("allocated memory addr = ERROR (%s))\n", join('',@_));         | 
 |     } | 
 |     else | 
 |     { | 
 | 	    printf("allocated memory addr = 0x%s\n", join('',@_));         | 
 |     } | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # '_m' - deallocate memory command (LLDB extension) | 
 | # | 
 | #   Command: '_m' | 
 | #      Arg1: Hex address as big endian hex string | 
 | # | 
 | #   Returns: "OK" on success "EXX" on error | 
 | # | 
 | # Examples: | 
 | #   _m201000    # Free previously allocated memory at address 0x201000 | 
 | #---------------------------------------------------------------------- | 
 | sub dump_deallocate_memory_cmd | 
 | { | 
 | 	shift; shift; # shift off the '_' and the 'm' | 
 | 	printf("deallocate_memory ( addr =  0x%s)\n", join('',@_)); | 
 | } | 
 |  | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'p' command | 
 | #---------------------------------------------------------------------- | 
 | sub dump_read_single_register_cmd | 
 | { | 
 | 	my $cmd = shift; | 
 | 	$reg_cmd_reg = get_hex(\@_); | 
 | 	my $thread = get_thread_from_thread_suffix (\@_); | 
 | 	my $reg_href = $$registers_aref[$reg_cmd_reg]; | 
 |    | 
 | 	if (defined $thread) | 
 | 	{ | 
 |     	print "read_register ( reg = \"$reg_href->{name}\", thread = $thread )\n"; | 
 | 	} | 
 | 	else | 
 | 	{ | 
 |     	print "read_register ( reg = \"$reg_href->{name}\" )\n"; | 
 | 	} | 
 | } | 
 |  | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'P' command | 
 | #---------------------------------------------------------------------- | 
 | sub dump_write_single_register_cmd | 
 | { | 
 | 	my $cmd = shift; | 
 | 	my $reg_num = get_hex(\@_); | 
 | 	shift (@_);	# Discard the '=' | 
 | 	 | 
 | 	print "write_register ( "; | 
 | 	dump_register_value(0, \@_, $reg_num); | 
 | 	my $thread = get_thread_from_thread_suffix (\@_); | 
 | 	if (defined $thread) | 
 | 	{ | 
 | 	    print ", thread = $thread"; | 
 | 	} | 
 | 	print " )\n"; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'm' command | 
 | #---------------------------------------------------------------------- | 
 | our $read_mem_address = 0; | 
 | sub dump_read_mem_cmd | 
 | { | 
 | 	my $cmd = shift; | 
 | 	$read_mem_address = get_addr(\@_); | 
 | 	shift;	# Skip ',' | 
 | 	printf("read_mem ( $addr_format, %s )\n", $read_mem_address, join('',@_)); | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'm' response | 
 | #---------------------------------------------------------------------- | 
 | sub dump_read_mem_rsp | 
 | { | 
 | 	# If the memory read was 2 or 4 bytes, print it out in native format | 
 | 	# instead of just as bytes. | 
 | 	my $num_nibbles = @_; | 
 | 	if ($num_nibbles == 2) | 
 | 	{ | 
 | 		printf(" 0x%2.2x", get8(\@_)); | 
 | 	} | 
 | 	elsif ($num_nibbles == 4) | 
 | 	{ | 
 | 		printf(" 0x%4.4x", get16(\@_)); | 
 | 	} | 
 | 	elsif ($num_nibbles == 8) | 
 | 	{ | 
 | 		printf(" 0x%8.8x", get32(\@_)); | 
 | 	} | 
 | 	elsif ($num_nibbles == 16) | 
 | 	{ | 
 | 		printf(" 0x%s", get64(\@_)); | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		my $curr_address = $read_mem_address; | 
 | 		my $nibble; | 
 | 		my $nibble_offset = 0; | 
 | 		my $max_nibbles_per_line = 2 * $max_bytes_per_line; | 
 | 		foreach $nibble (@_) | 
 | 		{ | 
 | 			if (($nibble_offset % $max_nibbles_per_line) == 0) | 
 | 			{ | 
 | 				($nibble_offset > 0) and print "\n    "; | 
 | 				printf("$addr_format: ", $curr_address + $nibble_offset/2); | 
 | 			} | 
 | 			(($nibble_offset % 2) == 0) and print ' ';			 | 
 | 			print $nibble; | 
 | 			$nibble_offset++; | 
 | 		} | 
 | 	} | 
 | 	print "\n"; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'c' or 's' command | 
 | #---------------------------------------------------------------------- | 
 | sub dump_continue_cmd | 
 | {	 | 
 | 	my $cmd = shift; | 
 | 	my $cmd_str; | 
 | 	$cmd eq 'c' and $cmd_str = 'continue'; | 
 | 	$cmd eq 's' and $cmd_str = 'step'; | 
 | 	my $address = -1; | 
 | 	if (@_) | 
 | 	{ | 
 | 		my $address = get_addr(\@_); | 
 | 		printf("%s ($addr_format)\n", $cmd_str, $address); | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		printf("%s ()\n", $cmd_str); | 
 | 	} | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'Css' continue (C) with signal (ss where 'ss' is two hex digits) | 
 | # 'Sss' step (S) with signal (ss where 'ss' is two hex digits) | 
 | #---------------------------------------------------------------------- | 
 | sub dump_continue_with_signal_cmd | 
 | {	 | 
 | 	my $cmd = shift; | 
 | 	my $address = -1; | 
 | 	my $cmd_str; | 
 | 	$cmd eq 'c' and $cmd_str = 'continue'; | 
 | 	$cmd eq 's' and $cmd_str = 'step'; | 
 | 	my $signal = get_hex(\@_); | 
 | 	if (@_) | 
 | 	{ | 
 | 		my $address = 0; | 
 | 		if (@_ && $_[0] == ';') | 
 | 		{ | 
 | 			shift; | 
 | 		 	$address = get_addr(\@_); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if ($address != -1) | 
 | 	{ | 
 | 		printf("%s_with_signal (signal = 0x%2.2x, address = $addr_format)\n", $cmd_str, $signal, $address); | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		printf("%s_with_signal (signal = 0x%2.2x)\n", $cmd_str, $signal); | 
 | 	} | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'A' command | 
 | #---------------------------------------------------------------------- | 
 | sub dump_A_command | 
 | {	 | 
 | 	my $cmd = get_expected_char(\@_, 'A') or print "error: incorrect command letter for argument packet, expected 'A'\n"; | 
 | 	printf("set_program_arguments (\n"); | 
 | 	do | 
 | 	{ | 
 | 		my $arg_len = get_uint(\@_); | 
 | 		get_expected_char(\@_, ',') or die "error: missing comma after argument length...?\n"; | 
 | 		my $arg_idx = get_uint(\@_); | 
 | 		get_expected_char(\@_, ',') or die "error: missing comma after argument number...?\n"; | 
 | 	 | 
 | 		my $arg = ''; | 
 | 		my $num_hex8_bytes = $arg_len/2; | 
 | 		for (1 .. $num_hex8_bytes) | 
 | 		{ | 
 | 			$arg .= sprintf("%c", get8(\@_)) | 
 | 		} | 
 | 		printf("        <%3u> argv[%u] = '%s'\n", $arg_len, $arg_idx, $arg); | 
 | 		if (@_ > 0) | 
 | 		{ | 
 | 			get_expected_char(\@_, ',') or die "error: missing comma after argument argument ASCII hex bytes...?\n"; | 
 | 		}		 | 
 | 	} while (@_ > 0);	 | 
 | 	printf("    )\n"); | 
 | } | 
 |  | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'z' and 'Z' command | 
 | #---------------------------------------------------------------------- | 
 | sub dump_bp_wp_command | 
 | {	 | 
 | 	my $cmd = shift; | 
 | 	my $type = shift; | 
 | 	shift;	# Skip ',' | 
 | 	my $address = get_addr(\@_); | 
 | 	shift;	# Skip ',' | 
 | 	my $length = join('',@_); | 
 | 	if ($cmd eq 'z') | 
 | 	{ | 
 | 		printf("remove $point_types[$type]($addr_format, %d)\n", $address, $length); | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		printf("insert $point_types[$type]($addr_format, %d)\n", $address, $length);		 | 
 | 	} | 
 | } | 
 |  | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'X' command | 
 | #---------------------------------------------------------------------- | 
 | sub dump_write_mem_binary_cmd | 
 | {	 | 
 | 	my $cmd = shift; | 
 | 	my $address = get_addr(\@_); | 
 | 	shift;	# Skip ',' | 
 | 	 | 
 | 	my ($length, $binary) = split(/:/, join('',@_)); | 
 | 	printf("write_mem_binary ( $addr_format, %d, %s)\n", $address, $length, $binary); | 
 |  | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'M' command | 
 | #---------------------------------------------------------------------- | 
 | sub dump_write_mem_cmd | 
 | {	 | 
 | 	my $cmd = shift; | 
 | 	my $address = get_addr(\@_); | 
 | 	shift;	# Skip ',' | 
 | 	my ($length, $hex_bytes) = split(/:/, join('',@_)); | 
 | #	printf("write_mem ( $addr_format, %d, %s)\n", $address, $length, $hex_bytes); | 
 | 	printf("write_mem ( addr = $addr_format, len = %d (0x%x), bytes = ", $address, $length, $length); | 
 | 	splice(@_, 0, length($length)+1); | 
 |  | 
 | 	my $curr_address = $address; | 
 | 	my $nibble; | 
 | 	my $nibble_count = 0; | 
 | 	my $max_nibbles_per_line = 2 * $max_bytes_per_line; | 
 | 	foreach $nibble (@_) | 
 | 	{ | 
 | 		(($nibble_count % 2) == 0) and print ' '; | 
 | 		print $nibble; | 
 | 		$nibble_count++; | 
 | 	} | 
 |  | 
 | 	# If the memory to write is 2 or 4 bytes, print it out in native format | 
 | 	# instead of just as bytes. | 
 | 	if (@_ == 4) | 
 | 	{ | 
 | 		printf(" ( 0x%4.4x )", get16(\@_)); | 
 | 	} | 
 | 	elsif (@_ == 8) | 
 | 	{ | 
 | 		printf(" ( 0x%8.8x )", get32(\@_)); | 
 | 	} | 
 | 	print " )\n"; | 
 |  | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'v' command | 
 | #---------------------------------------------------------------------- | 
 | our $extended_rsp_callback = 0; | 
 | sub dump_extended_cmd | 
 | { | 
 | 	$extended_rsp_callback = 0; | 
 | 	if (join('', @_[0..4]) eq "vCont") | 
 | 	{ | 
 | 		dump_extended_continue_cmd(splice(@_,5)); | 
 | 	} | 
 | 	elsif (join('', @_[0..7]) eq 'vAttach;') | 
 | 	{ | 
 | 		dump_attach_command (splice(@_,8)); | 
 | 	} | 
 | 	elsif (join('', @_[0..11]) eq 'vAttachWait;') | 
 | 	{ | 
 | 		dump_attach_wait_command (splice(@_,12)); | 
 | 	} | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'v' response | 
 | #---------------------------------------------------------------------- | 
 | sub dump_extended_rsp | 
 | { | 
 | 	if ($extended_rsp_callback) | 
 | 	{ | 
 | 		&$extended_rsp_callback(@_); | 
 | 	} | 
 | 	$extended_rsp_callback = 0; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'vAttachWait' command | 
 | #---------------------------------------------------------------------- | 
 | sub dump_attach_wait_command | 
 | { | 
 | 	print "attach_wait ( "; | 
 | 	while (@_) | 
 | 	{ | 
 | 		printf("%c", get8(\@_)) | 
 | 	} | 
 | 	printf " )\n"; | 
 | 	 | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'vAttach' command | 
 | #---------------------------------------------------------------------- | 
 | sub dump_attach_command | 
 | { | 
 | 	printf("attach ( pid = %i )", get_hex(\@_)); | 
 | 	$extended_rsp_callback = \&dump_stop_reply_packet; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'vCont' command | 
 | #---------------------------------------------------------------------- | 
 | sub dump_extended_continue_cmd | 
 | { | 
 | 	print "extended_continue ( "; | 
 | 	my $cmd = shift; | 
 | 	if ($cmd eq '?') | 
 | 	{ | 
 | 		print "list supported modes )\n"; | 
 | 		$extended_rsp_callback = \&dump_extended_continue_rsp; | 
 | 	} | 
 | 	elsif  ($cmd eq ';') | 
 | 	{ | 
 | 		$extended_rsp_callback = \&dump_stop_reply_packet; | 
 | 		my $i = 0; | 
 | 		while ($#_ >= 0) | 
 | 		{ | 
 | 			if ($i > 0) | 
 | 			{ | 
 | 				print ", "; | 
 | 			} | 
 | 			my $continue_cmd = shift; | 
 | 			my $tmp; | 
 | 			if ($continue_cmd eq 'c') | 
 | 			{  | 
 | 				print "continue"; | 
 | 			} | 
 | 			elsif ($continue_cmd eq 'C')			 | 
 | 			{ | 
 | 				print "continue with signal "; | 
 | 				print shift; | 
 | 				print shift; | 
 | 			} | 
 | 			elsif ($continue_cmd eq 's')			 | 
 | 			{  | 
 | 				print "step"; | 
 | 			} | 
 | 			elsif ($continue_cmd eq 'S')			 | 
 | 			{ | 
 | 				print "step with signal "; | 
 | 				print shift; | 
 | 				print shift; | 
 | 			} | 
 |  | 
 | 			if ($_[0] eq ':') | 
 | 			{ | 
 | 				shift; # Skip ':' | 
 | 				print " for thread "; | 
 | 				while ($#_ >= 0) | 
 | 				{ | 
 | 					$tmp = shift; | 
 | 					if (length($tmp) > 0 && $tmp ne ';') { | 
 | 						print $tmp;  | 
 | 					} else {  | 
 | 						last; | 
 | 					} | 
 | 				} | 
 | 			} | 
 | 			$i++; | 
 | 		} | 
 | 		 | 
 | 		printf " )\n"; | 
 | 	} | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # 'vCont' response | 
 | #---------------------------------------------------------------------- | 
 | sub dump_extended_continue_rsp | 
 | { | 
 | 	if (scalar(@_) == 0) | 
 | 	{ | 
 | 		print "$unimplemented_str\n"; | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		print "extended_continue supports " . join('',@_) . "\n"; | 
 | 	} | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Dump the command ascii for any unknown commands | 
 | #---------------------------------------------------------------------- | 
 | sub dump_other_cmd | 
 | { | 
 | 	print "other = " . join('',@_) . "\n"; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Check to see if the response was unsupported with appropriate checksum | 
 | #---------------------------------------------------------------------- | 
 | sub rsp_is_unsupported | 
 | { | 
 | 	return join('',@_) eq "#00"; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Check to see if the response was "OK" with appropriate checksum | 
 | #---------------------------------------------------------------------- | 
 | sub rsp_is_OK | 
 | { | 
 | 	return join('',@_) eq "OK#9a"; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Dump a response for an unknown command | 
 | #---------------------------------------------------------------------- | 
 | sub dump_other_rsp | 
 | { | 
 | 	print "other = " . join('',@_) . "\n"; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Get a byte from the ascii string assuming that the 2 nibble ascii | 
 | # characters are in hex.  | 
 | # | 
 | # The argument for this function needs to be a reference to an array  | 
 | # that contains single character strings and the array will get  | 
 | # updated by shifting characters off the front of it (no leading # "0x") | 
 | #---------------------------------------------------------------------- | 
 | sub get8 | 
 | { | 
 | 	my $arrayref = shift; | 
 | 	my $val = hex(shift(@$arrayref) . shift(@$arrayref)); | 
 | 	return $val; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Get a 16 bit integer and swap if $swap global is set to a non-zero  | 
 | # value. | 
 | # | 
 | # The argument for this function needs to be a reference to an array  | 
 | # that contains single character strings and the array will get  | 
 | # updated by shifting characters off the front of it (no leading # "0x") | 
 | #---------------------------------------------------------------------- | 
 | sub get16 | 
 | { | 
 | 	my $arrayref = shift; | 
 | 	my $val = 0; | 
 | 	if ($swap) | 
 | 	{ | 
 | 		$val =	get8($arrayref) 	| | 
 | 				get8($arrayref) << 8; | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		$val =	get8($arrayref) << 8 | | 
 | 				get8($arrayref)		 ; | 
 | 	} | 
 | 	return $val; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Get a 32 bit integer and swap if $swap global is set to a non-zero  | 
 | # value. | 
 | # | 
 | # The argument for this function needs to be a reference to an array  | 
 | # that contains single character strings and the array will get  | 
 | # updated by shifting characters off the front of it (no leading # "0x") | 
 | #---------------------------------------------------------------------- | 
 | sub get32 | 
 | { | 
 | 	my $arrayref = shift; | 
 | 	my $val = 0; | 
 | 	if ($swap) | 
 | 	{ | 
 | 		$val =	get8($arrayref)       | | 
 | 				get8($arrayref) << 8  | | 
 | 				get8($arrayref) << 16 | | 
 | 				get8($arrayref) << 24 ; | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		$val =	get8($arrayref) << 24 | | 
 | 				get8($arrayref) << 16 | | 
 | 				get8($arrayref) <<  8 | | 
 | 				get8($arrayref)       ; | 
 | 	} | 
 | 	return $val; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Get a 64 bit hex value as a string | 
 | # | 
 | # The argument for this function needs to be a reference to an array  | 
 | # that contains single character strings and the array will get  | 
 | # updated by shifting characters off the front of it (no leading # "0x") | 
 | #---------------------------------------------------------------------- | 
 | sub get64 | 
 | { | 
 | 	my $arrayref = shift; | 
 | 	my $val = ''; | 
 | 	my @nibbles; | 
 | 	if ($swap) | 
 | 	{ | 
 |         push @nibbles, splice(@$arrayref, 14, 2); | 
 |         push @nibbles, splice(@$arrayref, 12, 2); | 
 |         push @nibbles, splice(@$arrayref, 10, 2); | 
 |         push @nibbles, splice(@$arrayref, 8, 2); | 
 |         push @nibbles, splice(@$arrayref, 6, 2); | 
 |         push @nibbles, splice(@$arrayref, 4, 2); | 
 |         push @nibbles, splice(@$arrayref, 2, 2); | 
 |         push @nibbles, splice(@$arrayref, 0, 2); | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 	    (@nibbles) = splice(@$arrayref, 0, ((64/8) * 2)); | 
 | 	} | 
 |     $val = join('', @nibbles);         | 
 | 	return $val; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Get a 80 bit hex value as a string | 
 | # | 
 | # The argument for this function needs to be a reference to an array  | 
 | # that contains single character strings and the array will get  | 
 | # updated by shifting characters off the front of it (no leading # "0x") | 
 | #---------------------------------------------------------------------- | 
 | sub get80 | 
 | { | 
 | 	my $arrayref = shift; | 
 | 	my $val = ''; | 
 | 	my @nibbles; | 
 | 	if ($swap) | 
 | 	{ | 
 |         push @nibbles, splice(@$arrayref, 18, 2); | 
 |         push @nibbles, splice(@$arrayref, 16, 2); | 
 |         push @nibbles, splice(@$arrayref, 14, 2); | 
 |         push @nibbles, splice(@$arrayref, 12, 2); | 
 |         push @nibbles, splice(@$arrayref, 10, 2); | 
 |         push @nibbles, splice(@$arrayref, 8, 2); | 
 |         push @nibbles, splice(@$arrayref, 6, 2); | 
 |         push @nibbles, splice(@$arrayref, 4, 2); | 
 |         push @nibbles, splice(@$arrayref, 2, 2); | 
 |         push @nibbles, splice(@$arrayref, 0, 2); | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 	    (@nibbles) = splice(@$arrayref, 0, ((80/8) * 2)); | 
 | 	} | 
 |     $val = join('', @nibbles);         | 
 | 	return $val; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Get a 96 bit hex value as a string | 
 | # | 
 | # The argument for this function needs to be a reference to an array  | 
 | # that contains single character strings and the array will get  | 
 | # updated by shifting characters off the front of it (no leading # "0x") | 
 | #---------------------------------------------------------------------- | 
 | sub get96 | 
 | { | 
 | 	my $arrayref = shift; | 
 | 	my $val = ''; | 
 | 	my @nibbles; | 
 | 	if ($swap) | 
 | 	{ | 
 |         push @nibbles, splice(@$arrayref, 22, 2); | 
 |         push @nibbles, splice(@$arrayref, 20, 2); | 
 |         push @nibbles, splice(@$arrayref, 18, 2); | 
 |         push @nibbles, splice(@$arrayref, 16, 2); | 
 |         push @nibbles, splice(@$arrayref, 14, 2); | 
 |         push @nibbles, splice(@$arrayref, 12, 2); | 
 |         push @nibbles, splice(@$arrayref, 10, 2); | 
 |         push @nibbles, splice(@$arrayref, 8, 2); | 
 |         push @nibbles, splice(@$arrayref, 6, 2); | 
 |         push @nibbles, splice(@$arrayref, 4, 2); | 
 |         push @nibbles, splice(@$arrayref, 2, 2); | 
 |         push @nibbles, splice(@$arrayref, 0, 2); | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 	    (@nibbles) = splice(@$arrayref, 0, ((96/8) * 2)); | 
 | 	} | 
 |     $val = join('', @nibbles);         | 
 | 	return $val; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Get a 128 bit hex value as a string | 
 | # | 
 | # The argument for this function needs to be a reference to an array  | 
 | # that contains single character strings and the array will get  | 
 | # updated by shifting characters off the front of it (no leading # "0x") | 
 | #---------------------------------------------------------------------- | 
 | sub get128 | 
 | { | 
 | 	my $arrayref = shift; | 
 | 	my $val = ''; | 
 | 	my @nibbles; | 
 | 	if ($swap) | 
 | 	{ | 
 |         push @nibbles, splice(@$arrayref, 30, 2); | 
 |         push @nibbles, splice(@$arrayref, 28, 2); | 
 |         push @nibbles, splice(@$arrayref, 26, 2); | 
 |         push @nibbles, splice(@$arrayref, 24, 2); | 
 |         push @nibbles, splice(@$arrayref, 22, 2); | 
 |         push @nibbles, splice(@$arrayref, 20, 2); | 
 |         push @nibbles, splice(@$arrayref, 18, 2); | 
 |         push @nibbles, splice(@$arrayref, 16, 2); | 
 |         push @nibbles, splice(@$arrayref, 14, 2); | 
 |         push @nibbles, splice(@$arrayref, 12, 2); | 
 |         push @nibbles, splice(@$arrayref, 10, 2); | 
 |         push @nibbles, splice(@$arrayref, 8, 2); | 
 |         push @nibbles, splice(@$arrayref, 6, 2); | 
 |         push @nibbles, splice(@$arrayref, 4, 2); | 
 |         push @nibbles, splice(@$arrayref, 2, 2); | 
 |         push @nibbles, splice(@$arrayref, 0, 2); | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 	    (@nibbles) = splice(@$arrayref, 0, ((128/8) * 2)); | 
 | 	} | 
 |     $val = join('', @nibbles);         | 
 | 	return $val; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Get a 256 bit hex value as a string | 
 | # | 
 | # The argument for this function needs to be a reference to an array  | 
 | # that contains single character strings and the array will get  | 
 | # updated by shifting characters off the front of it (no leading # "0x") | 
 | #---------------------------------------------------------------------- | 
 | sub get256 | 
 | { | 
 | 	my $arrayref = shift; | 
 | 	my $val = ''; | 
 | 	my @nibbles; | 
 | 	if ($swap) | 
 | 	{ | 
 |         push @nibbles, splice(@$arrayref, 62, 2); | 
 |         push @nibbles, splice(@$arrayref, 60, 2); | 
 |         push @nibbles, splice(@$arrayref, 58, 2); | 
 |         push @nibbles, splice(@$arrayref, 56, 2); | 
 |         push @nibbles, splice(@$arrayref, 54, 2); | 
 |         push @nibbles, splice(@$arrayref, 52, 2); | 
 |         push @nibbles, splice(@$arrayref, 50, 2); | 
 |         push @nibbles, splice(@$arrayref, 48, 2); | 
 |         push @nibbles, splice(@$arrayref, 46, 2); | 
 |         push @nibbles, splice(@$arrayref, 44, 2); | 
 |         push @nibbles, splice(@$arrayref, 42, 2); | 
 |         push @nibbles, splice(@$arrayref, 40, 2); | 
 |         push @nibbles, splice(@$arrayref, 38, 2); | 
 |         push @nibbles, splice(@$arrayref, 36, 2); | 
 |         push @nibbles, splice(@$arrayref, 34, 2); | 
 |         push @nibbles, splice(@$arrayref, 32, 2); | 
 |         push @nibbles, splice(@$arrayref, 30, 2); | 
 |         push @nibbles, splice(@$arrayref, 28, 2); | 
 |         push @nibbles, splice(@$arrayref, 26, 2); | 
 |         push @nibbles, splice(@$arrayref, 24, 2); | 
 |         push @nibbles, splice(@$arrayref, 22, 2); | 
 |         push @nibbles, splice(@$arrayref, 20, 2); | 
 |         push @nibbles, splice(@$arrayref, 18, 2); | 
 |         push @nibbles, splice(@$arrayref, 16, 2); | 
 |         push @nibbles, splice(@$arrayref, 14, 2); | 
 |         push @nibbles, splice(@$arrayref, 12, 2); | 
 |         push @nibbles, splice(@$arrayref, 10, 2); | 
 |         push @nibbles, splice(@$arrayref, 8, 2); | 
 |         push @nibbles, splice(@$arrayref, 6, 2); | 
 |         push @nibbles, splice(@$arrayref, 4, 2); | 
 |         push @nibbles, splice(@$arrayref, 2, 2); | 
 |         push @nibbles, splice(@$arrayref, 0, 2); | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 	    (@nibbles) = splice(@$arrayref, 0, ((256/8) * 2)); | 
 | 	} | 
 |     $val = join('', @nibbles);         | 
 | 	return $val; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Get an unsigned integer value by grabbing items off the front of  | 
 | # the array stopping when a non-digit char string is encountered. | 
 | # | 
 | # The argument for this function needs to be a reference to an array  | 
 | # that contains single character strings and the array will get  | 
 | # updated by shifting characters off the front of it | 
 | #---------------------------------------------------------------------- | 
 | sub get_uint | 
 | { | 
 | 	my $arrayref = shift; | 
 | 	@$arrayref == 0 and return 0; | 
 | 	my $val = 0; | 
 | 	while ($$arrayref[0] =~ /[0-9]/) | 
 | 	{ | 
 | 		$val = $val * 10 + int(shift(@$arrayref)); | 
 | 	} | 
 | 	return $val; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Check the first character in the array and if it matches the expected | 
 | # character, return that character, else return undef; | 
 | # | 
 | # The argument for this function needs to be a reference to an array  | 
 | # that contains single character strings and the array will get  | 
 | # updated by shifting characters off the front of it. If the expected | 
 | # character doesn't match, it won't touch the array. If the first | 
 | # character does match, it will shift it off and return it. | 
 | #---------------------------------------------------------------------- | 
 | sub get_expected_char | 
 | { | 
 | 	my $arrayref = shift; | 
 | 	my $expected_char = shift; | 
 | 	if ($expected_char eq $$arrayref[0]) | 
 | 	{ | 
 | 		return shift(@$arrayref); | 
 | 	} | 
 | 	return undef; | 
 | } | 
 | #---------------------------------------------------------------------- | 
 | # Get a hex value by grabbing items off the front of the array and  | 
 | # stopping when a non-hex char string is encountered. | 
 | # | 
 | # The argument for this function needs to be a reference to an array  | 
 | # that contains single character strings and the array will get  | 
 | # updated by shifting characters off the front of it (no leading # "0x") | 
 | #---------------------------------------------------------------------- | 
 | sub get_hex | 
 | { | 
 | 	my $arrayref = shift; | 
 | 	my $my_swap = @_ ? shift : 0; | 
 | 	my $shift = 0; | 
 | 	my $val = 0; | 
 | 	while ($$arrayref[0] =~ /[0-9a-fA-F]/) | 
 | 	{ | 
 | 		if ($my_swap) | 
 | 		{ | 
 | 			my $byte = hex(shift(@$arrayref)) << 4 | hex(shift(@$arrayref)); | 
 | 			$val |= $byte << $shift; | 
 | 			$shift += 8; | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			$val <<= 4; | 
 | 			$val |= hex(shift(@$arrayref)); | 
 | 		} | 
 | 	} | 
 | 	return $val; | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Get an address value by grabbing items off the front of the array. | 
 | # | 
 | # The argument for this function needs to be a reference to an array  | 
 | # that contains single character strings and the array will get  | 
 | # updated by shifting characters off the front of it (no leading # "0x") | 
 | #---------------------------------------------------------------------- | 
 | sub get_addr | 
 | { | 
 | 	get_hex(shift); | 
 | } | 
 |  | 
 | sub get_hex_string | 
 | { | 
 | 	my $arrayref = shift; | 
 | 	my $str = ''; | 
 | 	while ($$arrayref[0] =~ /[0-9a-fA-F]/ and $$arrayref[1] =~ /[0-9a-fA-F]/) | 
 | 	{ | 
 | 		my $hi_nibble = hex(shift(@$arrayref)); | 
 | 		my $lo_nibble = hex(shift(@$arrayref)); | 
 | 		my $byte = ($hi_nibble << 4) | $lo_nibble; | 
 | 		$str .= chr($byte); | 
 | 	} | 
 | 	return $str; | 
 | } | 
 |  | 
 | sub dump_stop_reply_data | 
 | { | 
 |     while ($#_ >= 0) | 
 | 	{ | 
 | 		last unless ($_[0] ne '#'); | 
 | 		 | 
 | 	 | 
 | 		my $key = ''; | 
 | 		my $value = ''; | 
 | 		my $comment = ''; | 
 |         if ($_[0] =~ /[0-9a-fA-F]/ && $_[1] =~ /[0-9a-fA-F]/) | 
 |     	{ | 
 |     		my $reg_num = get8(\@_); | 
 |     		shift(@_);	# Skip ':' | 
 |     		if (defined ($registers_aref) && $reg_num < @$registers_aref) | 
 |     		{ | 
 |                 dump_register_value(1, \@_, $reg_num); | 
 |                 print "\n"; | 
 |         		shift(@_);	# Skip ';' | 
 |         		next; | 
 |     		} | 
 |     		$key = sprintf("reg %u", $reg_num); | 
 |     	} | 
 |     	my $char; | 
 |     	 | 
 |     	if (length($key) == 0) | 
 |     	{ | 
 |     		while (1) | 
 |     		{ | 
 |     			$char = shift(@_); | 
 |     			if (length($char) == 0 or $char eq ':' or $char eq '#') { last; } | 
 |     			$key .= $char; | 
 |     		} | 
 |     	} | 
 |     	 | 
 | 		while (1) | 
 | 		{ | 
 | 			$char = shift(@_); | 
 | 			if (length($char) == 0 or $char eq ';' or $char eq '#') { last; } | 
 | 			$value .= $char; | 
 | 		} | 
 | 		if ($key eq 'metype') | 
 | 		{ | 
 | 		    our %metype_to_name = ( | 
 | 		        '1' => ' (EXC_BAD_ACCESS)', | 
 |                 '2' => ' (EXC_BAD_INSTRUCTION)', | 
 |                 '3' => ' (EXC_ARITHMETIC)', | 
 |                 '4' => ' (EXC_EMULATION)', | 
 |                 '5' => ' (EXC_SOFTWARE)', | 
 |                 '6' => ' (EXC_BREAKPOINT)', | 
 |                 '7' => ' (EXC_SYSCALL)', | 
 |                 '8' => ' (EXC_MACH_SYSCALL)', | 
 |                 '9' => ' (EXC_RPC_ALERT)', | 
 |                 '10' => ' (EXC_CRASH)' | 
 |             ); | 
 |             if (exists $metype_to_name{$value}) | 
 |             { | 
 |                 $comment = $metype_to_name{$value}; | 
 |             } | 
 | 		} | 
 | 		printf("\t%*s = %s$comment\n", $max_register_name_len, $key, $value); | 
 | 	} | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Dumps a Stop Reply Packet which happens in response to a step,  | 
 | # continue, last signal, and probably a few other commands. | 
 | #---------------------------------------------------------------------- | 
 | sub dump_stop_reply_packet | 
 | { | 
 | 	my $what = shift(@_); | 
 | 	if ($what eq 'S' or $what eq 'T') | 
 | 	{ | 
 | 	    my $signo = get8(\@_); | 
 | 	     | 
 | 	    our %signo_to_name = ( | 
 |                 '1'  => ' SIGHUP', | 
 |                 '2'  => ' SIGINT', | 
 |                 '3'  => ' SIGQUIT', | 
 |                 '4'  => ' SIGILL', | 
 |                 '5'  => ' SIGTRAP', | 
 |                 '6'  => ' SIGABRT', | 
 |                 '7'  => ' SIGPOLL/SIGEMT', | 
 |                 '8'  => ' SIGFPE', | 
 |                 '9'  => ' SIGKILL', | 
 |                 '10' => ' SIGBUS', | 
 |                 '11' => ' SIGSEGV', | 
 |                 '12' => ' SIGSYS', | 
 |                 '13' => ' SIGPIPE', | 
 |                 '14' => ' SIGALRM', | 
 |                 '15' => ' SIGTERM', | 
 |                 '16' => ' SIGURG', | 
 |                 '17' => ' SIGSTOP', | 
 |                 '18' => ' SIGTSTP', | 
 |                 '19' => ' SIGCONT', | 
 |                 '20' => ' SIGCHLD', | 
 |                 '21' => ' SIGTTIN', | 
 |                 '22' => ' SIGTTOU', | 
 |                 '23' => ' SIGIO', | 
 |                 '24' => ' SIGXCPU', | 
 |                 '25' => ' SIGXFSZ', | 
 |                 '26' => ' SIGVTALRM', | 
 |                 '27' => ' SIGPROF', | 
 |                 '28' => ' SIGWINCH', | 
 |                 '29' => ' SIGINFO', | 
 |                 '30' => ' SIGUSR1', | 
 |                 '31' => ' SIGUSR2', | 
 |                 '145' => ' TARGET_EXC_BAD_ACCESS',        # 0x91 | 
 |                 '146' => ' TARGET_EXC_BAD_INSTRUCTION',   # 0x92 | 
 |                 '147' => ' TARGET_EXC_ARITHMETIC',        # 0x93 | 
 |                 '148' => ' TARGET_EXC_EMULATION',         # 0x94 | 
 |                 '149' => ' TARGET_EXC_SOFTWARE',          # 0x95 | 
 |                 '150' => ' TARGET_EXC_BREAKPOINT'         # 0x96 | 
 |         ); | 
 |         my $signo_str = sprintf("%i", $signo); | 
 |         my $signo_name = ''; | 
 | 	    if (exists $signo_to_name{$signo_str}) | 
 |         { | 
 |             $signo_name = $signo_to_name{$signo_str}; | 
 |         } | 
 | 		printf ("signal (signo=%u$signo_name)\n", $signo); | 
 | 		dump_stop_reply_data (@_); | 
 | 	} | 
 | 	elsif ($what eq 'W') | 
 | 	{ | 
 | 		print 'process_exited( ' . shift(@_) . shift(@_) . " )\n"; | 
 | 	} | 
 | 	elsif ($what eq 'X') | 
 | 	{ | 
 | 		print 'process_terminated( ' . shift(@_) . shift(@_) . " )\n"; | 
 | 	} | 
 | 	elsif ($what eq 'O') | 
 | 	{ | 
 | 		my $console_output = ''; | 
 | 		my $num_hex8_bytes = @_/2; | 
 | 		for (1 .. $num_hex8_bytes) | 
 | 		{ | 
 | 			$console_output .= sprintf("%c", get8(\@_)) | 
 | 		} | 
 | 		 | 
 | 		print "program_console_output('$console_output')\n"; | 
 | 	} | 
 | } | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # '?' command | 
 | #---------------------------------------------------------------------- | 
 | sub dump_last_signal_cmd | 
 | { | 
 | 	my $cmd = shift; | 
 | 	print 'last_signal (' . join('',@_) . ")\n"; | 
 | } | 
 |  | 
 | sub dump_raw_command | 
 | { | 
 | 	my $cmd_aref = shift; | 
 | 	my $callback_ref; | 
 | 	$curr_cmd = $$cmd_aref[0]; | 
 |  | 
 |     if ($curr_cmd eq 'q' or $curr_cmd eq 'Q' or $curr_cmd eq '_') | 
 |     { | 
 |         $curr_full_cmd = ''; | 
 |         foreach my $ch (@$cmd_aref) | 
 |         { | 
 |             $ch !~ /[A-Za-z_]/ and last; | 
 |             $curr_full_cmd .= $ch; | 
 |         } | 
 |     } | 
 |     else | 
 |     { | 
 |         $curr_full_cmd = $curr_cmd; | 
 |     } | 
 | 	 | 
 | 	$curr_cmd eq '_' and $curr_cmd .= $$cmd_aref[1];	 | 
 | 	$callback_ref = $cmd_callbacks{$curr_cmd}; | 
 | 	if ($callback_ref) | 
 | 	{ | 
 | 		&$callback_ref(@$cmd_aref); | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		# Strip the command byte for responses since we injected that above | 
 | 		dump_other_cmd(@$cmd_aref);  | 
 | 	} 		 | 
 | } | 
 |  | 
 | sub dump_standard_response | 
 | { | 
 | 	my $cmd_aref = shift; | 
 | 	 | 
 | 	my $cmd_len = scalar(@$cmd_aref); | 
 | 	if ($cmd_len == 0) | 
 | 	{ | 
 | 		print "$unimplemented_str\n"; | 
 | 		return 1; | 
 | 	}	 | 
 |  | 
 | 	my $response = join('', @$cmd_aref); | 
 | 	if ($response eq 'OK') | 
 | 	{ | 
 | 		print "$success_str\n"; | 
 | 		return 1; | 
 | 	} | 
 | 	 | 
 | 	if ($cmd_len == 3 and index($response, 'E') == 0) | 
 | 	{ | 
 | 		print "ERROR: " . substr($response, 1) . "\n"; | 
 | 		return 1;		 | 
 | 	} | 
 | 	 | 
 | 	return 0; | 
 | } | 
 | sub dump_raw_response | 
 | { | 
 | 	my $cmd_aref = shift; | 
 | 	my $callback_ref; | 
 | 	 | 
 | 	if ($packet_start_time != 0.0) | 
 | 	{ | 
 | 	    if (length($curr_full_cmd) > 0) | 
 | 	    { | 
 |             $packet_times{$curr_full_cmd} += $curr_time - $packet_start_time; | 
 | 	    } | 
 | 	    else | 
 | 	    { | 
 |             $packet_times{$curr_cmd} += $curr_time - $packet_start_time; | 
 | 	    } | 
 |         $packet_start_time = 0.0; | 
 | 	} | 
 | 	 | 
 | 	$callback_ref = $rsp_callbacks{$curr_cmd}; | 
 |  | 
 | 	if ($callback_ref) | 
 | 	{ | 
 | 		&$callback_ref(@$cmd_aref); | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		dump_standard_response($cmd_aref) or dump_other_rsp(@$cmd_aref); | 
 | 	} 	 | 
 | 	 | 
 | } | 
 | #---------------------------------------------------------------------- | 
 | # Dumps any command and handles simple error checking on the responses | 
 | # for commands that are unsupported or OK. | 
 | #---------------------------------------------------------------------- | 
 | sub dump_command | 
 | { | 
 | 	my $cmd_str = shift; | 
 |  | 
 | 	# Dump the original command string if verbose is on | 
 | 	if ($opt_v) | 
 | 	{ | 
 | 		print "dump_command($cmd_str)\n    "; | 
 | 	} | 
 |  | 
 | 	my @cmd_chars = extract_command($cmd_str); | 
 | 	my $is_cmd = 1; | 
 | 	 | 
 | 	my $cmd = $cmd_chars[0]; | 
 | 	if ($cmd eq '$') | 
 | 	{ | 
 | 		$is_cmd = 0;		# Note that this is a reply | 
 | 		$cmd = $curr_cmd;	# set the command byte appropriately | 
 | 		shift @cmd_chars;	# remove the '$' from the cmd bytes | 
 | 	} | 
 | 	 | 
 | 	# Check for common responses across all commands and handle them | 
 | 	# if we can | 
 | 	if ( $is_cmd == 0 ) | 
 | 	{ | 
 | 		if (rsp_is_unsupported(@cmd_chars)) | 
 | 		{ | 
 | 			print "$unimplemented_str\n"; | 
 | 			return; | 
 | 		} | 
 | 		elsif (rsp_is_OK(@cmd_chars)) | 
 | 		{ | 
 | 			print "$success_str\n"; | 
 | 			return; | 
 | 		} | 
 | 		# Strip the checksum information for responses | 
 | 		strip_checksum(\@cmd_chars); | 
 | 	} | 
 |  | 
 | 	my $callback_ref; | 
 | 	if ($is_cmd) { | 
 | 		$callback_ref = $cmd_callbacks{$cmd}; | 
 | 	} else { | 
 | 		$callback_ref = $rsp_callbacks{$cmd}; | 
 | 	} | 
 |  | 
 | 	if ($callback_ref) | 
 | 	{ | 
 | 		&$callback_ref(@cmd_chars); | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		# Strip the command byte for responses since we injected that above | 
 | 		if ($is_cmd) { | 
 | 			dump_other_cmd(@cmd_chars);  | 
 | 		} else { | 
 | 			dump_other_rsp(@cmd_chars); | 
 | 		} | 
 | 		 | 
 | 	} 	 | 
 | } | 
 |  | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | # Process a gdbserver log line by looking for getpkt and putkpt and | 
 | # tossing any other lines. | 
 |  | 
 | #---------------------------------------------------------------------- | 
 | sub process_log_line | 
 | { | 
 | 	my $line = shift; | 
 | 	#($opt_v and $opt_g) and print "# $line"; | 
 |  | 
 | 	my $extract_cmd = 0; | 
 | 	my $delta_time = 0.0; | 
 | 	if ($line =~ /^(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$/) | 
 | 	{ | 
 | 	    my $leading_space = $1; | 
 | 	    $curr_time = $2; | 
 | 	    $line = $3; | 
 | 	    if ($base_time == 0.0) | 
 | 	    { | 
 | 	        $base_time = $curr_time; | 
 | 	    } | 
 | 	    else | 
 | 	    { | 
 | 	        $delta_time = $curr_time - $last_time; | 
 | 	    } | 
 | 	    printf ("(%.6f, %+.6f): ",  $curr_time - $base_time, $delta_time); | 
 | 	    $last_time = $curr_time; | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 	    $curr_time = 0.0 | 
 | 	} | 
 |  | 
 | 	if ($line =~ /getpkt /) | 
 | 	{ | 
 | 		$extract_cmd = 1; | 
 | 		print "\n--> "; | 
 | 		$packet_start_time = $curr_time; | 
 | 	} | 
 | 	elsif ($line =~ /putpkt /) | 
 | 	{ | 
 | 		$extract_cmd = 1; | 
 | 		print "<-- "; | 
 | 	} | 
 | 	elsif ($line =~ /.*Sent:  \[[0-9]+\.[0-9]+[:0-9]*\] (.*)/) | 
 | 	{ | 
 | 		$opt_g and print "maintenance dump-packets command: $1\n"; | 
 | 		my @raw_cmd_bytes = split(/ */, $1); | 
 | 		$packet_start_time = $curr_time; | 
 | 		print "\n--> "; | 
 | 		dump_raw_command(\@raw_cmd_bytes); | 
 | 		process_log_line($2); | 
 | 	} | 
 | 	elsif ($line =~ /.*Recvd: \[[0-9]+\.[0-9]+[:0-9]*\] (.*)/) | 
 | 	{ | 
 | 		$opt_g and print "maintenance dump-packets reply: $1\n"; | 
 | 		my @raw_rsp_bytes = split(/ */, $1); | 
 | 		print "<-- "; | 
 | 		dump_raw_response(\@raw_rsp_bytes);		 | 
 | 		print "\n"; | 
 | 	} | 
 | 	elsif ($line =~ /getpkt: (.*)/) | 
 | 	{ | 
 | 		if ($1 =~ /\$([^#]+)#[0-9a-fA-F]{2}/) | 
 | 		{ | 
 | 			$opt_g and print "command: $1\n"; | 
 | 			my @raw_cmd_bytes = split(/ */, $1); | 
 | 			print "--> "; | 
 |     		$packet_start_time = $curr_time; | 
 | 			dump_raw_command(\@raw_cmd_bytes);			 | 
 | 		} | 
 | 		elsif ($1 =~ /\+/) | 
 | 		{ | 
 | 			#print "--> ACK\n"; | 
 | 		} | 
 | 		elsif ($1 =~ /-/) | 
 | 		{ | 
 | 			#print "--> NACK\n"; | 
 | 		} | 
 | 	} | 
 | 	elsif ($line =~ /putpkt: (.*)/) | 
 | 	{ | 
 | 		if ($1 =~ /\$([^#]+)#[0-9a-fA-F]{2}/) | 
 | 		{ | 
 | 			$opt_g and print "response: $1\n"; | 
 | 			my @raw_rsp_bytes = split(/ */, $1); | 
 | 			print "<-- "; | 
 | 			dump_raw_response(\@raw_rsp_bytes);		 | 
 | 			print "\n"; | 
 | 		} | 
 | 		elsif ($1 =~ /\+/) | 
 | 		{ | 
 | 			#print "<-- ACK\n"; | 
 | 		} | 
 | 		elsif ($1 =~ /-/) | 
 | 		{ | 
 | 			#print "<-- NACK\n"; | 
 | 		} | 
 | 	} | 
 | 	elsif ($line =~ /send packet: (.*)/) | 
 | 	{ | 
 | 		if ($1 =~ /\$([^#]+)#[0-9a-fA-F]{2}/) | 
 | 		{ | 
 | 			$opt_g and print "command: $1\n"; | 
 | 			my @raw_cmd_bytes = split(/ */, $1); | 
 | 			print "--> "; | 
 |     		$packet_start_time = $curr_time; | 
 | 			dump_raw_command(\@raw_cmd_bytes);			 | 
 | 		} | 
 | 		elsif ($1 =~ /\+/) | 
 | 		{ | 
 | 			#print "--> ACK\n"; | 
 | 		} | 
 | 		elsif ($1 =~ /-/) | 
 | 		{ | 
 | 			#print "--> NACK\n"; | 
 | 		} | 
 | 	} | 
 | 	elsif ($line =~ /read packet: (.*)/) | 
 | 	{ | 
 | 		if ($1 =~ /\$([^#]*)#[0-9a-fA-F]{2}/) | 
 | 		{ | 
 | 			$opt_g and print "response: $1\n"; | 
 | 			my @raw_rsp_bytes = split(/ */, $1); | 
 | 			print "<-- "; | 
 | 			dump_raw_response(\@raw_rsp_bytes);		 | 
 | 			print "\n"; | 
 | 		} | 
 | 		elsif ($1 =~ /\+/) | 
 | 		{ | 
 | 			#print "<-- ACK\n"; | 
 | 		} | 
 | 		elsif ($1 =~ /-/) | 
 | 		{ | 
 | 			#print "<-- NACK\n"; | 
 | 		} | 
 | 	} | 
 | 	elsif ($line =~ /Sending packet: \$([^#]+)#[0-9a-fA-F]{2}\.\.\.(.*)/) | 
 | 	{ | 
 | 		$opt_g and print "command: $1\n"; | 
 | 		my @raw_cmd_bytes = split(/ */, $1); | 
 | 		print "\n--> "; | 
 | 		$packet_start_time = $curr_time; | 
 | 		dump_raw_command(\@raw_cmd_bytes); | 
 | 		process_log_line($2); | 
 | 	} | 
 | 	elsif ($line =~ /Packet received: (.*)/) | 
 | 	{ | 
 | 		$opt_g and print "response: $1\n"; | 
 | 		my @raw_rsp_bytes = split(/ */, $1); | 
 | 		print "<-- "; | 
 | 		dump_raw_response(\@raw_rsp_bytes);		 | 
 | 		print "\n"; | 
 | 	} | 
 | 	 | 
 | 	if ($extract_cmd) | 
 | 	{ | 
 | 		my $beg = index($line, '("') + 2; | 
 | 		my $end = rindex($line, '");'); | 
 | 		$packet_start_time = $curr_time; | 
 | 		dump_command(substr($line, $beg, $end - $beg)); | 
 | 	} | 
 | } | 
 |  | 
 |  | 
 | our $line_num = 0; | 
 | while(<>) | 
 | { | 
 | 	$line_num++; | 
 | 	$opt_q or printf("# %5d: $_", $line_num); | 
 | 	process_log_line($_); | 
 | } | 
 |  | 
 | if (%packet_times) | 
 | { | 
 |     print "----------------------------------------------------------------------\n"; | 
 |     print "Packet timing summary:\n"; | 
 |     print "----------------------------------------------------------------------\n"; | 
 |     print "Packet                 Time       %\n"; | 
 |     print "---------------------- -------- ------\n"; | 
 |     my @packet_names = keys %packet_times; | 
 |     my $total_packet_times = 0.0; | 
 |     foreach my $key (@packet_names) | 
 |     { | 
 |         $total_packet_times += $packet_times{$key}; | 
 |     } | 
 |  | 
 |     foreach my $value (sort {$packet_times{$b} cmp $packet_times{$a}} @packet_names) | 
 |     { | 
 |         my $percent = ($packet_times{$value} / $total_packet_times) * 100.0; | 
 |         if ($percent < 10.0) | 
 |         { | 
 |             printf("%22s %1.6f   %2.2f\n", $value, $packet_times{$value}, $percent); | 
 |              | 
 |         } | 
 |         else | 
 |         { | 
 |             printf("%22s %1.6f  %2.2f\n", $value, $packet_times{$value}, $percent);             | 
 |         } | 
 |     }    | 
 |     print "---------------------- -------- ------\n"; | 
 |     printf ("                 Total %1.6f 100.00\n", $total_packet_times); | 
 | } | 
 |  | 
 |  | 
 |  | 
 |  | 
 |  | 
 |  | 
 |  |