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) / 6 matches eeu.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 zero4 values land byte-exact on a real, parseable eeu.il entry (the [11-byte prefix][name][0x00] format already cracked for eeu.il) โ€” of those, 100% resolve, via the entry's own embedded eeu.rd index, to a real road whose name matches the entry's own string.
  • Chaining exactly vb such entries from zero4 and 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.rd record within a few km of the anchor's own coordinates. eeu.rd is 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-disk count word (+0x4 above) is returned AS-IS.
  • type == 1: after returning the on-disk count, the function makes 2 MORE calls โ€” matching db_minor_road_cache_get_status__FP16Intersection ListUl (compared against magic values 0/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 type value (the 0x80 default included): already rejected upstream by db_get_minor_road_list_offset's own type != 0 check โ€” 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

  1. The common-case count's exact meaning beyond the eeu.il- reference-count correlation above (now 3 hypotheses tested: eeu.il reference count โ€” weak positive; local road density โ€” weak; eeuz.rl reference 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 count could legitimately NOT match any static cross-reference for type == 1 anchor 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 == 0x80 default population, a DIFFERENT subset the disassembly says nothing new about.

  2. 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.
  3. type's exact bit-level meaning โ€” substantially CLOSED (a still later session, real DBAL.OUT disassembly, see "Cracked via real DBAL.OUT disassembly" above): type == 0 = statically-correct count/ offset, use as stored; type == 1 = provisional on-disk count, firmware recomputes the real value from a live IntersectionList cache once ready; anything else (the 0x80 default included) = no valid list, confirmed by db_get_minor_road_list_offset's own type != 0 rejection. 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.OUT has no DWARF debug sections, only linker symbol names).
  4. 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 own eeu.rd index, 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).