From 61c2d21ac0dac1258bf1f82c07eeef0f02f4642b Mon Sep 17 00:00:00 2001 From: tamnd <1218621+tamnd@users.noreply.github.com> Date: Sun, 4 Oct 2026 02:41:12 +0700 Subject: [PATCH] rk sections-diff: list every difference with --all --- README.md | 2 +- crates/rk/src/cli.rs | 5 +++-- crates/rk/src/main.rs | 2 +- crates/rk/src/sections.rs | 21 +++++++++++++-------- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 3ce6fd3..263e7da 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ The reference compilers live in era containers built from `provision/eras` and p `rk config-diff`, `rk probes`, `rk flags-diff`, `rk demands` and `rk asm-inventory` read build directories and write markdown tables: the `.config` differences, the compiler probes the two compilers answered differently, the flags each unit was compiled with on one side only (read from the `.cmd` files kbuild writes), the failed units by error, and the instructions the kernel writes itself. `rk config-diff --why` also names the Kconfig expressions behind each difference and the probe that decided them, and needs the kernel tree, which it finds through `build.json` or `--source`. `rk syntax --build DIR --cc rucc` replays every unit of a reference build through rucc's front end with the reference's own command lines, `-fsyntax-only` for C and `-E` for assembly, and writes the failing units grouped by their first error. Units listed with an issue in `syntax-known.toml` are known failures, so the command fails only on new ones. -`rk sections-diff`, `rk symvers-diff`, `rk vec-audit`, `rk modules-audit` and `rk objtool-report` look at what the compilers produced. `rk sections-diff` compares the section names of every object two builds share, the size and relocation count of each kernel table (exports, jump labels, alternatives, exception fixups, initcalls and the rest), the call-site lists per function, and the `.modinfo` and `__ksymtab_strings` strings. `rk symvers-diff` compares `Module.symvers`, CRCs and namespaces included, and the global symbols of `System.map`. `rk vec-audit` decodes the x86-64 code of every unit built with `-mno-sse` or `-mgeneral-regs-only` and lists the vector and x87 instructions it finds, only those above the reference's count when given `--reference`. `rk modules-audit` fails on any module relocation the loader rejects, a wrong `vermagic` or an imported CRC that does not match `Module.symvers`. `rk objtool-report` buckets the objtool warnings of two build logs by message and function shape. `rk frames` compares the stack frame of every function in two builds made with `rk build --stack-usage`, which passes `KCFLAGS=-fstack-usage` so that each compiler writes a `.su` file next to every object. It fails on a function over `CONFIG_FRAME_WARN` that the reference keeps under it, and on a run time stack high water mark more than 10% above the reference's when both build directories have a `boot.log` from a kernel with `CONFIG_DEBUG_STACK_USAGE`. `rk sections-diff`, `rk vec-audit` and `rk frames` take `--save FILE` to keep what they read as JSON, and accept such a file in place of a build directory, which is how CI compares builds without moving their objects. +`rk sections-diff`, `rk symvers-diff`, `rk vec-audit`, `rk modules-audit` and `rk objtool-report` look at what the compilers produced. `rk sections-diff` compares the section names of every object two builds share, the size and relocation count of each kernel table (exports, jump labels, alternatives, exception fixups, initcalls and the rest), the call-site lists per function, and the `.modinfo` and `__ksymtab_strings` strings. It lists the first 60 differences, and every one with `--all`. `rk symvers-diff` compares `Module.symvers`, CRCs and namespaces included, and the global symbols of `System.map`. `rk vec-audit` decodes the x86-64 code of every unit built with `-mno-sse` or `-mgeneral-regs-only` and lists the vector and x87 instructions it finds, only those above the reference's count when given `--reference`. `rk modules-audit` fails on any module relocation the loader rejects, a wrong `vermagic` or an imported CRC that does not match `Module.symvers`. `rk objtool-report` buckets the objtool warnings of two build logs by message and function shape. `rk frames` compares the stack frame of every function in two builds made with `rk build --stack-usage`, which passes `KCFLAGS=-fstack-usage` so that each compiler writes a `.su` file next to every object. It fails on a function over `CONFIG_FRAME_WARN` that the reference keeps under it, and on a run time stack high water mark more than 10% above the reference's when both build directories have a `boot.log` from a kernel with `CONFIG_DEBUG_STACK_USAGE`. `rk sections-diff`, `rk vec-audit` and `rk frames` take `--save FILE` to keep what they read as JSON, and accept such a file in place of a build directory, which is how CI compares builds without moving their objects. The nightly workflow builds every pin in the current set on X64 with gcc-14 and with rucc, from `tinyconfig` and the test fragment, and runs `rk test` on boot, smoke and KUnit. When the rucc kernel fails a unit, `rk mixed` runs on the first one in the same job. The run's summary has a line per version, green or red, and what `rk mixed` found. A manual run takes a branch or commit of tamnd/rucc and another configuration target. diff --git a/crates/rk/src/cli.rs b/crates/rk/src/cli.rs index e5be285..c49820d 100644 --- a/crates/rk/src/cli.rs +++ b/crates/rk/src/cli.rs @@ -61,7 +61,8 @@ fn accepted(command: &str) -> Option<(bool, &'static [&'static str])> { "probes" | "flags-diff" | "symvers-diff" | "objtool-report" => { (false, &["reference", "other"]) } - "sections-diff" | "frames" => (false, &["reference", "other", "save"]), + "sections-diff" => (false, &["reference", "other", "save", "all"]), + "frames" => (false, &["reference", "other", "save"]), "vec-audit" => (false, &["build", "reference", "save"]), "modules-audit" => (false, &["build"]), "syntax" => (false, &["build", "cc", "allow", "jobs"]), @@ -152,7 +153,7 @@ usage: rk config-diff --reference DIR --other DIR [--why] [--source DIR] rk flags-diff --reference DIR --other DIR rk probes --reference DIR --other DIR - rk sections-diff --reference DIR|FILE [--other DIR|FILE] [--save FILE] + rk sections-diff --reference DIR|FILE [--other DIR|FILE] [--save FILE] [--all] rk symvers-diff --reference DIR --other DIR rk vec-audit --build DIR|FILE [--reference DIR|FILE] [--save FILE] rk modules-audit --build DIR diff --git a/crates/rk/src/main.rs b/crates/rk/src/main.rs index d212aa1..27a08bb 100644 --- a/crates/rk/src/main.rs +++ b/crates/rk/src/main.rs @@ -509,7 +509,7 @@ fn sections_diff(args: &Args) -> Result { } let other = objects::load_or_scan(std::path::Path::new(other), sections::scan)?; let comparison = sections::compare(&reference, &other); - print!("{}", sections::report(&comparison)); + print!("{}", sections::report(&comparison, args.has("all"))); Ok(verdict(comparison.clean())) } diff --git a/crates/rk/src/sections.rs b/crates/rk/src/sections.rs index 1daedd3..5eee205 100644 --- a/crates/rk/src/sections.rs +++ b/crates/rk/src/sections.rs @@ -592,9 +592,10 @@ fn cell(s: &str) -> String { } } -/// The comparison as markdown. +/// The comparison as markdown, with the first 60 differences or, with `all`, every one. #[must_use] -pub fn report(c: &Comparison) -> String { +pub fn report(c: &Comparison, all: bool) -> String { + let rows = if all { c.differences.len() } else { ROWS }; let mut s = String::from("### Sections and kernel tables\n\n"); let _ = writeln!( s, @@ -615,7 +616,7 @@ pub fn report(c: &Comparison) -> String { let _ = writeln!(s, "| `{what}` | {n} |"); } s.push_str("\n| object | what | reference only | other only |\n|---|---|---|---|\n"); - for d in c.differences.iter().take(ROWS) { + for d in c.differences.iter().take(rows) { let _ = writeln!( s, "| {} | {} | {} | {} |", @@ -625,8 +626,12 @@ pub fn report(c: &Comparison) -> String { cell(&d.other) ); } - if c.differences.len() > ROWS { - let _ = writeln!(s, "\nand {} more.", c.differences.len() - ROWS); + if c.differences.len() > rows { + let _ = writeln!( + s, + "\nand {} more, which `--all` lists.", + c.differences.len() - rows + ); } s.push('\n'); } @@ -725,8 +730,8 @@ mod tests { let c = compare(&reference, &other); let what: Vec<&str> = c.differences.iter().map(|d| d.what.as_str()).collect(); assert_eq!(what, ["__jump_table", "__mcount_loc in f", ".modinfo"]); - assert!(report(&c).contains("| a.o | __mcount_loc in f | 1 | 3 |")); - assert!(report(&c).contains("| a.o | __jump_table | 8=key1+0 | nothing |")); + assert!(report(&c, false).contains("| a.o | __mcount_loc in f | 1 | 3 |")); + assert!(report(&c, false).contains("| a.o | __jump_table | 8=key1+0 | nothing |")); } /// Two copies of one site, as when a function with a static branch is inlined twice. @@ -767,6 +772,6 @@ mod tests { let c = compare(&reference, &other); assert!(c.clean()); assert_eq!(c.only_reference, ["b.o"]); - assert!(report(&c).contains("Only in the reference: b.o")); + assert!(report(&c, false).contains("Only in the reference: b.o")); } }