Repository navigation
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.
- 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.
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 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.
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.
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.)
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.
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.
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).
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.
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.
-
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.
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).
Road network
- eeu.rd
- eeu.il
- eeu.iof
- eeu.typ
- rt / rl / prl
- eeu.si (segment classification)
- eeu.tmc (TMC traffic data)
Places
- eeu.ctr
- cty / cl / ct
- eeu.cny (counties)
- eeu.stt (states/regions)
- eeu.ti (time-info/DST)
- pmc / pmm (postal-code merge)
- pol / pot / pmp (postal-code, empty)
Language / TTS support
- eeu.abc (alphabet)
- eeu.aff (affix)
- eeu.cal (country names)
- eeu.cat (country bboxes)
- prd (road phonetics)
- pct (city phonetics)
- pcl (phoneme cluster list)
- pca (country phonemes)
Map tiles
Container formats
Cross-cutting
- eeu.mod (schema dictionary)
- Road naming join
- Header trailer fields
- Map viewer tool
- Road editor tool
- Unexamined files
- Disc-root build script & subsystems
Firmware reversing