Skip to content

Commit 176a835

Browse files
committed
fix: support DWARF5 rnglistx and split function ranges
Handle DW_FORM_rnglistx/DebugRngListsIndex in the range parsing paths so clang and gcc DWARF5 function-section builds keep their function ranges. Add gcc and clang regression coverage for indexed and offset-backed ranges, prefer the symbol-backed primary partition when split ranges lack entry_pc, and clean up fixture compiler selection and temporary patched binaries used by these tests.
1 parent 33cbf42 commit 176a835

11 files changed

Lines changed: 579 additions & 116 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

e2e-tests/compile-fixtures.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ else
1313
CLANG_BIN="clang"
1414
fi
1515

16+
if [[ -n "${GCC_BIN:-}" ]]; then
17+
GCC_BIN="$GCC_BIN"
18+
else
19+
GCC_BIN="gcc"
20+
fi
21+
1622
log() {
1723
printf '==> %s\n' "$*"
1824
}
@@ -69,6 +75,18 @@ run_make_fixture inline_call_value_program all
6975

7076
run_make_fixture partitioned_ranges_program clean
7177
run_make_fixture partitioned_ranges_program all
78+
run_make_fixture partitioned_ranges_program \
79+
all \
80+
"CC=${GCC_BIN}" \
81+
"CFLAGS=-Wall -Wextra -gdwarf-5 -O3 -DNDEBUG -ffunction-sections -freorder-blocks-and-partition" \
82+
"BINARY=partitioned_ranges_program_gcc_dwarf5_sections" \
83+
"OBJ=partitioned_ranges_program_gcc_dwarf5_sections.o"
84+
run_make_fixture partitioned_ranges_program \
85+
all \
86+
"CC=${CLANG_BIN}" \
87+
"CFLAGS=-Wall -Wextra -gdwarf-5 -O3 -DNDEBUG -ffunction-sections -fbasic-block-sections=all" \
88+
"BINARY=partitioned_ranges_program_clang_dwarf5_rnglistx" \
89+
"OBJ=partitioned_ranges_program_clang_dwarf5_rnglistx.o"
7290

7391
run_make_fixture cpp_complex_program clean
7492
run_make_fixture cpp_complex_program all

e2e-tests/tests/common/mod.rs

Lines changed: 146 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ lazy_static! {
3535
Mutex::new(None);
3636
static ref COMPILE_INLINE_CALL_VALUE_RESULT: Mutex<Option<anyhow::Result<()>>> =
3737
Mutex::new(None);
38-
static ref COMPILE_PARTITIONED_RANGES_RESULT: Mutex<Option<anyhow::Result<()>>> =
38+
static ref COMPILE_PARTITIONED_RANGES_DEFAULT_RESULT: Mutex<Option<anyhow::Result<()>>> =
39+
Mutex::new(None);
40+
static ref COMPILE_PARTITIONED_RANGES_GCC_DWARF5_FUNCTION_SECTIONS_RESULT: Mutex<Option<anyhow::Result<()>>> =
41+
Mutex::new(None);
42+
static ref COMPILE_PARTITIONED_RANGES_CLANG_DWARF5_RNGLISTX_RESULT: Mutex<Option<anyhow::Result<()>>> =
3943
Mutex::new(None);
4044
static ref COMPILE_CPP_COMPLEX_RESULT: Mutex<Option<anyhow::Result<()>>> = Mutex::new(None);
4145
static ref COMPILE_STATIC_SCOPE_DEFAULT_RESULT: Mutex<Option<anyhow::Result<()>>> =
@@ -211,6 +215,8 @@ pub fn init() {
211215
let _ = OptimizationLevel::Stripped;
212216
let _ = FixtureCompiler::Default;
213217
let _ = FixtureCompiler::ClangDwarf5;
218+
let _ = FixtureCompiler::GccDwarf5FunctionSections;
219+
let _ = FixtureCompiler::ClangDwarf5Rnglistx;
214220

215221
// Exercise runner builder methods so they are referenced in all bins.
216222
let _ = runner::GhostscopeRunner::new()
@@ -257,13 +263,17 @@ pub enum OptimizationLevel {
257263
pub enum FixtureCompiler {
258264
Default,
259265
ClangDwarf5,
266+
GccDwarf5FunctionSections,
267+
ClangDwarf5Rnglistx,
260268
}
261269

262270
impl FixtureCompiler {
263271
pub(crate) fn binary_name(&self, base: &str) -> String {
264272
match self {
265273
FixtureCompiler::Default => base.to_string(),
266274
FixtureCompiler::ClangDwarf5 => format!("{base}_clang_dwarf5"),
275+
FixtureCompiler::GccDwarf5FunctionSections => format!("{base}_gcc_dwarf5_sections"),
276+
FixtureCompiler::ClangDwarf5Rnglistx => format!("{base}_clang_dwarf5_rnglistx"),
267277
}
268278
}
269279

@@ -275,18 +285,30 @@ impl FixtureCompiler {
275285
match self {
276286
FixtureCompiler::Default => "default toolchain",
277287
FixtureCompiler::ClangDwarf5 => "clang -gdwarf-5",
288+
FixtureCompiler::GccDwarf5FunctionSections => "gcc -gdwarf-5 -ffunction-sections",
289+
FixtureCompiler::ClangDwarf5Rnglistx => {
290+
"clang -gdwarf-5 -ffunction-sections -fbasic-block-sections=all"
291+
}
278292
}
279293
}
280294

281-
fn apply_to_c_make(&self, cmd: &mut Command, base: &str, clang_dwarf5_cflags: &str) {
295+
fn apply_to_c_make(&self, cmd: &mut Command, base: &str, compiler_cflags: &str) {
282296
cmd.arg("all")
283297
.arg(format!("BINARY={}", self.binary_name(base)))
284298
.arg(format!("OBJ={}", self.object_name(base)));
285299

286-
if matches!(self, FixtureCompiler::ClangDwarf5) {
287-
let clang = preferred_clang_binary().unwrap_or("clang");
288-
cmd.arg(format!("CC={clang}"))
289-
.arg(format!("CFLAGS={clang_dwarf5_cflags}"));
300+
match self {
301+
FixtureCompiler::Default => {}
302+
FixtureCompiler::ClangDwarf5 | FixtureCompiler::ClangDwarf5Rnglistx => {
303+
let clang = preferred_clang_binary().unwrap_or_else(|| "clang".to_string());
304+
cmd.arg(format!("CC={clang}"))
305+
.arg(format!("CFLAGS={compiler_cflags}"));
306+
}
307+
FixtureCompiler::GccDwarf5FunctionSections => {
308+
let gcc = preferred_gcc_binary().unwrap_or_else(|| "gcc".to_string());
309+
cmd.arg(format!("CC={gcc}"))
310+
.arg(format!("CFLAGS={compiler_cflags}"));
311+
}
290312
}
291313
}
292314
}
@@ -377,8 +399,8 @@ impl RegisteredFixture {
377399
Ok(dir.join("inline_call_value_program"))
378400
}
379401
RegisteredFixtureKind::PartitionedRanges => {
380-
ensure_partitioned_ranges_program_compiled()?;
381-
Ok(dir.join("partitioned_ranges_program"))
402+
ensure_partitioned_ranges_program_compiled(FixtureCompiler::Default)?;
403+
Ok(dir.join(FixtureCompiler::Default.binary_name(self.name)))
382404
}
383405
RegisteredFixtureKind::CppComplex => {
384406
ensure_cpp_complex_program_compiled()?;
@@ -413,6 +435,12 @@ impl RegisteredFixture {
413435
.dir(fixtures_base)
414436
.join(compiler.binary_name(self.name)))
415437
}
438+
RegisteredFixtureKind::PartitionedRanges => {
439+
ensure_partitioned_ranges_program_compiled(compiler)?;
440+
Ok(self
441+
.dir(fixtures_base)
442+
.join(compiler.binary_name(self.name)))
443+
}
416444
RegisteredFixtureKind::EntryValueRecovery => {
417445
ensure_entry_value_recovery_program_compiled(compiler)?;
418446
Ok(self
@@ -451,6 +479,21 @@ pub(crate) fn fixture_compiler_available(compiler: FixtureCompiler) -> bool {
451479
),
452480
])
453481
}
482+
FixtureCompiler::GccDwarf5FunctionSections => {
483+
preferred_gcc_binary().is_some()
484+
|| precompiled_outputs_available(&[fixture_binary_path(
485+
"partitioned_ranges_program",
486+
&FixtureCompiler::GccDwarf5FunctionSections
487+
.binary_name("partitioned_ranges_program"),
488+
)])
489+
}
490+
FixtureCompiler::ClangDwarf5Rnglistx => {
491+
preferred_clang_binary().is_some()
492+
|| precompiled_outputs_available(&[fixture_binary_path(
493+
"partitioned_ranges_program",
494+
&FixtureCompiler::ClangDwarf5Rnglistx.binary_name("partitioned_ranges_program"),
495+
)])
496+
}
454497
}
455498
}
456499

@@ -462,14 +505,27 @@ fn command_available(name: &str) -> bool {
462505
.unwrap_or(false)
463506
}
464507

465-
fn preferred_clang_binary() -> Option<&'static str> {
466-
if command_available("clang-18") {
467-
Some("clang-18")
468-
} else if command_available("clang") {
469-
Some("clang")
470-
} else {
471-
None
508+
fn preferred_clang_binary() -> Option<String> {
509+
preferred_compiler_binary("CLANG_BIN", &["clang-18", "clang"])
510+
}
511+
512+
fn preferred_gcc_binary() -> Option<String> {
513+
preferred_compiler_binary("GCC_BIN", &["gcc"])
514+
}
515+
516+
fn preferred_compiler_binary(env_var: &str, candidates: &[&str]) -> Option<String> {
517+
if let Some(override_bin) = std::env::var_os(env_var) {
518+
let override_bin = override_bin.to_string_lossy().trim().to_string();
519+
if !override_bin.is_empty() {
520+
return command_available(&override_bin).then_some(override_bin);
521+
}
472522
}
523+
524+
candidates
525+
.iter()
526+
.copied()
527+
.find(|name| command_available(name))
528+
.map(str::to_string)
473529
}
474530

475531
fn fixture_binary_path(fixture_name: &str, binary_name: &str) -> PathBuf {
@@ -985,7 +1041,9 @@ static COMPILE_RUST_GLOBAL: Once = Once::new();
9851041
static COMPILE_INLINE_CALLSITE_DEFAULT: Once = Once::new();
9861042
static COMPILE_INLINE_CALLSITE_CLANG_DWARF5: Once = Once::new();
9871043
static COMPILE_INLINE_CALL_VALUE: Once = Once::new();
988-
static COMPILE_PARTITIONED_RANGES: Once = Once::new();
1044+
static COMPILE_PARTITIONED_RANGES_DEFAULT: Once = Once::new();
1045+
static COMPILE_PARTITIONED_RANGES_GCC_DWARF5_FUNCTION_SECTIONS: Once = Once::new();
1046+
static COMPILE_PARTITIONED_RANGES_CLANG_DWARF5_RNGLISTX: Once = Once::new();
9891047
static COMPILE_CPP_COMPLEX: Once = Once::new();
9901048
static COMPILE_STATIC_SCOPE_DEFAULT: Once = Once::new();
9911049
static COMPILE_STATIC_SCOPE_CLANG_DWARF5: Once = Once::new();
@@ -1118,6 +1176,12 @@ fn ensure_inline_callsite_program_compiled(compiler: FixtureCompiler) -> anyhow:
11181176
&COMPILE_INLINE_CALLSITE_CLANG_DWARF5,
11191177
&*COMPILE_INLINE_CALLSITE_CLANG_DWARF5_RESULT,
11201178
),
1179+
_ => {
1180+
anyhow::bail!(
1181+
"Compiler override {} is not wired for inline_callsite_program",
1182+
compiler.description()
1183+
)
1184+
}
11211185
};
11221186

11231187
once.call_once(|| {
@@ -1175,9 +1239,43 @@ fn ensure_inline_call_value_program_compiled() -> anyhow::Result<()> {
11751239
}
11761240
}
11771241

1178-
fn ensure_partitioned_ranges_program_compiled() -> anyhow::Result<()> {
1179-
COMPILE_PARTITIONED_RANGES.call_once(|| {
1180-
let compile_result = (|| -> anyhow::Result<()> {
1242+
fn ensure_partitioned_ranges_program_compiled(compiler: FixtureCompiler) -> anyhow::Result<()> {
1243+
let (once, slot): (&Once, &Mutex<Option<anyhow::Result<()>>>) = match compiler {
1244+
FixtureCompiler::Default => (
1245+
&COMPILE_PARTITIONED_RANGES_DEFAULT,
1246+
&*COMPILE_PARTITIONED_RANGES_DEFAULT_RESULT,
1247+
),
1248+
FixtureCompiler::GccDwarf5FunctionSections => (
1249+
&COMPILE_PARTITIONED_RANGES_GCC_DWARF5_FUNCTION_SECTIONS,
1250+
&*COMPILE_PARTITIONED_RANGES_GCC_DWARF5_FUNCTION_SECTIONS_RESULT,
1251+
),
1252+
FixtureCompiler::ClangDwarf5Rnglistx => (
1253+
&COMPILE_PARTITIONED_RANGES_CLANG_DWARF5_RNGLISTX,
1254+
&*COMPILE_PARTITIONED_RANGES_CLANG_DWARF5_RNGLISTX_RESULT,
1255+
),
1256+
_ => {
1257+
anyhow::bail!(
1258+
"Compiler override {} is not wired for partitioned_ranges_program",
1259+
compiler.description()
1260+
)
1261+
}
1262+
};
1263+
1264+
once.call_once(|| {
1265+
let compile_result = compile_partitioned_ranges_program(compiler);
1266+
*slot.lock().unwrap() = Some(compile_result);
1267+
});
1268+
1269+
match slot.lock().unwrap().as_ref() {
1270+
Some(Ok(())) => Ok(()),
1271+
Some(Err(e)) => Err(anyhow::anyhow!("{e}")),
1272+
None => panic!("Compilation result should be set after call_once"),
1273+
}
1274+
}
1275+
1276+
fn compile_partitioned_ranges_program(compiler: FixtureCompiler) -> anyhow::Result<()> {
1277+
match compiler {
1278+
FixtureCompiler::Default => {
11811279
let base = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
11821280
.join("tests/fixtures/partitioned_ranges_program");
11831281
if let Some(result) = use_precompiled_outputs(
@@ -1187,11 +1285,6 @@ fn ensure_partitioned_ranges_program_compiled() -> anyhow::Result<()> {
11871285
return result;
11881286
}
11891287
println!("Compiling partitioned_ranges_program (Optimized O3) in {base:?}");
1190-
let _ = Command::new("make")
1191-
.arg("clean")
1192-
.current_dir(base.clone())
1193-
.status()
1194-
.is_ok();
11951288
let out = Command::new("make").arg("all").current_dir(base).output()?;
11961289
if out.status.success() {
11971290
println!("✓ Successfully compiled partitioned_ranges_program");
@@ -1203,14 +1296,21 @@ fn ensure_partitioned_ranges_program_compiled() -> anyhow::Result<()> {
12031296
stderr
12041297
))
12051298
}
1206-
})();
1207-
*COMPILE_PARTITIONED_RANGES_RESULT.lock().unwrap() = Some(compile_result);
1208-
});
1209-
1210-
match COMPILE_PARTITIONED_RANGES_RESULT.lock().unwrap().as_ref() {
1211-
Some(Ok(())) => Ok(()),
1212-
Some(Err(e)) => Err(anyhow::anyhow!("{e}")),
1213-
None => panic!("Compilation result should be set after call_once"),
1299+
}
1300+
FixtureCompiler::GccDwarf5FunctionSections => compile_c_make_fixture(
1301+
"partitioned_ranges_program",
1302+
compiler,
1303+
"-Wall -Wextra -gdwarf-5 -O3 -DNDEBUG -ffunction-sections -freorder-blocks-and-partition",
1304+
),
1305+
FixtureCompiler::ClangDwarf5Rnglistx => compile_c_make_fixture(
1306+
"partitioned_ranges_program",
1307+
compiler,
1308+
"-Wall -Wextra -gdwarf-5 -O3 -DNDEBUG -ffunction-sections -fbasic-block-sections=all",
1309+
),
1310+
_ => anyhow::bail!(
1311+
"Compiler override {} is not wired for partitioned_ranges_program",
1312+
compiler.description()
1313+
),
12141314
}
12151315
}
12161316

@@ -1255,7 +1355,7 @@ fn ensure_cpp_complex_program_compiled() -> anyhow::Result<()> {
12551355
pub(crate) fn compile_c_make_fixture(
12561356
fixture_name: &str,
12571357
compiler: FixtureCompiler,
1258-
clang_dwarf5_cflags: &str,
1358+
compiler_cflags: &str,
12591359
) -> anyhow::Result<()> {
12601360
let base = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
12611361
.join("tests/fixtures")
@@ -1273,7 +1373,7 @@ pub(crate) fn compile_c_make_fixture(
12731373
);
12741374

12751375
let mut cmd = Command::new("make");
1276-
compiler.apply_to_c_make(&mut cmd, fixture_name, clang_dwarf5_cflags);
1376+
compiler.apply_to_c_make(&mut cmd, fixture_name, compiler_cflags);
12771377
let output = cmd.current_dir(base).output().map_err(|e| {
12781378
anyhow::anyhow!(
12791379
"Failed to run make for {fixture_name} {}: {}",
@@ -1308,6 +1408,12 @@ fn ensure_static_scope_program_compiled(compiler: FixtureCompiler) -> anyhow::Re
13081408
&COMPILE_STATIC_SCOPE_CLANG_DWARF5,
13091409
&*COMPILE_STATIC_SCOPE_CLANG_DWARF5_RESULT,
13101410
),
1411+
_ => {
1412+
anyhow::bail!(
1413+
"Compiler override {} is not wired for static_scope_program",
1414+
compiler.description()
1415+
)
1416+
}
13111417
};
13121418

13131419
once.call_once(|| {
@@ -1340,6 +1446,12 @@ fn ensure_entry_value_recovery_program_compiled(compiler: FixtureCompiler) -> an
13401446
&COMPILE_ENTRY_VALUE_RECOVERY_CLANG_DWARF5,
13411447
&*COMPILE_ENTRY_VALUE_RECOVERY_CLANG_DWARF5_RESULT,
13421448
),
1449+
_ => {
1450+
anyhow::bail!(
1451+
"Compiler override {} is not wired for entry_value_recovery_program",
1452+
compiler.description()
1453+
)
1454+
}
13431455
};
13441456

13451457
once.call_once(|| {

0 commit comments

Comments
 (0)