A C library for parsing and managing debug symbol information from various formats.
- Parse STABS debug information from .s files
- Read symbol tables from a.out binaries
- Load binary code from a.out files
- Load custom map files
- Fast binary search for symbol lookups
- Support for DAP (Debug Adapter Protocol) integration
The library supports loading debug symbols during the DAP launch phase:
// Load symbols from a.out binary
bool symbols_load_aout(const char* filename);
// Load symbols from STABS .s file
bool symbols_load_stabs(const char* filename);
// Load symbols from map file
bool symbols_load_map(const char* filename);For setting breakpoints, the library provides:
// Find address for a source location
bool symbols_find_address(const symbol_table_t* table, const char* filename,uint16_t *address, int line);
// Get source location for an address
const char* symbols_get_file(const symbol_table_t* table, uint16_t address);
int symbols_get_line(const symbol_table_t* table, uint16_t address);For stepping through code:
// Look up symbol at address
const symbol_entry_t* symbols_lookup_by_address(const symbol_table_t* table,
uint16_t address);
// Check if address is a line entry
bool symbols_is_line_entry(const symbol_entry_t* entry);
// Get next line address for stepping
uint16_t symbols_get_next_line_address(const symbol_table_t* table,
uint16_t current_address);The library can load binary code from a.out files:
// Load binary code
binary_info_t info;
if (symbols_load_binary("program.out", &info)) {
// Get program entry point
uint16_t entry = symbols_get_entry_point(&info);
// Find memory segment for an address
const memory_segment_t* segment = symbols_get_segment(&info, 0x1000);
if (segment) {
// Access memory contents
uint8_t value = segment->data[0x1000 - segment->start_address];
}
// Clean up
symbols_free_binary(&info);
}The binary loading features provide:
- Loading of text and data segments
- Memory segment information (start address, size, type)
- Program entry point
- Memory access through segment data pointers
makeThe library comes with a comprehensive test suite. To run all tests:
- First build the library and tests:
make
cd test
make- Run individual test programs:
# Test map file parser
./test_mapfile [mapfile]
# Test a.out symbol loading and binary code loading
./test_symbols_aout [a.out file] [--dump-code]
# Run performance tests
./test_performanceEach test program accepts different command line arguments:
test_mapfile: Tests the map file parser. If no file is specified, it uses a default test file.test_symbols_aout: Tests a.out symbol loading and binary code loading. The--dump-codeoption dumps the loaded binary code.test_performance: Runs performance tests for symbol lookups and other operations.
Test data files are located in the test/data/ directory.
// Launch phase
symbol_table_t* symbols = symbols_create();
if (symbols_load_aout(program_path)) {
// Symbols loaded successfully
} else if (symbols_load_stabs(stabs_path)) {
// STABS symbols loaded
} else if (symbols_load_map(map_path)) {
// Map file loaded
}
// Breakpoint handling
uint16_t address = symbols_find_address(symbols, source_file, line_number);
if (address != 0) {
// Set breakpoint at address
}
// Stepping
uint16_t pc = get_current_pc();
const symbol_entry_t* entry = symbols_lookup_by_address(symbols, pc);
if (entry) {
// Update source location
current_file = entry->filename;
current_line = entry->line;
}The library supports various symbol types:
- Functions (N_FUN)
- Variables (N_GSYM, N_LSYM)
- Source files (N_SO)
- Line numbers (N_SLINE)
- Types (N_TYPE)
The library handles memory management for:
- Symbol tables
- String allocations
- Type information
- Source file paths
The library uses binary search for fast symbol lookups, providing:
- O(log n) lookup time for address-based searches
- Automatic sorting of symbols by address
- Efficient memory usage
- Linear search for name-based lookups (since names are not sorted)
MIT License
This library provides a unified interface for reading and manipulating debug symbols from different formats:
- STABS (.s files)
- a.out symbol tables (nlist)
- Map files (source:line -> address mappings)
- ✅ Basic symbol table structure and management
- ✅ STABS parser implementation for PCC compiler output
- ✅ a.out nlist parser implementation
- ✅ Map file parser implementation
- ✅ Unified symbol type system
- ✅ Basic symbol lookup functions
- ✅ Memory management and cleanup
- ✅ Binary search optimization for address lookups
- ✅ Binary code loading from a.out files
- ✅ Test suite for all major components
- ✅ Integration with ND-100 toolchain
- 🔄 Documentation improvements
- 🔄 Binary loading bug fixes (see Todo section)
- 🔄 Performance optimization for large symbol tables
- Fix logic to load binary
- test_symbols_aout --dump-code data/intr.out
- Debug: text=171 data=0 bss=0 syms=184
- Failed to load binary from data/intr.out
- Add support for more complex STABS expressions
- Implement caching for frequently accessed symbols
- Add support for DWARF debug information (optional)
The library can be built using the provided Makefile:
makeThis will build both the library and test programs.
Basic usage example:
#include "symbols.h"
int main() {
// Create a new symbol table
symbol_table_t* table = symbols_create();
if (!table) {
// Handle error
}
// Load symbols from different sources
if (!symbols_load_stabs(table, "debug.s")) {
// Handle error
}
if (!symbols_load_nlist(table, "program.out")) {
// Handle error
}
if (!symbols_load_map(table, "program.map")) {
// Handle error
}
// Look up symbols
const symbol_entry_t* symbol = symbols_lookup_by_address(table, 0x1234);
if (symbol) {
printf("Found symbol at 0x1234: %s\n", symbol->name);
}
// Clean up
symbols_free(table);
return 0;
}Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
- Parse STABS debug symbols from
.sfiles (produced by PCC compiler) - Parse
nlistentries from a.out binaries - Spport simple map file formats
- Provide a unified lookup API: address ↔ file/line, symbol name ↔ address
- Be usable by:
- ND-100 emulator
- DAP server (
libdap) - Symbol inspection tools (e.g.,
test_reader)
libsymbols/
├── include/ # Public headers (symbols.h)
├── src/ # Implementation files (stabs, nlist, map, core logic)
├── test/ # Test program to load and dump symbols
├── Makefile # Builds libsymbols.a
├── README.md # This file
└── docs/ # Optional: references, notes, and format docs
- Implement
SymbolEntrydata structure (shared memory model) - Implement symbol table loading for:
- STABS in
.sfiles -
nlistin a.out binaries - Optional: address map files
- STABS in
- Implement lookup functions:
-
symbols_lookup_by_address() -
symbols_lookup_by_name() -
symbols_find_address(file, line)
-
- Implement
symbols_dump_all()for inspection
- Export the library for use in:
- ND-100 emulator
libdapDAP server
- Add error handling and validation
- Document the public API with comments
- Add test samples to
test/folder
MIT License
- STABS expression support (for types and structs)
- DWARF support (optional, later)
- Type-safe access to variable memory in emulator