You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There are certain symbols that the debugger (windbg/lldb) understands but BN does not know about. For example, when a register points to the address of a Windows API function, it would be great if we can let the user know about it. However, this requires the debugger knowing the address of the API function, which is not present in the executable binary view. To solve this problem, we need to read symbols from the debugger backend and somehow integrate it into the debugger binary view. So the annotation process is aware of it.
So a compromise on this is that we can offer a method to read the symbol at a specific address. The users can use this API on demand. This avoids many tricky design issues, e.g., how often/when should we update the symbols.
Dumping this. A common scenario is where the user debugs some code and a register now points to an API function. Right now he would not be able to see it. We should somehow offer a way to do it
Design Notes (from code review of x64dbg + internal discussion)
How x64dbg handles symbols
Per-module lifecycle: Symbols are loaded on LOAD_DLL_DEBUG_EVENT and unloaded on UNLOAD_DLL_DEBUG_EVENT. They are never refreshed on step/breakpoint — only on module load/unload.
Async loading: Background threads per module so symbol loading doesn't block the debugger.
Full refresh per module, not incremental: Old symbols destroyed and rebuilt from scratch when a module reloads.
Data structures: Sorted vectors for O(log n) binary search by address and by name.
Proposed design for our debugger
Key insight: Symbols are tied to module lifecycle, not execution state. They should NOT be in the dirty-flag refresh cycle that runs on every stop event. Instead, piggyback on the existing DetectLoadedModule() flow which already diffs the module list on each stop.
When modules change:
New module appears → fetch its symbols from the backend
Module disappears → discard its symbols
Module still present → keep symbols, no work needed
Adding symbols to the BinaryView:
Create FunctionSymbol for each backend symbol (e.g., exports like CreateFileA)
Short name: CreateFileA, full name: kernel32!CreateFileA
Also create a data variable at each address with type void — this is needed for BN to actually render the symbol in views
Use DefineAutoSymbol (not DefineUserSymbol) so they don't override user-defined symbols
Cleanup on debug stop: Track all addresses where backend symbols were added (similar to existing m_addressesWithVariable / m_addressesWithComment pattern). On TargetExitedEventType / DetachedEventType, iterate and call UndefineAutoSymbol + UndefineDataVariable for each.
Performance: For large modules (e.g., ntdll with thousands of exports), wrap bulk symbol addition in SetFunctionAnalysisUpdateDisabled(true/false) to avoid per-symbol analysis notification overhead.
Adapter capability: Add DebugAdapterSupportSymbols to DebugAdapterCapacity enum, or just add a virtual method with a default empty return:
Activity
xusheng6 commentedon Nov 17, 2023
So a compromise on this is that we can offer a method to read the symbol at a specific address. The users can use this API on demand. This avoids many tricky design issues, e.g., how often/when should we update the symbols.
xusheng6 commentedon Sep 26, 2025
Dumping this. A common scenario is where the user debugs some code and a register now points to an API function. Right now he would not be able to see it. We should somehow offer a way to do it
xusheng6 commentedon Mar 20, 2026
Design Notes (from code review of x64dbg + internal discussion)
How x64dbg handles symbols
LOAD_DLL_DEBUG_EVENTand unloaded onUNLOAD_DLL_DEBUG_EVENT. They are never refreshed on step/breakpoint — only on module load/unload.Proposed design for our debugger
Key insight: Symbols are tied to module lifecycle, not execution state. They should NOT be in the dirty-flag refresh cycle that runs on every stop event. Instead, piggyback on the existing
DetectLoadedModule()flow which already diffs the module list on each stop.When modules change:
Adding symbols to the BinaryView:
FunctionSymbolfor each backend symbol (e.g., exports likeCreateFileA)CreateFileA, full name:kernel32!CreateFileAvoid— this is needed for BN to actually render the symbol in viewsDefineAutoSymbol(notDefineUserSymbol) so they don't override user-defined symbolsCleanup on debug stop: Track all addresses where backend symbols were added (similar to existing
m_addressesWithVariable/m_addressesWithCommentpattern). OnTargetExitedEventType/DetachedEventType, iterate and callUndefineAutoSymbol+UndefineDataVariablefor each.Performance: For large modules (e.g., ntdll with thousands of exports), wrap bulk symbol addition in
SetFunctionAnalysisUpdateDisabled(true/false)to avoid per-symbol analysis notification overhead.Adapter capability: Add
DebugAdapterSupportSymbolstoDebugAdapterCapacityenum, or just add a virtual method with a default empty return:Symbol lookup: O(log n) — find the containing module first (existing
GetModuleForAddress()), then binary search that module's sorted symbol list.Load module symbols from the debugger backend on demand (#210)
Load module symbols from the debugger backend on demand (#210)
Load module symbols from the debugger backend on demand (#210) (#1115)