def connect(self): """ attaches to blackmagic jtag debugger in swd mode """ # ignore redundant stuff tmp = self.readpkt(timeout=1) while(tmp): tmp = self.readpkt(timeout=1) # enable extended mode self.fetchOK('!') # setup registers TODO # registers should be parsed from the output of, see target.xml #print self.fetch('qXfer:features:read:target.xml:0,3fb') #print self.fetch('Xfer:features:read:target.xml:3cf,3fb') #print self.fetch('qXfer:memory-map:read::0,3fb') #print self.fetch('qXfer:memory-map:read::364,3fb') self.port.setup(self) addr=struct.unpack(">I", self.getreg(4, 0x0800000c))[0] - 1 self.br[format(addr, '08x')]={'sym': "FaultHandler", 'cb': self.checkfault} tmp = self.fetch('Z1,%s,2' % format(addr, 'x')) if tmp== 'OK': print "set break: @%s (0x%s)" % ('FaultHandler', format(addr, 'x')), tmp return # vector_catch enable hard int bus stat chk nocp mm reset self.send('qRcmd,766563746f725f636174636820656e61626c65206861726420696e742062757320737461742063686b206e6f6370206d6d207265736574') pkt=self.readpkt() while pkt!='OK': if pkt[0]!='O': raise ValueError('not O: %s' % pkt) if self.verbose: print unhex(pkt[1:-1]) pkt=self.readpkt()
def set_br_a(self, addr, cb, quiet=False, sym=None): """ Sets a breakpoint at address, and install callback cb for it. `addr` is a hexadecimal string as defined by RSP protocol. Also, because of this RSP implementation `addr` format should be the same as defined by `reg_fmt`. Tips: - Use `reg_fmt` attribute to get `addr` string from an integer. - Normally, an unparsed register value has the same format and can be used as is. """ if addr in self.br: print("warn: overwriting breakpoint at %s" % (sym or "0x" + addr)) br = self.br[addr] br.update(sym=sym, cb=cb) else: self.br[addr] = br = {'sym': sym, 'addr': addr, 'cb': cb} if self.z_breaks: tmp = self.fetch(b'Z0,%s,2' % addr) if tmp == b"": # Z/z packages are not supported, use code patching self.z_breaks = False br['old'] = unhex(self.fetch(b'm%s,2' % addr)) tmp = self.fetch(b'X%s,2:\xbe\xbe' % addr) else: br['old'] = unhex(self.fetch(b'm%s,2' % addr)) tmp = self.fetch(b'X%s,2:\xbe\xbe' % addr) if self.verbose and not quiet: print("set break: @%s (0x%s) %s" % (sym or "[unknown]", s(addr), s(tmp)))
def set_br_a(self, addr, cb, quiet=False, sym=None): """ Sets a breakpoint at address, and install callback cb for it. `addr` is a hexadecimal string as defined by RSP protocol. Also, because of this RSP implementation `addr` format should be the same as defined by `reg_fmt`. Tips: - Use `reg_fmt` attribute to get `addr` string from an integer. - Normally, an unparsed register value has the same format and can be used as is. """ if addr in self.br: print("warn: overwriting breakpoint at %s" % (sym or "0x" + addr)) br = self.br[addr] br.update(sym = sym, cb = cb) else: self.br[addr]= br = {'sym': sym, 'addr': addr, 'cb': cb} if self.z_breaks: tmp = self.fetch(b'Z0,%s,2' % addr) if tmp == b"": # Z/z packages are not supported, use code patching self.z_breaks = False br['old'] = unhex(self.fetch(b'm%s,2' % addr)) tmp = self.fetch(b'X%s,2:\xbe\xbe' % addr) else: br['old'] = unhex(self.fetch(b'm%s,2' % addr)) tmp = self.fetch(b'X%s,2:\xbe\xbe' % addr) if self.verbose and not quiet: print("set break: @%s (0x%s) %s" % (sym or "[unknown]", s(addr), s(tmp)))
def setup(self, rsp): rsp.send('qRcmd,737764705f7363616e') pkt = rsp.readpkt() while pkt != 'OK': if pkt[0] != 'O': raise ValueError('not O: %s' % pkt) if rsp.verbose: print unhex(pkt[1:-1]) pkt = rsp.readpkt() rsp.fetchOK('vAttach;1', 'T05')
def setup(self, rsp): rsp.send('qRcmd,737764705f7363616e') pkt=rsp.readpkt() while pkt!='OK': if pkt[0]!='O': raise ValueError('not O: %s' % pkt) if rsp.verbose: print unhex(pkt[1:-1]) pkt=rsp.readpkt() rsp.fetchOK('vAttach;1','T05')
def dump(self, size, addr = None): """ dumps data from addr if given otherwise at beginning of .text segment aka self.elf.workarea""" if addr==None: addr=self.elf.workarea rd = b'' end = addr + size bsize = int(self.feats[b'PacketSize'], 16) // 2 while addr < end: bsize = bsize if addr + bsize < end else end - addr #print('m%x,%x' % (addr, bsize)) pkt = self.fetch(b'm%x,%x' % (addr, bsize)) if len(pkt) & 1 and pkt[:1] == b'E': # There is an assumption that stub only uses 'e' for data # hexadecimal representation and 'E' is only used for errors. # However, no confirmation has been found in the protocol # definition. But, according to the protocol error message # data length is always odd (i.e. Exx). raise RuntimeError("Reading %u bytes at 0x%x failed: %s " % ( bsize, addr, s(pkt) )) rd += unhex(rsp_decode(pkt)) addr += bsize #print("%s %s pkt %s" % (addr, bsize, pkt)) return rd
def connect(self): """ attaches to blackmagic jtag debugger in swd mode """ # ignore redundant stuff tmp = self.readpkt(timeout=1) while (tmp): tmp = self.readpkt(timeout=1) # enable extended mode self.fetchOK('!') # setup registers TODO # registers should be parsed from the output of, see target.xml #print self.fetch('qXfer:features:read:target.xml:0,3fb') #print self.fetch('Xfer:features:read:target.xml:3cf,3fb') #print self.fetch('qXfer:memory-map:read::0,3fb') #print self.fetch('qXfer:memory-map:read::364,3fb') self.port.setup(self) addr = struct.unpack(">I", self.getreg(4, 0x0800000c))[0] - 1 self.br[format(addr, '08x')] = { 'sym': "FaultHandler", 'cb': self.checkfault } tmp = self.fetch('Z1,%s,2' % format(addr, 'x')) if tmp == 'OK': if self.verbose: print "set break: @%s (0x%s)" % ('FaultHandler', format(addr, 'x')), tmp return # vector_catch enable hard int bus stat chk nocp mm reset self.send( 'qRcmd,766563746f725f636174636820656e61626c65206861726420696e742062757320737461742063686b206e6f6370206d6d207265736574' ) pkt = self.readpkt() while pkt != 'OK': if pkt[0] != 'O': raise ValueError('not O: %s' % pkt) if self.verbose: print unhex(pkt[1:-1]) pkt = self.readpkt()
def connect(self, id='1'): """ attaches to blackmagic jtag debugger in swd mode """ # enable extended mode self.fetchOK('!') # setup registers TODO # registers should be parsed from the output of, see target.xml #self.fetch('qXfer:features:read:target.xml:0,3fb') #self.fetch('Xfer:features:read:target.xml:3cf,3fb') #self.fetch('qXfer:memory-map:read::0,3fb') #self.fetch('qXfer:memory-map:read::364,3fb') self.send('qRcmd,737764705f7363616e') pkt=self.readpkt() while pkt!='OK': if pkt[0]!='O': raise ValueError('not O: %s' % pkt) pkt=self.readpkt() if self.verbose: print unhex(pkt[1:-1]) self.fetchOK('vAttach;%s' % id,'T05')
def connect(self, id='1'): """ attaches to blackmagic jtag debugger in swd mode """ # enable extended mode self.fetchOK('!') # setup registers TODO # registers should be parsed from the output of, see target.xml #self.fetch('qXfer:features:read:target.xml:0,3fb') #self.fetch('Xfer:features:read:target.xml:3cf,3fb') #self.fetch('qXfer:memory-map:read::0,3fb') #self.fetch('qXfer:memory-map:read::364,3fb') self.send('qRcmd,737764705f7363616e') pkt = self.readpkt() while pkt != 'OK': if pkt[0] != 'O': raise ValueError('not O: %s' % pkt) pkt = self.readpkt() if self.verbose: print unhex(pkt[1:-1]) self.fetchOK('vAttach;%s' % id, 'T05')
def get_thread_info(self): tid = None tmp = self.fetch('qC') if tmp.startswith("QC"): tid=tmp[2:].strip() extra = unhex(self.fetch('qThreadExtraInfo,%s' % tid)) tids = [] tmp = self.fetch('qfThreadInfo') while tmp != 'l': if not tmp.startswith('m'): raise ValueError('invalid qThreadInfo response') tids.extend(tmp[1:].split(',')) tmp = self.fetch('qsThreadInfo') return (tid, extra, tids)
def get_thread_info(self): tid = None tmp = self.fetch('qC') if tmp.startswith("QC"): tid = tmp[2:].strip() extra = unhex(self.fetch('qThreadExtraInfo,%s' % tid)) tids = [] tmp = self.fetch('qfThreadInfo') while tmp != 'l': if not tmp.startswith('m'): raise ValueError('invalid qThreadInfo response') tids.extend(tmp[1:].split(',')) tmp = self.fetch('qsThreadInfo') return (tid, extra, tids)
def dump(self, size, addr=None): """ dumps data from addr if given otherwise at beginning of .text segment aka self.elf.workarea""" if addr == None: addr = self.elf.workarea rd = [] i = 0 bsize = int(self.feats['PacketSize'], 16) while (i < size): bsize = bsize if i + bsize < size else size - i self.send('m%x,%x' % (addr + i, bsize)) pkt = self.readpkt() #print pkt rd.append(unhex(pkt)) i += bsize return ''.join(rd)
def dump(self, size, addr = None): """ dumps data from addr if given otherwise at beginning of .text segment aka self.elf.workarea""" if addr==None: addr=self.elf.workarea rd = [] i=0 bsize = int(self.feats['PacketSize']) while(i<size): bsize = bsize if i+bsize<size else size - i self.send('m%x,%x' % (addr+i, bsize)) pkt=self.readpkt() #print pkt rd.append(unhex(pkt)) i+=bsize return ''.join(rd)
def dump_cb(self): """ rsp_dump callback, hit if rsp_dump is called. Outputs to stdout the source line, and a hexdump of the memory pointed by $r0 with a size of $r1 bytes. Then it resumes running. """ src_line = self.get_src_line(int(self.regs['lr'],16) - 3) if src_line: print "%s:%s %s" % (src_line['file'], src_line['lineno'], src_line['line']) res_size = int(self.regs['r1'],16) if res_size < 1024: # for sanity ptr = int(self.regs['r0'],16) res = unhex(self.fetch('m%x,%x' % (ptr, res_size))) print hexdump(res, ptr) self.step_over_br()
def dump_cb(self): """ rsp_dump callback, hit if rsp_dump is called. Outputs to stdout the source line, and a hexdump of the memory pointed by $r0 with a size of $r1 bytes. Then it resumes running. """ src_line = self.get_src_line(int(self.regs['lr'], 16) - 3) if src_line: print "%s:%s %s" % (src_line['file'], src_line['lineno'], src_line['line']) res_size = int(self.regs['r1'], 16) if res_size <= 1024: # for sanity ptr = int(self.regs['r0'], 16) res = unhex(self.fetch('m%x,%x' % (ptr, res_size))) print hexdump(res, ptr) self.step_over_br()
def set_br(self, sym, cb, quiet=False): """ sets a breakpoint at symbol sym, and install callback cb for it """ addr = self.elf.symbols.get(sym) if not addr: print "unknown symbol: %s, ignoring request to set br" % sym return addr = "%08x" % (addr & ~1) if addr in self.br: print "warn: overwriting breakpoint at %s" % sym self.br[addr] = {'sym': sym, 'cb': cb, 'old': self.br[addr]['old']} else: self.br[addr] = { 'sym': sym, 'cb': cb, 'old': unhex(self.fetch('m%s,2' % addr)) } #self.fetch('Z0,%s,2' % addr) tmp = self.fetch('X%s,2:\xbe\xbe' % addr) if self.verbose and not quiet: print "set break: @%s (0x%s)" % (sym, addr), tmp
def set_br(self, sym, cb, quiet=False): """ sets a breakpoint at symbol sym, and install callback cb for it """ addr = self.elf.symbols.get(sym) if not addr: print "unknown symbol: %s, ignoring request to set br" % sym return addr = "%08x" % (addr & ~1) if addr in self.br: print "warn: overwriting breakpoint at %s" % sym self.br[addr]={'sym': sym, 'cb': cb, 'old': self.br[addr]['old']} else: self.br[addr]={'sym': sym, 'cb': cb, 'old': unhex(self.fetch('m%s,2' % addr))} #self.fetch('Z0,%s,2' % addr) tmp = self.fetch('X%s,2:\xbe\xbe' % addr) if self.verbose and not quiet: print "set break: @%s (0x%s)" % (sym, addr), tmp
def dump(self, size, addr=None): """ dumps data from addr if given otherwise at beginning of .text segment aka self.elf.workarea""" if addr == None: addr = self.elf.workarea rd = b'' end = addr + size bsize = self.get_packet_size() // 2 while addr < end: bsize = bsize if addr + bsize < end else end - addr #print('m%x,%x' % (addr, bsize)) pkt = self.fetch(b'm%x,%x' % (addr, bsize)) if len(pkt) & 1 and pkt[:1] == b'E': # There is an assumption that stub only uses 'e' for data # hexadecimal representation and 'E' is only used for errors. # However, no confirmation has been found in the protocol # definition. But, according to the protocol error message # data length is always odd (i.e. Exx). raise RuntimeError("Reading %u bytes at 0x%x failed: %s " % (bsize, addr, s(pkt))) rd += unhex(rsp_decode(pkt)) addr += bsize #print("%s %s pkt %s" % (addr, bsize, pkt)) return rd
def getreg(self, size, ptr): tmp = self.fetch('m%x,%x' % (ptr, size)) return unhex(switch_endian(tmp))
def getreg(self,size,ptr): tmp = self.fetch(b'm%x,%x' % (ptr, size)) return unhex(switch_endian(tmp))
def getreg(rsp, size, ptr): tmp = rsp.fetch('m%x,%x' % (ptr, size)) return unhex(switch_endian(tmp))
rsp.refresh_regs() steps -= 1 if __name__ == "__main__": try: elffile = sys.argv[1] if len(sys.argv) > 1 else None rsp = CortexM3('/dev/ttyACM0', elffile, verbose=False) rsp.refresh_regs() dump_mpu(rsp) print 'flash_optcr=', printreg( flash_optcr.parse(getreg(rsp, 4, FLASH_OPTCR))) check_fault(rsp) print 'VTOR=', hex(struct.unpack(">I", getreg(rsp, 4, SCB_VTOR))[0]) rsp.lazy_dump_regs() print 'xpsr=', printreg(xpsr.parse(unhex(rsp.regs['xpsr']))) #print hex() disassm(rsp, int(rsp.regs['pc'], 16), 4) if int(rsp.regs['pc'], 16) in [0x8003422, 0x8003424, 0x8003426]: rsp.set_reg('r3', rsp.regs['r0']) print "[x] force stepping over loop" while int(rsp.regs['pc'], 16) < 0x8003426: rsp.lazy_dump_regs() r = rsp.fetch('s') if r != 'T05': print r disassm(rsp, int(rsp.regs['pc'], 16), 4) print "[x] tracing" trace(rsp, 20) rsp.port.close(rsp)