diff --git a/.gitignore b/.gitignore index cdd35713..8318da0f 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,8 @@ core/adapters/LLDB.framework /test/binaries/Darwin-arm64-signed/ /test/binaries/Darwin-x86_64-signed/ test/__pycache__ +api/python/__pycache__ +*/__pycache__/ /build /artifacts diff --git a/api/python/debuggercontroller.py b/api/python/debuggercontroller.py index 351550dd..0174581f 100644 --- a/api/python/debuggercontroller.py +++ b/api/python/debuggercontroller.py @@ -56,7 +56,7 @@ def __setattr__(self, name, value): raise AttributeError(f"attribute '{name}' is read only") def __repr__(self): - return f"" + return f"" class DebugThread: @@ -131,7 +131,7 @@ def __ne__(self, other): return not (self == other) def __hash__(self): - return hash((self.name, self.short_name, self.address. self.size, self.loaded)) + return hash((self.name, self.short_name, self.address, self.size, self.loaded)) def __setattr__(self, name, value): try: @@ -140,7 +140,7 @@ def __setattr__(self, name, value): raise AttributeError(f"attribute '{name}' is read only") def __repr__(self): - return f"" + return f"" class DebugRegister: @@ -174,7 +174,7 @@ def __ne__(self, other): return not (self == other) def __hash__(self): - return hash((self.name, self.value, self.width. self.index, self.hint)) + return hash((self.name, self.value, self.width, self.index, self.hint)) def __setattr__(self, name, value): try: @@ -203,7 +203,21 @@ def __init__(self, handle): dbgcore.BNDebuggerFreeRegisters(registers, count.value) def __repr__(self) -> str: - return self.regs.__repr__() + if not self.regs: + return "" + + # Show registers in a more readable format + reg_entries = [] + # Sort registers by name for consistent output + for name in sorted(self.regs.keys()): + reg = self.regs[name] + hint_str = f" ({reg.hint})" if reg.hint else "" + reg_entries.append(f"{name}={reg.value:#x}{hint_str}") + + # Show all registers + reg_list = ", ".join(reg_entries) + + return f"" def __getitem__(self, name): if name not in self.regs: @@ -248,7 +262,7 @@ def __ne__(self, other): return not (self == other) def __hash__(self): - return hash((self.module, self.offset, self.address. self.enabled)) + return hash((self.module, self.offset, self.address, self.enabled)) def __setattr__(self, name, value): try: @@ -305,6 +319,9 @@ def __setattr__(self, name, value): except AttributeError: raise AttributeError(f"attribute '{name}' is read only") + def __repr__(self): + return f"" + class DebugFrame: """ @@ -373,6 +390,9 @@ def __init__(self, reason: DebugStopReason, last_active_thread: int, exit_code: self.exit_code = exit_code self.data = data + def __repr__(self): + return f"" + class ErrorEventData: """ @@ -386,6 +406,9 @@ def __init__(self, error: str, data): self.error = error self.data = data + def __repr__(self): + return f"" + class TargetExitedEventData: """ @@ -397,6 +420,9 @@ class TargetExitedEventData: def __init__(self, exit_code: int): self.exit_code = exit_code + def __repr__(self): + return f"" + class StdOutMessageEventData: """ @@ -408,6 +434,11 @@ class StdOutMessageEventData: def __init__(self, message: str): self.message = message + def __repr__(self): + # Truncate long messages for readability + msg = self.message[:50] + "..." if len(self.message) > 50 else self.message + return f"" + class DebuggerEventData: """ @@ -434,6 +465,25 @@ def __init__(self, target_stopped_data: TargetStoppedEventData, self.exit_data = exit_data self.message_data = message_data + def __repr__(self): + # Show only the data that's not None for better readability + parts = [] + if self.target_stopped_data is not None: + parts.append(f"stopped={self.target_stopped_data.reason}") + if self.error_data is not None: + parts.append(f"error='{self.error_data.error[:30]}..'" if len(self.error_data.error) > 30 else f"error='{self.error_data.error}'") + if self.absolute_address: + parts.append(f"abs_addr={self.absolute_address:#x}") + if self.relative_address: + parts.append(f"rel_addr={self.relative_address}") + if self.exit_data is not None: + parts.append(f"exit_code={self.exit_data.exit_code}") + if self.message_data is not None: + msg = self.message_data.message[:20] + "..." if len(self.message_data.message) > 20 else self.message_data.message + parts.append(f"msg='{msg}'") + + return f"" + class DebuggerEvent: """ @@ -447,6 +497,9 @@ def __init__(self, type: DebuggerEventType, data: DebuggerEventData): self.type = type self.data = data + def __repr__(self): + return f"" + DebuggerEventCallback = Callable[['DebuggerEvent'], None] @@ -1602,3 +1655,31 @@ def __ne__(self, other): def __hash__(self): return hash(ctypes.addressof(self.handle.contents)) + + def __repr__(self): + try: + # Basic connection and status info + connected = "connected" if self.connected else "disconnected" + running = "running" if self.running else "stopped" + + # Debug adapter name + adapter_name = self.adapter_type + + # Determine if local or remote debugging + remote_host = self.remote_host + remote_port = self.remote_port + + if remote_host and remote_port > 0: + # Remote debugging + debugging_type = f"remote {remote_host}:{remote_port}" + else: + # Local debugging + debugging_type = "local" + + # Executable path + exec_path = self.executable_path or "unknown" + + return f"" + except: + # Fallback to basic representation if we can't get state info + return f""