A function type linked at an address has no pf format, and the
disassembly loop skipped the instruction entirely instead of falling
through to disassemble it.
A typedef like "typedef char *string" is a pointer with no star in its
name, so r_anal_type_bitsize measured it from the sdb instead of using
the target word size. Resolve the typedef chain first and fail closed
on cycles.
The test recorded `arg int64_t arg2 @ rsi` alongside the DWARF-named formals.
Current master no longer reports it, and does not with this branch's commits
removed either, so the line describes behaviour that changed upstream after
the test was written rather than anything this branch does.
Verified by building master alone at the same fixture and address: the output
is identical apart from that line. The full suite on this branch is 17017 OK
with one failure, `db/formats/dwarf "DWARF mismatch preserves registered type
and stable name"`, which fails on master unchanged.
arg_index counts placed arguments and must stay dense, because
apply_debug_info stops reading at the first missing fcn.%s.arg.%d key.
It was also passed as the formal's ABI position, so the two diverged the
moment a formal was skipped, and every later fallback was handed its
neighbour's register. Count non-result formals separately and pass that
as argno; argc now counts non-result formals too, which is what feeds
the stack-offset math for reverse conventions.
The calling convention tables describe integer slots only, so a float
formal without a location was placed in an integer register it never
occupies, colliding with a located argument sitting there. Skip the
fallback for floating-point and complex types instead.
On bins/elf/dwarf_go_tree that removes four float64 and three complex128
arguments from integer registers, and without the argno fix the removal
shifts twelve later arguments down a slot.
Read DW_AT_variable_parameter through the flag union member the form
parsers actually write, rather than uconstant.
db/anal, db/cmd/dwarf and db/cmd/dwarf2 are 910 OK, 35 BR, 0 XX, 3 SK,
1 FX. The added test is 19/19 with the change and 18 OK, 1 XX without.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A formal parameter can carry a name and a type but no DW_AT_location,
which happens routinely at -O2 when the parameter is never spilled.
sdb_variable_data() returns NULL without a location, so the argument was
skipped, while the function type is still built from every formal. The
two disagreed on arity: the prototype listed a parameter that no argument
existed for.
Derive the missing storage from the calling convention instead of
discarding the parameter. r_anal_cc_argslot() already answers where the
caller leaves parameter N on entry.
Skip a formal that carries DW_AT_variable_parameter. Go encodes a
function's result slots as formal parameters with that flag set, so
without the check the fallback handed them entry registers they never
occupy, and reflect.maplen(h *hmap) int gained a second argument
named ~r1.
On bins/elf/dwarf_rust_bubble:
before void dbg.begin_panic_str_ (int64_t arg1, int64_t arg2, int64_t arg3);
after void dbg.begin_panic_str_ (&str msg, int64_t arg2, int64_t arg3);
db/anal, db/cmd/dwarf and db/cmd/dwarf2 are 909 OK, 35 BR, 0 XX with the
change. The new test fails without it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A write to a `w` register clears the top half of the `x` register it sits
in. ESIL does not do that on its own: naming `w9` stores four bytes and
leaves the rest of `x9` as it was, so
ar x9=0xffffffff00000001
ar x10=1
wx 29010a0b ; add w9, w9, w10
aes; ar x9
before 0xffffffff00000002
after 0x2
The same held for every `w` destination: the arithmetic helpers, the
loads, the moves. It is appended once where the instruction's ESIL is
finished rather than at each of the sites that spell a destination, and
after the flag assignments so the extension cannot disturb the comparison
state they read. Storing through the 64-bit name clears the top half
without reading it, so `aea` still reports only what is really read.
Five expectations move, all because a 32-bit write now fully defines its
register and the type backtrace can follow it:
- db/anal/types: `mov w0, 1` picks up `int fd`
- db/anal/jmptbl: the three CCCrypt argument registers pick up their
parameter types, which is what that test is named for
- db/cmd/charset: `arg1` moves from `add x0, sp, 0x28` to the `ldr w0`
that actually sets the register the call reads, the `add` result being
consumed by `mov x1, x0` for `arg2`; and `mov w1, 0x63` picks up `arg2`
for `WriteAddress_DWORD(long, int)`
The full r2r suite is 17001 OK, 1043 BR, 1 XX, 30 SK, 33 FX; the single
failure, db/formats/mangling, fails identically without this change.
The x86-64 counterpart landed as e3d433fb8e.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>