Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8cf5980
Add section name constant and part/section IDs
lapla-cogito May 27, 2026
d1ba635
Add `--gdb-index` and `--no-gdb-index`
lapla-cogito May 27, 2026
935b190
Implement `.gdb_index` section generation
lapla-cogito May 27, 2026
3db1ae5
Update skip tests list
lapla-cogito May 27, 2026
a845911
Add integration tests
lapla-cogito May 27, 2026
c17257a
Eliminate duplicate parse_cu_boundaries in compute_gdb_index_size
lapla-cogito May 27, 2026
469eb9d
Merge address and symbol table construction into single object scan
lapla-cogito May 27, 2026
224d518
clippy fix
lapla-cogito May 27, 2026
9d3f0ff
Extract shared pubnames/pubtypes iteration into a helper
lapla-cogito May 27, 2026
b31d144
Use more idiomatic APIs and fix step calc
lapla-cogito May 29, 2026
c6aaf5b
Calculate hashslots using zerocopy
lapla-cogito May 29, 2026
52a5131
Add a comment for `cv_bytes` addition
lapla-cogito May 29, 2026
17b1abf
Add consts for `.debug_info`
lapla-cogito May 29, 2026
1b3070c
Write constant pool directly to output buffer
lapla-cogito May 29, 2026
b935f8f
Use itertools `sorted_unstable_by_key()`
lapla-cogito May 29, 2026
82fb063
Unify object scannig logic
lapla-cogito May 29, 2026
00ab232
Refactor pubnames collection
lapla-cogito May 29, 2026
f3c060f
Use `BTreeSet` for `cv_entries`
lapla-cogito May 29, 2026
ebf6270
Improve error handling
lapla-cogito May 31, 2026
d35f6b8
Use `sorted_names` rather than `sorted` as a variable name
lapla-cogito May 31, 2026
1c1550f
Emit errors when GDB indices are corrupted
lapla-cogito Jun 1, 2026
1084243
Add some comments and warnings
lapla-cogito Jun 1, 2026
a682194
Revert "Emit errors when GDB indices are corrupted"
lapla-cogito Jun 1, 2026
f6f856c
Add a comment about CU
lapla-cogito Jun 1, 2026
c56a5be
Add some `timing_phase!`s
lapla-cogito Jun 11, 2026
b80b0c5
Return an error if gdb index hash table has no empty slots
lapla-cogito Jun 11, 2026
0c0b335
Parallelize GDB index scan and cache the result across phases
lapla-cogito Jun 11, 2026
fb3ccdf
Reduce reparsing `.debug_info`
lapla-cogito Jun 11, 2026
1011cec
Handle compressed debug sections in GDB index generation
lapla-cogito Jun 11, 2026
373a70a
Replace most of `break`s with `ensure!`
lapla-cogito Jun 11, 2026
aa4f1c3
Don't generate GDB index with `--strip-debug` or `--strip-all`
lapla-cogito Jun 11, 2026
b05456a
Fix address entries for objects with multiple CUs
lapla-cogito Jun 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion libwild/src/args/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ pub struct ElfArgs {

pub(crate) nmagic: bool,
pub(crate) rosegment: bool,
pub(crate) gdb_index: bool,

rpath_set: IndexSet<String>,

Expand Down Expand Up @@ -233,7 +234,6 @@ const SILENTLY_IGNORED_SHORT_FLAGS: &[&str] = &[
];

const IGNORED_FLAGS: &[&str] = &[
"gdb-index",
"fix-cortex-a53-835769",
"fix-cortex-a53-843419",
"discard-all",
Expand Down Expand Up @@ -332,6 +332,7 @@ impl Default for ElfArgs {

experimental_sframe: false,
debug_compression_kind: None,
gdb_index: false,
}
}
}
Expand Down Expand Up @@ -1117,6 +1118,24 @@ fn setup_argument_parser() -> ArgumentParser<ElfArgs> {
Ok(())
});

parser
.declare()
.long("gdb-index")
.help("Generate GDB index")
.execute(|args, _modifier_stack| {
args.gdb_index = true;
Ok(())
});

parser
.declare()
.long("no-gdb-index")
.help("Disable GDB index generation")
.execute(|args, _modifier_stack| {
args.gdb_index = false;
Ok(())
});

parser
.declare_with_param()
.long("soname")
Expand Down Expand Up @@ -2057,6 +2076,10 @@ impl platform::Args for ElfArgs {
fn should_output_partial_object(&self) -> bool {
self.should_output_partial_object
}

fn should_write_gdb_index(&self) -> bool {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like lld and mold, if --strip-debug is supplied (or presumably --strip, but I didn't try that) won't write the gdb-index. Could we do the same (and have a test for it)? As a separate PR is fine, but also fine in this PR.

@lapla-cogito lapla-cogito Jun 11, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing locally, neither lld nor mold emits a GDB index when either --strip-all or --strip-debug is passed, so I changed the implementation to match that behavior. aa4f1c3

self.gdb_index && !self.should_strip_debug()
}
}

#[cfg(test)]
Expand Down
14 changes: 14 additions & 0 deletions libwild/src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1889,6 +1889,7 @@ impl platform::Platform for Elf {
builder.add_sections(&custom.bss);

builder.add_sections(&custom.nonalloc);
builder.add_section(output_section_id::GDB_INDEX);
builder.add_section(output_section_id::COMMENT);
builder.add_section(output_section_id::RISCV_ATTRIBUTES);
builder.add_section(output_section_id::SHSTRTAB);
Expand Down Expand Up @@ -2099,6 +2100,14 @@ impl platform::Platform for Elf {
total_sizes.merge(&extra_sizes);
}

type GdbIndexScanResult = crate::gdb_index::GdbIndexScanResult;

fn compute_gdb_index_size(
groups: &[crate::layout::GroupState<Self>],
) -> crate::error::Result<(u64, Option<Self::GdbIndexScanResult>)> {
crate::gdb_index::compute_gdb_index_size(groups)
}

fn align_load_segment_start(
_segment_def: Self::ProgramSegmentDef,
segment_alignment: Alignment,
Expand Down Expand Up @@ -4757,6 +4766,11 @@ const SECTION_DEFINITIONS: [BuiltInSectionDetails; NUM_BUILT_IN_SECTIONS] = {
kind: SectionKind::Secondary(output_section_id::SYMTAB_SHNDX_LOCAL),
..DEFAULT_DEFS
};
defs[output_section_id::GDB_INDEX.as_usize()] = BuiltInSectionDetails {
kind: SectionKind::Primary(SectionName(GDB_INDEX_SECTION_NAME)),
ty: sht::PROGBITS,
..DEFAULT_DEFS
};
// Start of regular sections
defs[output_section_id::RODATA.as_usize()] = BuiltInSectionDetails {
kind: SectionKind::Primary(SectionName(RODATA_SECTION_NAME)),
Expand Down
24 changes: 24 additions & 0 deletions libwild/src/elf_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ pub(crate) fn write<'data, A: Arch<Platform = Elf>>(
crate::validation::validate_bytes(layout, &sized_output.out)?;
}

// Write .gdb_index before splitting, since it needs to read .debug_info from the output.
write_gdb_index_section(&mut sized_output.out, layout)?;

let mut section_buffers = split_output_into_sections(layout, &mut sized_output.out).0;

if layout.args().should_write_eh_frame_hdr {
Expand Down Expand Up @@ -313,6 +316,27 @@ fn fill_padding(mut section_buffers: OutputSectionMap<&mut [u8]>) {
});
}

fn write_gdb_index_section(output: &mut [u8], layout: &ElfLayout) -> Result {
use crate::platform::Args as _;
if !layout.args().should_write_gdb_index() {
return Ok(());
}
let Some(scan) = &layout.gdb_index_data else {
return Ok(());
};
let sl = layout.section_layouts.get(output_section_id::GDB_INDEX);
if sl.file_size == 0 {
return Ok(());
}
timing_phase!("Write .gdb_index");
let start = sl.file_offset;
// Split the output buffer so that the part before our section is readable (for .debug_info)
// and our section is writable.
let (before, rest) = output.split_at_mut(start);
let gdb_buf = &mut rest[..sl.file_size];
crate::gdb_index::write_gdb_index(gdb_buf, before, layout, scan)
}

fn write_sframe_section(sframe_buffer: &mut [u8], layout: &ElfLayout) -> Result {
if layout.args().discard_sframe || sframe_buffer.is_empty() {
return Ok(());
Expand Down
Loading
Loading