debugger
debugger copied to clipboard
Implement module list parsing for GDB MI adapter
Summary
Implemented GetModuleList() for the GDB MI adapter to parse info proc mappings output and return loaded modules. Also added process exit detection and event handling. Fixed synchronization issue with console output buffering. Fixed command serialization to prevent concurrent GDB commands.
Changes
- [x] Understand the repository structure and GDB MI adapter
- [x] Implement parsing of
info proc mappingsoutput in GdbMiAdapter::GetModuleList() - [x] Handle duplicate module names by appending -1, -2, etc. (logic prepared)
- [x] Fix parsing to properly skip anonymous memory mappings
- [x] Test the implementation with standalone test (all tests pass)
- [x] Run security checks with codeql_checker (no vulnerabilities found)
- [x] Clean up code
- [x] Add process exit detection and event handling
- [x] Fix synchronization issue with console output collection
- [x] Fix command serialization to prevent interleaved GDB commands
Implementation Details
Module List Parsing
The implementation:
- Uses
-interpreter-exec console "info proc mappings"to get memory mappings - Acquires
m_gdbCommandMutexto serialize GDB commands - Buffers console output asynchronously to avoid race conditions
- Increases timeout to 5 seconds to handle large output
- Parses tabular output to extract address ranges and object file paths
- Consolidates multiple segments for the same object file
- Filters out special mappings ([stack], [heap], [vvar], [vdso], etc.)
- Filters out anonymous memory mappings
- Returns proper
DebugModulestructures with name, address, and size
Command Serialization
The m_gdbCommandMutex is now acquired in GetModuleList():
- Prevents other threads from sending GDB commands while waiting for response
- Eliminates command interleaving (e.g., ReadMemory sent before GetModuleList completes)
- Ensures responses arrive in the expected order
- Consistent with how other adapter methods serialize MI traffic
Console Output Buffering
Added a mechanism to temporarily buffer console output:
m_consoleBuffer: Stores console output when collection is enabledm_collectConsoleOutput: Flag to enable/disable bufferingm_consoleBufferMutex: Protects access to the buffer- Console output (
~records) is buffered inAsyncRecordHandlerwhen enabled - This prevents console output from being lost or arriving after timeout
Process Exit Handling
When the target process exits after resuming:
- Detects
ProcessExitedstop reason in async stopped events - Parses the
exit-codefield if available from GDB MI output - Posts a
TargetExitedEventTypeevent to notify the debugger UI - Stores and returns the exit code via
ExitCode()method - Skips state refresh when process has exited
Root Causes of Synchronization Issues
Issue 1: Console Output Race
The original implementation had a race condition:
info proc mappingsgenerates console output as async~records- These records were sent to the event system, not collected
- The command timeout (1 second) was too short for large output
- Console output arrived after timeout, causing subsequent commands to fail
Issue 2: Command Interleaving
The console buffering fix didn't fully resolve the issue because:
GetModuleList()didn't acquirem_gdbCommandMutex- Other threads (e.g., UI thread calling ReadMemory) could send commands concurrently
- Commands were interleaved while waiting for
info proc mappingsresponse - GDB responses arrived out of order, causing timeouts and failures
The final fix ensures both proper console buffering AND command serialization.
Testing
Created standalone tests that validate:
- Basic parsing of sample GDB output
- Correct handling of empty output
- Proper filtering of special mappings
- Single and multiple module scenarios
All tests pass successfully.
Original prompt
This section details on the original issue you should resolve
<issue_title>GDB MI adapter should read the list of loaded modules</issue_title> <issue_description>Parse the result of
info proc mappingsand return its result. A sample output is provided:(gdb) info proc mappings process 25443 Mapped address spaces: Start Addr End Addr Size Offset Perms objfile 0x555555554000 0x555555555000 0x1000 0x0 r--p /home/xusheng/debugger_build/debugger/test/binaries/Linux-x86_64/helloworld 0x555555555000 0x555555556000 0x1000 0x1000 r-xp /home/xusheng/debugger_build/debugger/test/binaries/Linux-x86_64/helloworld 0x555555556000 0x555555557000 0x1000 0x2000 r--p /home/xusheng/debugger_build/debugger/test/binaries/Linux-x86_64/helloworld 0x555555557000 0x555555558000 0x1000 0x2000 r--p /home/xusheng/debugger_build/debugger/test/binaries/Linux-x86_64/helloworld 0x555555558000 0x555555559000 0x1000 0x3000 rw-p /home/xusheng/debugger_build/debugger/test/binaries/Linux-x86_64/helloworld 0x7ffff7c00000 0x7ffff7c28000 0x28000 0x0 r--p /usr/lib/x86_64-linux-gnu/libc.so.6 0x7ffff7c28000 0x7ffff7db0000 0x188000 0x28000 r-xp /usr/lib/x86_64-linux-gnu/libc.so.6 0x7ffff7db0000 0x7ffff7dff000 0x4f000 0x1b0000 r--p /usr/lib/x86_64-linux-gnu/libc.so.6 0x7ffff7dff000 0x7ffff7e03000 0x4000 0x1fe000 r--p /usr/lib/x86_64-linux-gnu/libc.so.6 0x7ffff7e03000 0x7ffff7e05000 0x2000 0x202000 rw-p /usr/lib/x86_64-linux-gnu/libc.so.6 0x7ffff7e05000 0x7ffff7e12000 0xd000 0x0 rw-p 0x7ffff7fa0000 0x7ffff7fa3000 0x3000 0x0 rw-p 0x7ffff7fbd000 0x7ffff7fbf000 0x2000 0x0 rw-p 0x7ffff7fbf000 0x7ffff7fc1000 0x2000 0x0 r--p [vvar] 0x7ffff7fc1000 0x7ffff7fc3000 0x2000 0x0 r--p [vvar_vclock] 0x7ffff7fc3000 0x7ffff7fc5000 0x2000 0x0 r-xp [vdso] 0x7ffff7fc5000 0x7ffff7fc6000 0x1000 0x0 r--p /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 0x7ffff7fc6000 0x7ffff7ff1000 0x2b000 0x1000 r-xp /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 0x7ffff7ff1000 0x7ffff7ffb000 0xa000 0x2c000 r--p /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 0x7ffff7ffb000 0x7ffff7ffd000 0x2000 0x36000 r--p /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 0x7ffff7ffd000 0x7ffff7fff000 0x2000 0x38000 rw-p /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 0x7ffffffde000 0x7ffffffff000 0x21000 0x0 rw-p [stack] 0xffffffffff600000 0xffffffffff601000 0x1000 0x0 --xp [vsyscall]When there are multiple object file with the same name, the one that appears first should take the original name, and later ones should have -1, -2 appended to the name so as to differentiate them</issue_description>
Comments on the Issue (you are @copilot in this section)
Fixes Vector35/debugger#900
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.