Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//! (kuna `libgccsigs`) Compiler-runtime contracts whose integer widths come from
//! machine modes, not the host C data model. Off by default: a caller that
//! returns arithmetic on the locked eight-byte quotient still loses a word.
//!
//! `__divdi3` is `di_int (di_int, di_int)`, with `di_int = int64_t`:
//! https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/divdi3.c
//! https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/int_types.h

use object::{Architecture, BinaryFormat, Object};

use super::{seed_named_prototypes, seed_resolved_prototypes, Sig, Ty, L};
use crate::pass::{AnalysisCtx, AnalysisOutput, AnalysisPass, Phase};

const SIGNATURES: &[(&str, Sig)] = &[
("__divdi3", Sig { ret: Ty::Int64, params: &[Ty::Int64, Ty::Int64], vararg: -1 }),
];

pub struct LibgccSigsPass;

impl AnalysisPass for LibgccSigsPass {
fn phase(&self) -> Phase {
Phase::P1
}

fn id(&self) -> &'static str {
"libgccsigs"
}

/// Seed the evidenced SPARC32 ELF runtime ABI without retyping other targets.
fn run(&self, ctx: &AnalysisCtx) -> AnalysisOutput {
let mut out = AnalysisOutput::default();
if ctx.file.format() != BinaryFormat::Elf
|| !matches!(ctx.file.architecture(), Architecture::Sparc | Architecture::Sparc32Plus)
|| ctx.arch.get_description() != "sparc:BE:32:default:default"
{
return out;
}
let (imports, reloc_imports) = super::loaded_import_addrs(ctx.file, ctx.bytes, ctx.image);
let names = super::loaded_function_names(ctx.file, ctx.bytes, &reloc_imports, false);
let types = ctx.arch.types();
let (_, word_size) = ctx.arch.data_org();
seed_named_prototypes(&mut out, &names, SIGNATURES, types, word_size, L);
seed_resolved_prototypes(&mut out, &imports, SIGNATURES, types, word_size, L);
out
}
}
11 changes: 7 additions & 4 deletions decompiler/crates/kuna-analysis/src/analyzers/protos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use kuna_decomp::fspec::PrototypePieces;

use crate::pass::{AnalysisCtx, AnalysisOutput, AnalysisPass, Phase};

pub mod kuna_libgcc;
mod kuna_libcnames;
pub mod kuna_libcsigs;
pub mod kuna_libctypes;
Expand All @@ -49,10 +50,9 @@ pub struct LibProtoPass;

/// A primitive type slot in a built-in libc signature.
///
/// Every variant is **width-stable**: it is either `void`, exactly 4 bytes, or
/// exactly pointer-width on every ILP32/LP64 target. A C type that is neither
/// (`off_t`, `time_t`, `long long`, `char`/`short` parameters) has no spelling
/// here on purpose — see [`kuna_libcsigs`].
/// Integer slots are four bytes or pointer-width for libc declarations. Compiler
/// runtime machine-mode contracts can additionally state an exact eight-byte
/// integer; that does not establish the width of libc `long long` parameters.
#[derive(Clone, Copy)]
enum Ty {
/// `void` (return only).
Expand All @@ -65,6 +65,8 @@ enum Ty {
Size,
/// `ssize_t` / `long` / `ptrdiff_t` (pointer-width signed).
Long,
/// Signed DI-mode integer (exactly eight bytes in the compiler runtime ABI).
Int64,
/// `char *`.
CharPtr,
/// `char **`.
Expand Down Expand Up @@ -182,6 +184,7 @@ fn build_ty(
Ty::UInt => types.get_base(4, type_metatype::TYPE_UINT),
Ty::Size => types.get_base(ptr, type_metatype::TYPE_UINT),
Ty::Long => types.get_base(ptr, type_metatype::TYPE_INT),
Ty::Int64 => types.get_base(8, type_metatype::TYPE_INT),
Ty::CharPtr => {
let c = types.get_type_char(types.get_size_of_char())?;
types.get_type_pointer(ptr, c, word_size)
Expand Down
4 changes: 4 additions & 0 deletions decompiler/crates/kuna-analysis/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ pub fn passes_for(compiler: Compiler, format: object::BinaryFormat) -> Vec<Box<d
// `--option libcsigs on|off` via `engine.rs::analysis_pass_enabled`, so `off`
// is byte-identical to the base table alone.
Box::new(crate::protos::kuna_libcsigs::LibcSigsPass),
// S1 libgcc DI-mode contracts (`libgccsigs`): `long long __divdi3(long long,
// long long)` on SPARC32 BE ELF. Registered always; the COMMIT is gated by
// `--option libgccsigs on|off` (default off) via `analysis_pass_enabled`.
Box::new(crate::protos::kuna_libgcc::LibgccSigsPass),
// S1 built-in Win32 API signatures (`win32sigs`): the Windows half of the
// `.gdt` stand-in, which nothing in the tree carried. PE/COFF only, and
// keyed by ENTRY ADDRESS rather than by name -- a PE import is TWO
Expand Down
3 changes: 2 additions & 1 deletion decompiler/crates/kuna-base/src/xml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2113,7 +2113,8 @@ mod tests {
// and kuna-gowritebarrier / the Go GC write-barrier diamond folds (option gowritebarrier)
// and kuna-ppc-lwarx-reservation / PowerPC lwarx sets the reservation its stwcx. checks
// and kuna-ppc64-ldarx-encoding / generic PowerPC ldx and ldarx decode at their own opcodes
assert_eq!(count, 591, "corpus file count drifted");
// and kuna-sparc-delay-condition / a flag-writing delay slot cannot change its branch
assert_eq!(count, 592, "corpus file count drifted");
}

/// ~20 representative SLEIGH spec files across varied processors
Expand Down
6 changes: 6 additions & 0 deletions decompiler/crates/kuna-cli/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ mod local_stack_views;
#[path = "library_names.rs"]
mod library_names;

#[path = "libgcc_divdi3.rs"]
mod libgcc_divdi3;

#[path = "rettriangle_round_trip.rs"]
mod rettriangle_round_trip;

Expand Down Expand Up @@ -292,6 +295,9 @@ mod passthrough_own_return;
#[path = "pointer_table_strings.rs"]
mod pointer_table_strings;

#[path = "ppc64_delayed_constant_switch.rs"]
mod ppc64_delayed_constant_switch;

#[path = "powerpc_isa_selection.rs"]
mod powerpc_isa_selection;

Expand Down
Loading
Loading