eeu iof Parallel Road Array - krcenov/RNS510-Map-Viewer GitHub Wiki
eeu.iof โ Parallel Road Array
Status: ๐ก Partially cracked ยท 52.8 MB ยท NOT_COMPRESSED ยท A real
"nearby street names" pointer mechanism is now cracked and validated for a
0.36% subset of records; which records become that 0.36% is substantially
narrowed (route-numbered roads strongly enriched); the common case's own
count field remains open. A later session disassembled real firmware
code (not just symbol names) and confirmed the real struct is called
IOF_Record, all 3 fields have real firmware names (offset/count/
type, the latter an IlTypeFlag_e enum), and type's real role is a
tri-state cache/resolution flag, not a simple classifier โ see "Cracked
via real DBAL.OUT disassembly" below.
A fixed per-record array parallel to eeu.rd โ same 94-byte header, then
one 6-byte record per road record, in the same order.
Layout
- Same 94-byte header.
- Fixed 6-byte records, exactly the same count as
eeu.rd((filesize - 94) / 6matcheseeu.rd's own record count). [uint32 LE "zero4"][uint8 "vb"][uint8 "c80"].
The earlier [00 00 00 00][varying byte][0x80 constant] sketch (from only
15 hand-checked records) turns out to describe just the common case โ at
full-file scale (8,809,081 records) neither zero4 nor c80 is a true
constant.
Cracked: the .il "nearby street names" pointer
For 31,318 records (0.3555%), zero4 is nonzero โ and it is an
absolute byte offset into eeu.il. vb, for these same records, is a
count of consecutive .il entries to read starting at that offset.
Together: one road's own list of other nearby street names.
Validated directly against the real ISO:
- 858/1000 randomly sampled
zero4values land byte-exact on a real, parseableeeu.ilentry (the[11-byte prefix][name][0x00]format already cracked foreeu.il) โ of those, 100% resolve, via the entry's own embeddedeeu.rdindex, to a real road whose name matches the entry's own string. - Chaining exactly
vbsuch entries fromzero4and validating every one the same way succeeds end-to-end for the large majority of a 500-record sample. - Geographic clustering โ every one of 30 random anchors: every entry
in an anchor's list resolves to a real
eeu.rdrecord within a few km of the anchor's own coordinates.eeu.rdis not spatially sorted, so this clustering cannot be chance. - The anchor's own name is essentially never inside its own list (1/300 sampled) โ a list of other nearby roads, not self-inclusive.
- Anchor names are frequently bare route/highway codes rather than full
street names โ real examples:
R102,T0803,B32,L73,SS1,D-400,180.
Practical reading (unverified on hardware): this looks like a real
"pick an area, browse its street names" catalog โ independent evidence,
from a completely different file, for the same kind of destination-entry
UI need the road name-search catalog
(.rt/.rl/.prl) hypothesis addresses. Which mechanism (if either) the
real unit's own address-entry screen actually reads is unconfirmed.
eeu.mod's real field names
eeu.mod names this table
intersectionOffsetFile, with 4 real leaf fields: offset,
countAndType (a wrapper), type, count. Confirms/renames what was
already found: offset=zero4, count=vb. c80 is really type,
and its value shape now makes clean sense as a discriminator:
type=0x80 (bit 7 set) is the "no real anchor" default; confirmed
anchors show type in {0, 1} (bit 7 clear) โ plausibly bit 7 = "is
this a real offset/count pair", with 0/1 a genuine 2-valued sub-type for
real anchors. Not independently confirmed beyond this value-shape
observation.
Cracked via real DBAL.OUT disassembly: IOF_Record's real fields and type's real meaning
A still later session went beyond debug-string name matching and actually
disassembled real firmware code. dbal/V010_015/DBAL.OUT (research/
dbal_reader.py) is a small, UNLINKED ET_REL PowerPC object โ unlike the
main FHDD6.FLI application image (where known function names like
db_seg_rank_V004 fall outside the disassemblable region, the project's
long-standing "disassembly wall"), this file's ELF section table
(.text/.rela.text/.data/.rela.data/.bss/.symtab/.strtab, no
.debug_* sections) shows every function's FULL machine code is physically
present in the same file, addressed as plain .text-relative offsets โ
nothing to recover, nothing missing. Used capstone (CS_ARCH_PPC,
big-endian, 32-bit) directly against raw .text bytes located via a
hand-rolled ELF32 BE section/symbol-table parser (no external tool needed).
A much richer string vein than previously found for this file: the
same printable-string scan that found db_intersection*.cpp (already
documented above) also found, in this later pass, the literal on-disk
struct name and real field-accessor functions:
db_get_intersection_offset_rec__FP23dbIntersectionCacheInfoUlP10IOF_Record
unpack_intersection_offset_rec__FP10IOF_Record
db_get_minor_road_list_offset__FP23dbIntersectionCacheInfoUlPUl
db_get_minor_road_list_type__FP23dbIntersectionCacheInfoUlP12IlTypeFlag_e
db_get_minor_road_count_V000 / _r_V005 / _intern
db_get_crossstreet_offset__FP23dbIntersectionCacheInfoUliRUl
db_init_cross_street_offset_memory__FP23dbIntersectionCacheInfoUlUli
db_minor_road_cache_get_status__FP16IntersectionListUl
db_minor_road_cache_get_rec_count__FP16IntersectionListUl
(demangled, CFront/old-GCC convention โ __F starts the parameter list,
P=pointer, R=reference, Ul=unsigned long, i=int,
Uc=unsigned char). This independently CONFIRMS (not just renames) the
already-cracked on-disk layout: the real struct is IOF_Record, and this
file's real-world feature is a "minor road"/"cross street" lookup โ
exactly the "pick a road, browse its nearby cross streets" UI need this
page already guessed at, now confirmed by the actual function names.
The real field mapping, confirmed by reading the actual code
db_get_intersection_offset_rec(dbIntersectionCacheInfo*, roadID, IOF_Record* out) reads one on-disk record (via unpack_intersection_offset_ rec) into a 12-byte in-memory struct โ unpack_intersection_offset_rec
itself opens with a call matching memset(out, 0, 12) (args (ptr, 0, 0xc)
seen directly in the disassembly), then populates 3 words via a generic,
schema-driven field-reader object (a virtual call through a "this"-adjusted
vtable โ consistent with eeu.mod's own Arriba-generated reflection
system, not code specific to this one file):
| In-memory offset | Confirmed by | = on-disk field |
|---|---|---|
+0x0 |
db_get_minor_road_list_type copies this word straight into its IlTypeFlag_e* output arg, no masking |
type (byte [5], "c80") |
+0x4 |
db_get_minor_road_count_r_V005 copies this word into its count output arg (lwz r0,0x14(r1) / stw r0,0(r26)) |
count (byte [4], "vb") |
+0x8 |
db_get_minor_road_list_offset copies this word into its offset output arg (lwz r0,0x18(r1) / stw r0,0(r30)) |
offset (bytes [0:4], "zero4") |
(The in-memory order is reversed from on-disk byte order โ expected for a schema-driven unpacker that reorders sub-fields for alignment/convenience; doesn't change which on-disk bytes mean what, already nailed empirically.)
type's real semantics: a validity + cache-resolution-state flag, not a simple classifier
db_get_minor_road_list_offset directly disassembled: after unpacking
a record, it checks if (type != 0) return -1 (error), and only returns
the real offset word when type == 0 exactly. This is a real,
code-level confirmation that type gates whether offset means anything
โ consistent with (and sharper than) this page's own earlier empirical
finding that confirmed anchors show type in {0, 1} while the
overwhelming non-anchor default is 0x80.
db_get_minor_road_count_r_V005 disassembled goes further and reveals
type is not just a 2-way valid/invalid flag:
type == 0: the on-diskcountword (+0x4above) is returned AS-IS.type == 1: after returning the on-diskcount, the function makes 2 MORE calls โ matchingdb_minor_road_cache_get_status__FP16Intersection ListUl(compared against magic values0/2, a classic not-loaded/loading/ready tri-state) then, only if status== 2,db_minor_road_cache_get_rec_count__FP16IntersectionListUlโ and OVERWRITES the count just returned with THIS call's result instead.- any other
typevalue (the0x80default included): already rejected upstream bydb_get_minor_road_list_offset's owntype != 0check โ no valid list at all, consistent with the already-known ~99.64% non-anchor majority.
Real, concrete meaning: type == 0 records carry a statically-correct
count baked into the disc; type == 1 records carry only a PROVISIONAL
on-disk count that the firmware deliberately discards and recomputes from
a separate, dynamically-built in-memory cache (IntersectionList) once
that cache has finished loading. This gives a genuine, code-level reason
why this page's own earlier full-file correlation work (below) only ever
found a WEAK relationship between the raw on-disk count byte and any
other file's reference counts for anchor records โ for at least the
type == 1 subset, the firmware itself doesn't fully trust the stored
byte either, and recomputes the real figure from runtime data this project
has no static copy of.
Tested and refuted, a genuinely different mechanism than hoped: before
this disassembly, the natural guess was "type selects between 2 kinds of
list โ minor roads vs. cross streets." db_get_crossstreet_offset was
disassembled directly to check this, and it is NOT a type-gated sibling
of db_get_minor_road_list_offset at all โ it never calls db_get_ intersection_offset_rec or touches an IOF_Record. Instead it indexes a
completely separate in-memory array (a road-ID-keyed hash/cache built by
db_init_cross_street_offset_memory, lazily populated on first miss) โ
"cross street" is a distinct, separately-cached derived feature built on
top of this data, not a second raw value multiplexed through the type
byte.
Not pursued further
The generic schema-driven field-reader (the virtual call inside unpack_ intersection_offset_rec that does the ACTUAL byte-level unpacking/
bit-masking) was not traced into its own function body โ it's shared
machinery for every eeu.mod-schema table on this disc, not eeu.iof-
specific, and disassembling it would be a project-wide undertaking, not a
one-file fix. Likewise IlTypeFlag_e's own enum CONSTANT names were not
recovered โ DBAL.OUT has no DWARF debug sections (confirmed directly
from its ELF section table), only .symtab linker names, so enum value
names (unlike function names) left no trace to find.
A later session's cross-reference attempts for the common-case count
Tested and correlates (real, moderate, not a clean formula): count
for zero4==0 (non-anchor) records correlates positively with how many
eeu.il entries reference that same
eeu.rd record elsewhere in the file โ Pearson r โ 0.21 over the
739,211 eeu.rd records eeu.il references at least once. Records
eeu.il references at all have roughly DOUBLE the mean/median count
of records it never references (mean 7.23 vs. 3.82; median 5 vs. 2). A
real, statistically significant signal โ not noise โ but not an exact
per-record formula either.
Tested and refuted: eeu.rd's own
unresolved bytes[1:5] does NOT correlate with count at full scale
(r โ -0.02, essentially zero) โ this also corrected that field's own
"~5 distinct patterns" claim to 6,174 distinct values at full scale
(no single value covers more than 0.41% of records). Also tested and
refuted: local road density (a coordinate-grid bucket count, ~100m
cells, over all 8,809,081 eeu.rd records, as a proxy for a literal
"intersection count" โ this file's own real name is
intersectionOffsetFile) shows only a weak correlation with count
(r โ 0.04-0.15).
A later session: which records become anchors, substantially narrowed
Tested and CONFIRMED (a real, strong, full-scale enrichment โ not a
clean 1:1 rule): anchor names were tested against a simple
"route-code-like" pattern (short, mostly-numeric, optional 1-4 letter
prefix โ B215/SP246/L1/SS18/331-shaped). At FULL FILE SCALE:
| route-like | total | % | |
|---|---|---|---|
All eeu.rd records |
528,463 | 8,809,081 | 6.00% |
| Anchor records | 14,031 | 31,318 | 44.80% |
| Non-anchor records | 514,432 | 8,777,763 | 5.86% |
Anchors are 7.5x more likely to have a route-code-like name โ a
real, large, full-scale-confirmed signal, visually obvious on
inspection (a random 40-anchor sample: B215, SP246, L551, L1,
T1810, SS18, N23, B96, L675, interleaved with genuine
settlement/street names like POBEDY, CHERNOMORSKIY, ROMA,
ALEXANDRU IOAN CUZA).
But NOT a clean 1:1 rule: of the 528,463 route-like-named records in
the whole file, only 2.66% (14,031) are anchors โ "has a route-code
name" is far from sufficient alone. Combined with the already-confirmed
geographic clustering and "anchor's own name almost never inside its
own list" findings above, the most consistent picture: anchors are a
curated, DEDUPLICATED subset โ roughly one anchor per distinct
real-world route/road identity, not one per eeu.rd SEGMENT (a single
real route like B215 gets many separate segment records along its
length, only a small fraction of which become the area's anchor). The
exact selection rule (which segment of a multi-segment route gets
picked, and what determines the remaining ~55% of settlement-name
anchors) is still not recovered.
A later session's 3rd count cross-reference, tested and refuted
eeuz.rl's own per-eeu.rd-index reference count (the
road name-search catalog's cracked
.rl bytes[0:4] "candidate index into eeu.rd" field, built the same
way as the eeu.il-reference-count correlation above โ np.bincount
over all 46,432,934 .rl records) shows, if anything, a slightly
NEGATIVE correlation with the common-case count (r โ -0.08 over all
8,809,081 records) โ weaker than even the weak eeu.il signal (r โ 0.21), and the wrong sign to be the same underlying quantity. .rl
covers a much larger fraction of eeu.rd (95.0%, 8,372,058/8,809,081
records referenced at least once) than .il (8.4%, 739,211 records) โ
consistent with .rl being a broad name-search index unrelated to
whatever count is actually counting.
Still open
- The common-case
count's exact meaning beyond theeeu.il- reference-count correlation above (now 3 hypotheses tested:eeu.ilreference count โ weak positive; local road density โ weak;eeuz.rlreference count โ weak negative, refuted). Its real range is 0โ255, heavily skewed toward small values (2/1/3/0/4 are the 5 most common,70% of records combined). Still fully open: the real DBAL.OUT disassembly below explains why
countcould legitimately NOT match any static cross-reference fortype == 1anchor records (the firmware discards the stored byte and recomputes it from a runtime cache this project has no static copy of) โ but the common case this item is about is the ~99.64%offset == 0/type == 0x80default population, a DIFFERENT subset the disassembly says nothing new about. - The exact anchor-selection rule beyond the route-number enrichment above โ which specific segment of a multi-segment route becomes the anchor, and what determines the remaining ~55% of settlement-name anchors.
โ substantially CLOSED (a still later session, real DBAL.OUT disassembly, see "Cracked via real DBAL.OUT disassembly" above):type's exact bit-level meaningtype == 0= statically-correct count/ offset, use as stored;type == 1= provisional on-disk count, firmware recomputes the real value from a liveIntersectionListcache once ready; anything else (the0x80default included) = no valid list, confirmed bydb_get_minor_road_list_offset's owntype != 0rejection. The rare 129โ255 outliers on the common-case side and 2โ7 on a few confirmed anchors remain individually unexplained โIlTypeFlag_e's own enum constant names didn't survive (DBAL.OUThas no DWARF debug sections, only linker symbol names).Whether an anchor's list is ordered by anythingโ CLOSED (a still later session): comprehensively tested and refuted. Beyond the earlier alphabetical check (16/100, inconclusive), 5 more orderings were tested on a real 60-anchor sample (countโฅ3): distance from the anchor โ 0/60; the list's owneeu.rdindex, ascending and descending โ 0/60 each; compass bearing from the anchor โ 0/60; name length, ascending and descending โ 0/60 each. Every plausible simple ordering is cleanly refuted, not just weakly โ zero exact matches across all 6 hypotheses. The list order is most likely a construction-time artifact (e.g. literal authoring/insertion order during the disc build), not something recoverable from the entries' own content.
Reader code
research/iof_reader.py โ read_iof_records(), analyze_iof(),
anchor_indices(), parse_il_entry(), nearby_street_entries(),
il_reference_counts(), is_route_like_name(). Full methodology and
every validation number are in its module docstring.
research/dbal_reader.py documents the string-level db_intersection*/
IOF_Record findings (its own module docstring has the full picture,
including the 5-version DBAL diff). The disassembly in "Cracked via real
DBAL.OUT disassembly" above was done ad hoc for this session (a short ELF32
big-endian section/symbol-table parser plus capstone
(CS_ARCH_PPC/CS_MODE_BIG_ENDIAN/CS_MODE_32) against dbal/V010_015/ DBAL.OUT's raw .text bytes) โ not saved as a new research/ module,
since it was a one-off targeted read of 5 specific functions rather than a
general-purpose reader; reproducible directly from the addresses/function
names cited above if a future session wants to go further (e.g. tracing
the generic schema-driven field-reader itself, or db_get_nearest_offset_ and_index, not pursued here).