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
Loading
Loading