Skip to content

Support arbitrary addresses in disassembly tabs#75

Open
TibboddiT wants to merge 1 commit into
al13n321:mainfrom
TibboddiT:feat-arbitrary_addresses
Open

Support arbitrary addresses in disassembly tabs#75
TibboddiT wants to merge 1 commit into
al13n321:mainfrom
TibboddiT:feat-arbitrary_addresses

Conversation

@TibboddiT

Copy link
Copy Markdown
Contributor

Related:

This PR makes the disassembly window useful when there is no normal function symbol to open. The existing symbol-backed function view remains preferred and unchanged for ordinary code, but the UI can now fall back to disassembling live process memory for JIT-generated code, anonymous executable mappings, stripped code, and stack frames whose instruction pointer cannot be resolved to a known function.

When the user enters an absolute address with g, the debugger first tries the normal function lookup path. If that succeeds, it opens or reuses the regular function disassembly tab with source lines, inline-call structure, symbol names, and function-relative offsets. If no function can be found and symbols are not merely still loading, it reads memory around the requested address and opens a memory disassembly tab instead.

Memory tabs use runtime addresses directly. They show bytes read from the debuggee process, restore original bytes over active software breakpoints, display the containing memory mapping, and support instruction breakpoints and run-to-cursor on raw instruction addresses. They do not show source lines or inline-function structure, because that information belongs to symbol-backed function disassembly.

Automatic stack/IP navigation also falls back to memory disassembly. When the selected stack frame has no usable function information, the disassembly window tries to show a memory tab around the frame instruction pointer instead of leaving the user with only an error tab. Failed automatic reads are remembered to avoid repeatedly probing the same unreadable area until caches are dropped.

Start-address selection is deliberately conservative for automatic IP fallback. The debugger trusts the instruction pointer as a real instruction boundary, then probes candidate decode streams before it. A candidate is accepted only if decoding from that start reaches the instruction pointer exactly as an instruction start, and only if that candidate is unique. If the code cannot prove a unique earlier stream, the memory tab starts at the instruction pointer. This favors showing less context over showing a plausible but wrong x86 decode stream.

Manual address lookup is more pragmatic. If the user-entered address lands inside an instruction, the debugger searches nearby possible starts and chooses the stream that contains the requested address and decodes farthest. If the selected thread's RIP is relevant to that candidate window, it is used as a hard instruction-boundary anchor. If no good candidate is found, the tab starts exactly at the requested address.

Source-level step-into now handles entering code without unwind information more sensibly. This is common for JIT code. When a source-level step-into lands in code where the debugger can no longer compute CFA/unwind state, the step is treated as complete instead of continuing to reason from stale symbolic stack state.

The user-facing help text was updated to describe the new memory-disassembly fallback. Explicit address ranges are still not supported; g accepts one raw address and the debugger chooses a useful range around it.

The PR also adds unit coverage for the instruction-start heuristics and a manual JIT test program in C for exercising the new behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The disassembly panel could show disassembled memory even when binary is absent or incomplete

1 participant