Firmware Fn ResolveUnsetNodeID - krcenov/RNS510-Map-Viewer GitHub Wiki
ResolveUnsetNodeID — AdasDBAccess::ResolveUnsetNodeID
Part of Firmware Reversing.
- File offset:
0x828940(true prologue start; naive symbol-table field-4 address is0x828de8) - VA:
0xf70b6634(= 0x828940 + 0xf688dcf4) - Status: 🟢 Fully traced (largest/most complex of the 4 fully-traced functions; one boundary noted below is not 100% pinned down)
- Real name source: symbol/EH-descriptor table, loose match, true
start found by scanning backward from the naive target the same way
as
getNodeVidArmMP0
Not to be confused with resolveUnsetVNodeId
(LaneCalculation::resolveUnsetVNodeId) — a different class, different
address, and (unlike this function) unreachable.
Disassembly
0x828940: stwu r1, -0x30(r1)
0x828944: mflr r0
0x828948: stmw r29, 0x24(r1)
0x82894c: stw r0, 0x34(r1)
0x828950: mr r31, r3 ; arg1 = this
0x828954: lwz r0, 4(r31) ; read this+4 -- the "node id" field?
0x828958: cmpwi r0, 0
0x82895c: beq 0x82899c ; unset (==0) -> do real work below
0x828960: lis r9, -0x91c
0x828964: addi r0, r9, -0x52f4 ; computed call target (see below)
0x828968: addi r29, r1, 0x10
0x82896c: mtlr r0
0x828970: addi r4, r31, 0x28
0x828974: mr r3, r29
0x828978: blrl ; virtual call -- the actual resolve step
0x82897c: lwz r11, 4(r31)
0x828980: mr r4, r29
0x828984: lwz r9, 4(r11)
0x828990: lwz r0, 0x34(r1)
0x828994: mtlr r0
0x828998: lmw r29, 0x24(r1)
0x82899c: addi r1, r1, 0x30 ; already-set path also lands here
0x8289a8: stmw r28, 0x20(r1) ; a DIFFERENT function's own prologue starts
0x8289ac: stw r0, 0x34(r1) ; immediately after -- see caveat below
0x8289b0: mr r28, r3
0x8289b4: lwz r8, 8(r28)
0x8289c0: mr r31, r3
0x8289c4: mtlr r0
0x8289c8: mr r3, r28
0x8289d4: addi r29, r1, 0x10
0x8289d8: addi r28, r28, 0x28
0x8289e4: mr r4, r3
0x8289e8: lwz r9, 0(r4)
0x8289ec: mr r5, r31
0x8289f0: mr r3, r29
0x8289f4: lha r0, 0x18(r9)
0x8289f8: lwz r9, 0x1c(r9)
0x8289fc: add r4, r4, r0
0x828a00: mtlr r9
0x828a0c: mr r4, r29
0x828a10: mr r3, r28
0x828a1c: lwz r0, 0x34(r1)
0x828a20: mtlr r0
0x828a24: lmw r28, 0x20(r1)
0x828a28: addi r1, r1, 0x30
0x828a34: mr r30, r3
0x828a38: lwz r9, 0xc(r30)
0x828a3c: mr r31, r4
0x828a40: lha r3, 0x18(r9)
0x828a44: lwz r0, 0x1c(r9)
0x828a50: cmplw r31, r3
0x828a54: blt 0x828a74
0x828a58: lwz r9, 0xc(r30)
0x828a64: addi r31, r3, -1
0x828a68: lwz r0, 4(r30)
0x828a6c: slwi r3, r31, 2
0x828a70: add r3, r0, r3
0x828a7c: or. r30, r4, r4
0x828a80: mr r29, r3
0x828a84: li r3, 0
0x828a88: beq 0x828b2c
0x828a94: addi r4, r4, -0x7a4c
0x828a98: li r3, 0x18 ; sizeof() -- allocating a new node
0x828a9c: li r5, 0x19
0x828aa0: blrl ; virtual call -- allocator
0x828aa4: lwz r4, 0(r30)
0x828aa8: mr r31, r3
0x828aac: lwz r11, 0x14(r30)
0x828ab0: cmpwi r4, 0
0x828ab4: lwz r0, 0x10(r30)
0x828ab8: lwz r9, 0xc(r30)
0x828abc: stw r11, 0x14(r3)
0x828ac0: stw r0, 0x10(r3)
0x828ac4: stw r9, 0xc(r31)
0x828ac8: beq 0x828aec
0x828acc: lis r9, -0x8b8
0x828ad0: addi r0, r9, 0x25fc
0x828ad4: mr r3, r29
0x828ad8: mtlr r0
0x828adc: blrl ; virtual call
0x828ae0: stw r3, 0(r31)
0x828ae4: stw r31, 8(r3)
0x828ae8: b 0x828af0
0x828aec: stw r4, 0(r31)
0x828af0: lwz r4, 4(r30)
0x828af4: cmpwi r4, 0
0x828b00: stw r3, 4(r31)
0x828b04: stw r31, 8(r3)
0x828b08: b 0x828b10
0x828b0c: stw r4, 4(r31)
0x828b10: mr r3, r31
0x828b20: addi r0, r9, -0x5f70
0x828b2c: blrl ; virtual call
0x828b30: lwz r0, 4(r29)
0x828b34: lis r9, -0x90f
0x828b38: stw r0, 4(r31)
0x828b3c: lis r4, -0x871
0x828b40: addi r0, r9, 0x1714
0x828b44: addi r4, r4, -0x7a4c
0x828b48: mtlr r0
0x828b54: stw r3, 8(r31)
0x828b58: li r0, 0
0x828b5c: lwz r9, 8(r29)
0x828b60: stw r0, 0xc(r3)
0x828b64: lwz r4, 8(r9)
0x828b68: cmpwi r4, 0
0x828b6c: bne 0x828b80
0x828b70: stw r4, 8(r3)
0x828b74: stw r3, 0(r3)
0x828b78: stw r3, 4(r3)
0x828b7c: b 0x828be0
0x828b80: lis r9, -0x8b8
0x828b84: addi r0, r9, 0x25fc
0x828b90: lwz r9, 8(r31)
0x828b94: stw r3, 8(r9)
0x828b98: stw r9, 8(r3)
0x828b9c: lwz r11, 8(r9)
0x828ba0: b 0x828ba8
0x828ba4: lwz r11, 0(r11) ; tree/list walk loop
0x828ba8: lwz r0, 0(r11)
0x828bac: cmpwi r0, 0
0x828bb0: bne 0x828ba4
0x828bb4: lwz r9, 8(r31)
0x828bb8: lwz r10, 8(r9)
0x828bbc: stw r11, 0(r9)
0x828bc0: b 0x828bc8
0x828bc4: lwz r10, 4(r10)
0x828bc8: lwz r0, 4(r10)
0x828bd4: stw r10, 4(r9)
0x828be0: addi r0, r9, -0x5e84
0x828be4: mr r29, r3
0x828be8: mtlr r0
0x828bec: lwz r3, 0(r29)
0x828bf8: li r5, 0x147
0x828bfc: addi r4, r4, -0x7370
0x828c08: lwz r4, 0(r29)
0x828c0c: addi r0, r9, 0x26d0
0x828c10: mtlr r0
0x828c14: blrl ; virtual call
0x828c18: stw r3, 0(r29)
0x828c24: lwz r11, 0(r3)
0x828c28: lwz r0, 4(r11)
0x828c2c: cmpwi r0, 0
0x828c30: beq 0x828c5c
0x828c34: mr r11, r0
0x828c38: lwz r0, 0(r11)
0x828c3c: cmpwi r0, 0
0x828c40: beq 0x828c88
0x828c4c: b 0x828c80
0x828c50: mr r11, r9
0x828c54: lwz r9, 8(r11)
0x828c58: lwz r0, 4(r9)
0x828c5c: cmpw r11, r0
0x828c60: beq 0x828c50 ; tree-rotation-shaped pointer fixup
0x828c64: lwz r0, 4(r11)
0x828c68: xor r0, r0, r9
0x828c6c: addic r0, r0, -1
0x828c70: subfe r0, r0, r0
0x828c74: andc r9, r9, r0
0x828c78: and r0, r11, r0
0x828c7c: or r11, r0, r9
0x828c80: stw r11, 0(r3)
0x828c84: li r3, 0
0x828c88: blr
(interstitial non-instruction words — EH-descriptor table entries, same pattern as elsewhere in this file — omitted from the listing above for readability; every one was checked and confirmed to decode as invalid, not silently skipped.)
Analysis
Reads offset+4 of its own argument and checks it against zero —
consistent with a "resolved node id" field, matching the function's own
name. If already set, execution falls through to 0x82899c and pops
the stack frame — but does not reach a local blr there; it lands
directly on what looks like a SEPARATE function's own prologue
(stmw r28,0x20(r1) at 0x8289a8) with no call instruction in
between, consistent with a real GCC tail-call optimization (reusing
the frame pop, falling straight into the next routine using the
original caller's own link register) rather than a simple return. This
means the exact boundary between ResolveUnsetNodeID and whatever
starts at 0x8289a8 is NOT fully pinned down — flagged honestly rather
than assumed.
If unset, makes a virtual call (0x828978) passing this+0x28, then —
after re-reading the result — performs substantial pointer/tree
manipulation: an li r3,0x18/li r5,0x19 pair immediately before a
virtual call (0x828aa0) looks like a real sizeof+alignment pair
feeding an allocator (allocating a 0x18-byte node), followed by linked
pointer field stores (0(r31)/4(r31)/8(r31)) and a loop
(0x828ba4-0x828bb0) walking a chain via lwz r11,0(r11) until a
NUL terminator, then more pointer rewiring using a branchless XOR-based
conditional-swap idiom (0x828c64-0x828c7c) — the same general shape
a red-black-tree or similar self-balancing structure's insert/rotate
step would take. Consistent with "if this node's id hasn't been
resolved yet, compute it and insert the result into a cache/index
structure."
Callees
None of its own virtual-call targets have been checked yet — a concrete next step, though a deep one given how many calls this function alone makes.