diff --git a/tools/minidumpserver.py b/tools/minidumpserver.py index 0e7b1d9cc4..6336e072d0 100755 --- a/tools/minidumpserver.py +++ b/tools/minidumpserver.py @@ -41,6 +41,9 @@ SHF_ALLOC_EXEC = SHF_ALLOC | SHF_EXEC GDB_SIGNAL_DEFAULT = 7 +UINT16_MAX = 65535 + + DEFAULT_GDB_INIT_CMD = "-ex 'bt full' -ex 'info reg' -ex 'display /40i $pc-40'" logger = logging.getLogger() @@ -307,7 +310,20 @@ class DumpELFFile: if segment.header.p_flags & 1 and not self.__text: self.__text = segment.header.p_vaddr + symtab = elf.get_section_by_name(".symtab") + self.symbol = {} + for symbol in symtab.iter_symbols(): + if symbol["st_info"]["type"] != "STT_OBJECT": + continue + + if symbol.name in ("g_tcbinfo", "g_pidhash", "g_npidhash"): + self.symbol[symbol.name] = symbol + logger.debug( + f"name:{symbol.name} size:{symbol['st_size']} value:{hex(symbol['st_value'])}" + ) + elf.close() + return True def merge(self, other): @@ -454,19 +470,25 @@ class GDBStub: def __init__( self, logfile: DumpLogFile, elffile: DumpELFFile, rawfile: RawMemoryFile ): - self.logfile = logfile + self.registers = logfile.registers self.elffile = elffile self.socket = None self.gdb_signal = GDB_SIGNAL_DEFAULT self.mem_regions = ( self.elffile.get_memories() - + self.logfile.get_memories() + + logfile.get_memories() + rawfile.get_memories() ) self.reg_digits = elffile.xlen() // 4 self.reg_fmt = " unknown value - # Send in "xxxxxxxx" - pkt += b"x" * self.reg_digits + def put_register_packet(regs): + pkt = b"" - self.put_gdb_packet(pkt) + for reg in regs: + if reg != b"x": + bval = struct.pack(self.reg_fmt, reg) + pkt += binascii.hexlify(bval) + else: + # Register not in coredump -> unknown value + # Send in "xxxxxxxx" + pkt += b"x" * self.reg_digits + + self.put_gdb_packet(pkt) + + if not self.threadinfo: + put_register_packet(self.registers) + else: + for thread in self.threadinfo: + if thread["tcb"]["pid"] == self.current_thread: + put_register_packet(thread["gdb_regs"]) + break def handle_register_single_read_packet(self, pkt): logger.debug(f"pkt: {pkt}") - reg = int("0x" + pkt[1:].decode("utf8"), 16) - if reg < len(self.logfile.registers) and self.logfile.registers[reg] != b"x": - bval = struct.pack(self.reg_fmt, self.logfile.registers[reg]) - self.put_gdb_packet(binascii.hexlify(bval)) + def put_one_register_packet(regs): + + reg = int(pkt[1:].decode("utf8"), 16) + if reg < len(regs) and regs[reg] != b"x": + bval = struct.pack(self.reg_fmt, regs[reg]) + self.put_gdb_packet(binascii.hexlify(bval)) + else: + self.put_gdb_packet(b"x" * self.reg_digits) + + if not self.threadinfo: + put_one_register_packet(self.registers) else: - self.put_gdb_packet(b"x" * self.reg_digits) + for thread in self.threadinfo: + if thread["tcb"]["pid"] == self.current_thread: + put_one_register_packet(thread["gdb_regs"]) + break def handle_register_group_write_packet(self): # the 'G' packet for writing to a group of registers @@ -572,35 +614,31 @@ class GDBStub: reg_val = 0 for i in range(0, len(value), 2): data = value[i : i + 2] - reg_val = reg_val + (int("0x" + data.decode("utf8"), 16) << (i * 4)) + reg_val = reg_val + (int(data.decode("utf8"), 16) << (i * 4)) - reg = int("0x" + index.decode("utf8"), 16) - if reg < len(self.logfile.registers): - self.logfile.registers[reg] = reg_val + reg = int(index.decode("utf8"), 16) + if reg < len(self.registers): + self.registers[reg] = reg_val self.put_gdb_packet(b"OK") + def get_mem_region(self, addr): + left = 0 + right = len(self.mem_regions) - 1 + while left <= right: + mid = (left + right) // 2 + if self.mem_regions[mid]["start"] <= addr <= self.mem_regions[mid]["end"]: + return self.mem_regions[mid] + elif addr < self.mem_regions[mid]["start"]: + right = mid - 1 + else: + left = mid + 1 + + return None + def handle_memory_read_packet(self, pkt): # the 'm' packet for reading memory: m, - def get_mem_region(addr): - left = 0 - right = len(self.mem_regions) - 1 - while left <= right: - mid = (left + right) // 2 - if ( - self.mem_regions[mid]["start"] - <= addr - <= self.mem_regions[mid]["end"] - ): - return self.mem_regions[mid] - elif addr < self.mem_regions[mid]["start"]: - right = mid - 1 - else: - left = mid + 1 - - return None - # extract address and length from packet # and convert them into usable integer values addr, length = pkt[1:].split(b",") @@ -610,7 +648,7 @@ class GDBStub: remaining = length addr = s_addr barray = b"" - r = get_mem_region(addr) + r = self.get_mem_region(addr) while remaining > 0: if r is None: barray = None @@ -634,8 +672,154 @@ class GDBStub: # We don't support writing so return error self.put_gdb_packet(b"E02") + def handle_is_thread_active(self, pkt): + self.current_thread = int(pkt[1:]) - 1 + self.put_gdb_packet(b"OK") + + def handle_thread_context(self, pkt): + if b"g" == pkt[1:2]: + self.current_thread = int(pkt[2:]) - 1 + elif b"c" == pkt[1:2]: + self.current_thread = int(pkt[3:]) - 1 + + if self.current_thread == -1: + self.current_thread = 0 + self.put_gdb_packet(b"OK") + + def parse_thread(self): + def unpack_data(addr, size, fmt): + r = self.get_mem_region(addr) + offset = addr - r["start"] + data = r["data"][offset : offset + size] + return struct.unpack(fmt, data) + + TCBINFO_FMT = "<8HQ" + + # uint16_t pid_off; /* Offset of tcb.pid */ + # uint16_t state_off; /* Offset of tcb.task_state */ + # uint16_t pri_off; /* Offset of tcb.sched_priority */ + # uint16_t name_off; /* Offset of tcb.name */ + # uint16_t stack_off; /* Offset of tcb.stack_alloc_ptr */ + # uint16_t stack_size_off; /* Offset of tcb.adj_stack_size */ + # uint16_t regs_off; /* Offset of tcb.regs */ + # uint16_t regs_num; /* Num of general regs */ + # union + # { + # uint8_t u[8]; + # FAR const uint16_t *p; + # } + + unpacked_data = unpack_data( + self.elffile.symbol["g_tcbinfo"]["st_value"], + self.elffile.symbol["g_tcbinfo"]["st_size"], + TCBINFO_FMT, + ) + tcbinfo = { + "pid_off": int(unpacked_data[0]), + "state_off": int(unpacked_data[1]), + "pri_off": int(unpacked_data[2]), + "name_off": int(unpacked_data[3]), + "stack_off": int(unpacked_data[4]), + "stack_size_off": int(unpacked_data[5]), + "regs_off": int(unpacked_data[6]), + "regs_num": int(unpacked_data[7]), + "reg_off": int(unpacked_data[8]), + } + + unpacked_data = unpack_data( + self.elffile.symbol["g_npidhash"]["st_value"], + self.elffile.symbol["g_npidhash"]["st_size"], + "