From cce13b092f3d2959218638f38f9796fa12367b9b Mon Sep 17 00:00:00 2001 From: macabeus Date: Sun, 2 Aug 2026 15:30:05 +0100 Subject: [PATCH 1/3] feat(debug-info): report an array's RANK, not just its flat element count MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `variableShape()`'s array arm and `struct()`'s array members now carry `dims` — the per-dimension extents, outermost first. `length` is unchanged (still the product). Only `dims` answers the question a consumer spelling C has to answer: `g[i]` on a rank-2 array is a ROW, not an element. Knowing just the flat count you write one subscript, which against the project's own header is a type error — or, where the row address flows into an integer context, silently the wrong address. On a DW_AT_declaration a leading extent of 1 is GCC 2.95's unsized-outer-bound spelling (`extern T x[]`, `extern T x[][4]`) and reports null, mirroring the rule `length` already applies; the inner extents are written down and survive. A rank-1 array reports a one-entry `dims`, so an absent key always means "not an array", never "rank unknown". Fixtures: agbcc-min gains g_grid3 [2][3][4], the extern g_ext_grid[][4] idiom, and a 2-D struct member Grid.cells. --- packages/arm-emulator/CHANGELOG.md | 2 + packages/arm-emulator/package.json | 2 +- packages/debug-info/CHANGELOG.md | 22 +++++ packages/debug-info/package.json | 2 +- .../src/__tests__/producer-quirks.spec.ts | 44 +++++++++- .../src/__tests__/real-projects.spec.ts | 19 ++++- packages/debug-info/src/types.ts | 77 +++++++++++++++--- .../test-projects/agbcc-min/build/min.elf | Bin 9100 -> 9552 bytes .../test-projects/agbcc-min/build/oracle.json | 41 ++++++---- .../debug-info/test-projects/agbcc-min/crt0.s | 8 ++ .../debug-info/test-projects/agbcc-min/main.c | 23 ++++++ packages/gba-browser/CHANGELOG.md | 7 ++ packages/gba-browser/package.json | 2 +- packages/gba-emulator/CHANGELOG.md | 8 ++ packages/gba-emulator/package.json | 2 +- packages/gba-node/CHANGELOG.md | 7 ++ packages/gba-node/package.json | 2 +- packages/gba-react/CHANGELOG.md | 6 ++ packages/gba-react/package.json | 2 +- 19 files changed, 236 insertions(+), 40 deletions(-) diff --git a/packages/arm-emulator/CHANGELOG.md b/packages/arm-emulator/CHANGELOG.md index d82faa9..95e03f9 100644 --- a/packages/arm-emulator/CHANGELOG.md +++ b/packages/arm-emulator/CHANGELOG.md @@ -1,5 +1,7 @@ # @gba-kit/arm-emulator +## 0.5.0 + ## 0.4.0 ## 0.3.0 diff --git a/packages/arm-emulator/package.json b/packages/arm-emulator/package.json index 4a8a49d..67f3b7f 100644 --- a/packages/arm-emulator/package.json +++ b/packages/arm-emulator/package.json @@ -1,6 +1,6 @@ { "name": "@gba-kit/arm-emulator", - "version": "0.4.0", + "version": "0.5.0", "description": "ARM7TDMI CPU emulator supporting Thumb and ARM instruction sets", "author": "macabeus", "type": "module", diff --git a/packages/debug-info/CHANGELOG.md b/packages/debug-info/CHANGELOG.md index 821e43a..cd51e08 100644 --- a/packages/debug-info/CHANGELOG.md +++ b/packages/debug-info/CHANGELOG.md @@ -1,5 +1,27 @@ # @gba-kit/debug-info +## 0.5.0 + +### Minor Changes + +- Report an array's RANK, not just its flattened element count. + + `variableShape()`'s array arm and `struct()`'s array members now carry `dims` — the + per-dimension extents, outermost first (`u16 g[4][0x400]` → `[4, 1024]`). `length` is + unchanged: it stays the product, which is what sizes the object. + + The two readings answer different questions, and only `dims` answers the one a consumer + spelling C needs: `g[i]` on a rank-2 array is a **row**, not an element. A consumer that + knows only the flat count writes a single subscript, which against the project's own header + is either a type error or — where the row address flows into an integer context — silently + the wrong address. + + `null` marks an unbounded dimension. On a `DW_AT_declaration` a leading extent of 1 is + GCC 2.95's spelling of an unsized outer bound (`extern T x[]`, `extern T x[][4]`) and is + reported as `null`, mirroring the rule `length` already applies; the inner extents are + written down and survive. A rank-1 array reports a one-entry `dims`, so an absent key + always means "not an array", never "rank unknown". + ## 0.4.0 ### Minor Changes diff --git a/packages/debug-info/package.json b/packages/debug-info/package.json index 119ea95..defd34a 100644 --- a/packages/debug-info/package.json +++ b/packages/debug-info/package.json @@ -1,6 +1,6 @@ { "name": "@gba-kit/debug-info", - "version": "0.4.0", + "version": "0.5.0", "description": "Parse ELF symbols and DWARF debug info (line tables) for GBA decomp debugging", "author": "macabeus", "type": "module", diff --git a/packages/debug-info/src/__tests__/producer-quirks.spec.ts b/packages/debug-info/src/__tests__/producer-quirks.spec.ts index 43866be..089ec78 100644 --- a/packages/debug-info/src/__tests__/producer-quirks.spec.ts +++ b/packages/debug-info/src/__tests__/producer-quirks.spec.ts @@ -88,6 +88,7 @@ describe('3. the 0xffffffff upper bound means zero-length, never 2^32 elements', elemSize: 1, elemSigned: false, length: null, + dims: [null], // rank 1, the single extent unbounded volatile: false, const: false, }); @@ -96,7 +97,15 @@ describe('3. the 0xffffffff upper bound means zero-length, never 2^32 elements', it('a zero-length trailing member reads exactly like modern flexible arrays', () => { // Mirrors the devkitarm-min `Blob.data` pin: stride reported, size and length not. const data = agbcc.struct('Flex')!.members.find((m) => m.name === 'data')!; - expect(data).toEqual({ name: 'data', offset: 4, size: null, signed: null, elemSize: 1, elemSigned: false }); + expect(data).toEqual({ + name: 'data', + offset: 4, + size: null, + signed: null, + elemSize: 1, + elemSigned: false, + dims: [null], + }); expect(agbcc.resolveVariable('g_flex.data')).toBeNull(); }); @@ -117,6 +126,7 @@ describe('4. an unsized extern array is not [1]', () => { elemSize: 2, elemSigned: true, length: null, + dims: [null], // the rank IS known (1); only its extent is not volatile: false, const: true, }); @@ -128,8 +138,40 @@ describe('4. an unsized extern array is not [1]', () => { elemSize: 2, elemSigned: true, length: 1, + dims: [1], volatile: false, const: false, }); }); }); + +describe('5. an array RANK is not its element count', () => { + // `length` is the PRODUCT of the subranges, so it cannot say how many subscripts an + // element access takes — and `g[i]` on a `[2][3]` is a ROW, not an element. A consumer + // that only knows the flat count cannot spell an access that type-checks against the + // project's own header, which is exactly how a flattened rank surfaces: as a compile + // error in the world the header lives in, never as a wrong number. + it('reports every dimension of a fully-bounded array, outermost first', () => { + expect(agbcc.types.variableShape('g_grid3')).toMatchObject({ dims: [2, 3, 4], length: 24 }); + expect(agbcc.types.variableShape('g_init_table')).toMatchObject({ dims: [2, 2], length: 4 }); + expect(agbcc.types.variableShape('g_fwd_sized_table')).toMatchObject({ dims: [3, 2], length: 6 }); + }); + + it('a DECLARATION keeps its INNER extents and loses only the unsized outer one', () => { + // `extern const short g_ext_grid[][4];` — agbcc spells the outer bound as upper_bound 0 + // (indistinguishable from a real [1]), but the inner 4 IS written down, and the inner + // extents are the ones an element access needs. + expect(agbcc.types.variableShape('g_ext_grid')).toMatchObject({ dims: [null, 4] }); + }); + + it('reports the rank of an array MEMBER too', () => { + const cells = agbcc.struct('Grid')!.members.find((m) => m.name === 'cells')!; + expect(cells).toMatchObject({ offset: 4, size: 12, elemSize: 2, length: 6, dims: [2, 3] }); + }); + + it('control: a rank-1 array reports a one-entry rank, not none', () => { + // Absence of `dims` must mean "this is not an array", never "rank unknown" — a consumer + // gating on key presence would otherwise read every plain table as unranked. + expect(agbcc.types.variableShape('g_rom_table')).toMatchObject({ dims: [3] }); + }); +}); diff --git a/packages/debug-info/src/__tests__/real-projects.spec.ts b/packages/debug-info/src/__tests__/real-projects.spec.ts index 082c783..8fe2ccd 100644 --- a/packages/debug-info/src/__tests__/real-projects.spec.ts +++ b/packages/debug-info/src/__tests__/real-projects.spec.ts @@ -136,7 +136,7 @@ describe.each(ARM_PROJECTS)('DebugInfo vs binutils oracle on $label', (project) { name: 'flags', offset: 8, size: 2, signed: true }, // char[6] → `size` is the WHOLE member (element size × length); the element facts are // what an indexed read into it needs, and `signed` stays null (an array is not a base type) - { name: 'name', offset: 10, size: 6, signed: null, elemSize: 1, elemSigned: false, length: 6 }, + { name: 'name', offset: 10, size: 6, signed: null, elemSize: 1, elemSigned: false, length: 6, dims: [6] }, // pointer → 4 bytes, and the pointee facts pointer arithmetic scales by { name: 'ptr', offset: 16, size: 4, signed: null, pointer: true, pointeeSize: 4, pointeeSigned: true }, { name: 'inner', offset: 20, size: 8, signed: null }, // nested struct @@ -221,6 +221,7 @@ describe.each(ARM_PROJECTS)('DebugInfo vs binutils oracle on $label', (project) elemSize: 2, elemSigned: true, length: 3, + dims: [3], volatile: false, const: true, }); @@ -385,7 +386,15 @@ describe('DebugInfo on devkitarm-min-only shapes', () => { // The member still declares an element STRIDE — what it has no bound. So `elemSize` is // reported and `length` is absent, the two facts being independent. const data = di.struct('Blob')!.members.find((m) => m.name === 'data')!; - expect(data).toEqual({ name: 'data', offset: 4, size: null, signed: null, elemSize: 1, elemSigned: false }); + expect(data).toEqual({ + name: 'data', + offset: 4, + size: null, + signed: null, + elemSize: 1, + elemSigned: false, + dims: [null], + }); }); it('names an UNNAMED pointee by the typedef that aliases it', () => { @@ -517,7 +526,7 @@ describe.each(BE_PROJECTS)('DebugInfo vs binutils oracle on $label', (project) = { name: 'tag', offset: 0, size: 1, signed: false }, { name: 'count', offset: 4, size: 4, signed: true }, { name: 'flags', offset: 8, size: 2, signed: true }, - { name: 'name', offset: 10, size: 6, signed: null, elemSize: 1, elemSigned: false, length: 6 }, + { name: 'name', offset: 10, size: 6, signed: null, elemSize: 1, elemSigned: false, length: 6, dims: [6] }, { name: 'ptr', offset: 16, size: 4, signed: null, pointer: true, pointeeSize: 4, pointeeSigned: true }, { name: 'inner', offset: 20, size: 8, signed: null }, // nested struct { name: 'tail', offset: 28, size: 4, signed: true }, @@ -606,6 +615,7 @@ describe.each(BE_PROJECTS)('DebugInfo vs binutils oracle on $label', (project) = elemSize: 2, elemSigned: true, length: 4, + dims: [4], volatile: false, const: false, }); @@ -615,6 +625,7 @@ describe.each(BE_PROJECTS)('DebugInfo vs binutils oracle on $label', (project) = elemSize: 2, elemSigned: true, length: 3, + dims: [3], volatile: false, const: true, }); @@ -811,7 +822,7 @@ describe('cross-endian equivalence (same declarations, four toolchains, both byt g_probe: { kind: 'struct', structName: 'Probe', size: 32, volatile: false, const: false }, g_bits: { kind: 'struct', structName: 'Bits', size: 8, volatile: false, const: false }, g_cv: { kind: 'struct', structName: 'Cv', size: 4, volatile: true, const: false }, - g_rom_table: { kind: 'array', elemSize: 2, elemSigned: true, length: 3, volatile: false, const: true }, + g_rom_table: { kind: 'array', elemSize: 2, elemSigned: true, length: 3, dims: [3], volatile: false, const: true }, g_util_pair: { kind: 'struct', structName: 'UtilPair', size: 4, volatile: false, const: false }, }; diff --git a/packages/debug-info/src/types.ts b/packages/debug-info/src/types.ts index bf53125..45c3117 100644 --- a/packages/debug-info/src/types.ts +++ b/packages/debug-info/src/types.ts @@ -178,6 +178,17 @@ export interface StructMember { * array member, `char data[]`, which declares a stride but no length). */ length?: number; + /** + * Array member only: the per-dimension extents, outermost first — the RANK that {@link length} + * multiplies away (`u16 x[4][8]` → `[4, 8]`, length 32). One entry per DW_TAG_subrange_type, + * `null` where that dimension has no bound (a flexible one). Absent when the member is not an + * array or the DWARF gave the array no subranges at all. + * + * The rank is not decoration: `x[i]` on a `[4][8]` member is a ROW, not an element, so a + * consumer that only knows the flat count cannot spell an element access that type-checks + * against the project's own header. + */ + dims?: (number | null)[]; } /** The width/signedness facts of one declared type — shared by a parameter and a return type. */ @@ -238,6 +249,11 @@ export type VariableShape = elemSize: number | null; elemSigned: boolean | null; length: number | null; + /** the per-dimension extents, outermost first — the RANK `length` multiplies away + * (`u16 g[4][0x400]` → `[4, 1024]`, length 4096). `null` where a dimension is + * unbounded, and null overall when the rank itself is unknown (an unsized 1-D + * extern) or the type is not subranged. `g[i]` on a rank-2 array is a ROW. */ + dims: (number | null)[] | null; volatile: boolean; const: boolean; } @@ -549,6 +565,12 @@ export class TypeIndex { // near-information-free fact. A DEFINED [1] keeps its length — the definition // is the witness. length: isDeclaration(variable) && length === 1 ? null : length, + // The RANK, under the same declaration rule applied per-dimension: on a DECLARATION + // a LEADING extent of 1 is that same unsized spelling (`extern T x[]`, `extern T + // x[][4]`) and reports null, while the inner extents ARE written down and survive — + // they are exactly what an element access needs. Only the outermost dimension can be + // unsized in C, so only it is normalized. + dims: declaredDims(variable, die), ...cv, }; } @@ -828,16 +850,18 @@ export class TypeIndex { /** An array member's element facts. Each is omitted when the DWARF does not determine it — an * unsized element type has no stride, a flexible array member no length — so a present key is * always a fact, never a default. */ - #arrayFacts(arrayDie: Die): Pick { + #arrayFacts(arrayDie: Die): Pick { const elemRef = arrayDie.attrs.get(DW_AT_type); const elem = this.#stripTypedefs(elemRef); const elemSize = this.#typeRefSize(elemRef); const elemSigned = elem ? baseTypeSignedness(elem) : null; const length = arrayLength(arrayDie); + const dims = arrayDims(arrayDie); return { ...(elemSize !== null ? { elemSize } : {}), ...(elemSigned !== null ? { elemSigned } : {}), ...(length !== null ? { length } : {}), + ...(dims !== null ? { dims } : {}), }; } @@ -936,30 +960,57 @@ function bitfieldAbsBitOffset(member: Die, typeSize: number | null, littleEndian } /** - * Element count of an array DIE (product of its DW_TAG_subrange_type dimensions), - * or null if any dimension is flexible (no bound) or zero-length — those have no - * fixed read size, so the member's size should surface as null, not 0. + * Per-dimension extents of an array DIE, outermost first — one entry per + * DW_TAG_subrange_type, `null` where that dimension is flexible (no bound) or + * zero-length. Null overall when the DIE carries no subranges at all. + * + * This is the RANK, which {@link arrayLength} multiplies away. Both readings are needed: + * the flat count sizes the object, the rank says how many subscripts an element access + * takes — and `x[i]` on a `[4][8]` is a row, not an element. */ -function arrayLength(arrayDie: Die): number | null { - let count = 1; - let sawDimension = false; +function arrayDims(arrayDie: Die): (number | null)[] | null { + const dims: (number | null)[] = []; for (const child of arrayDie.children) { if (child.tag !== DW_TAG_subrange_type) { continue; } - sawDimension = true; const explicit = numberAttr(child, DW_AT_count); const rawUpper = numberAttr(child, DW_AT_upper_bound); // GCC 2.95 stores a zero-length array's -1 upper bound in UNSIGNED DW_FORM_data4; // read raw, upper+1 would claim 2^32 elements. Normalize to the modern sdata reading. const upper = rawUpper === 0xffffffff ? -1 : rawUpper; const dim = explicit !== null ? explicit : upper !== null ? upper + 1 : null; - if (dim === null || dim <= 0) { - return null; - } - count *= dim; + dims.push(dim === null || dim <= 0 ? null : dim); + } + return dims.length > 0 ? dims : null; +} + +/** + * {@link arrayDims} for a VARIABLE, with the declaration quirk normalized: GCC 2.95 + * encodes an unsized extern's outermost bound as upper_bound 0, byte-identical to a + * real `[1]`, so on a DW_AT_declaration a leading extent of 1 is reported as unknown. + * The rare genuine `extern T x[1]` / `extern T x[1][4]` loses a near-information-free + * fact; a DEFINITION keeps its 1, since the definition is the witness. + */ +function declaredDims(variable: Die, arrayDie: Die): (number | null)[] | null { + const dims = arrayDims(arrayDie); + if (dims === null || !isDeclaration(variable) || dims[0] !== 1) { + return dims; + } + return [null, ...dims.slice(1)]; +} + +/** + * Element count of an array DIE (product of its DW_TAG_subrange_type dimensions), + * or null if any dimension is flexible (no bound) or zero-length — those have no + * fixed read size, so the member's size should surface as null, not 0. + */ +function arrayLength(arrayDie: Die): number | null { + const dims = arrayDims(arrayDie); + if (dims === null || dims.some((d) => d === null)) { + return null; } - return sawDimension ? count : null; + return dims.reduce((a, d) => a * d!, 1); } /** Signedness of a base type from DW_AT_encoding (DW_ATE_signed/signed_char = signed; diff --git a/packages/debug-info/test-projects/agbcc-min/build/min.elf b/packages/debug-info/test-projects/agbcc-min/build/min.elf index f6facf10a34b40e50ee0c60baec99e50ad6029af..5effc18571665b263d1d639e207dc8bfcbe3d016 100755 GIT binary patch delta 2182 zcmZ8ieQZ-z6hHU1uj}iWZMU~|quu&71}5_96bS=oM7M$=KsH18NK>}bz0kF_D<1=O z!zeKk!c z+49X#%hVnTiD>!eblDjy-#mja-RPAwzW%X3aEcg*F`SsQ0^<=3J@L(ceWNS!6=^HG zo9X5GqrRa+578F*#xZt*uO-~$kCD;r4i$Q)VDpekZM1|0Y2+X$>Exmsa#!&Gtp<5$ zs}S;NePCvv-!B&3Pr4RC*ha|qid zBbOS+s;y6gsKq@-p;RQ%woM_QVX5Urcv2o|3hQiLFW+qn)Xj0yy2FP+>7E%`GKX3vFel7;@RjCIa(wq+26^O6AYSRYt**th%(>9L_29t;LgGgna)1fAF z1-Vbli9q9;)37+THf*(iq?9U-kmyk+N03be#rz0Ny~^oe9&MO^TWwfYEKq-**Wr->T;dlq+&kOZ(V+HWgoo$Ey?Zs1>z>OanHoWaX?< zb*YKv@FFX2DN{iAbmOB^BMM}a=|gv@C;OQy%uZ(Q#fKBGRT1;KbaF7gm&EHkblf@O zb@J-RLGtSIhnCRThfs9~H?8?RRAg~DUBszO@dm)>7WRA(5AOrnYPAj~Ws26|gCx$* z!2{M7X8i@-P7s_*ip(Q1Q|D3{{tAYB9rPYH`^2oVj@{>~?J$teW>FBIF-0BTCMbM3 zyl{0{5}(&|INdQW8y6l~#NEb^Pd|38eT>EurJ_~f>+%YQ$}eXZX2g_i4Q}$kfn3SU zWH^aZE;$=q;#;=Po#I0UF^RjOL+PpqW|g|fDveMW zX@hZqRx3r-+HR%ZEvT0i-g|H`xr^KPx(&1GLuBHl{!J9y0ES4FH~`$Iq_#7(d0Aj^7l}k=##fYC-8l>b-BpO3$0@*E{+9Y z@wMgYD5+h!~GVxGT6KG*iBctT!i+c|a-_yUS# z5V9WeUV-G2$9&q)t@58(M_r_iXc|4>LCURiWjv_QM~Rlot?{^i LJ4Q4jMZDo(H9>=l delta 1788 zcmYjRUrd`-6hHTCKWGbMZ7CGi(*H09Bk+L0;?$uT415rY80H?jLc3B|`jOHB)5K1v zi3!HB+zg!w!x!HWooq3SSxlBJ^Km9D%tVdOm?cJ&#TWF!)Ze)u9cy#$`S-i$o_o%@ z-`(L42A4wGTKHn5MPx4y`SejiGk3X1lgR|OWW5< z6bt!9xU~Ic$?7j{e}R=A^~eq9SZ5b7&w>U(R_y8GeIRYfcCMf74L1MG;1qNRc_=`w z^0dpR9T4&-w|8UJJrq7M5^Ax|REtTd-Rlgp)`2a_te2LUo!5~1tFU_V(WrxI}69E|6qs&uNh zvbQoFpHat(=*QSAbc++$-ZKG=O|;n)B*(k~Uq4hvCNhX}kevW>5BA=WA9|nCwlsO$ z8!g^2VUtGI0PgU46UTkR=4m5|{GZt}jodiff`#b$OkoyB9d%Eo5_yPXfUQ<7phd|& zTS(+#8dN5Wk4=+#V-}`k%2erL(|m>_4=u=aLwB(TyOA6Zh3z}YFU*luykgI$=2EE0 z7@M%io=#+PBwpQ8s)lA{(z#SJWY(#o_D9%v8gwSN<5Qig#7!pWNF3KOHaLfeu66}z zzTtGnK;K^Dpm6alI@$qas?x~AodhgzOvej}i7awHF>FTRk@W;2*A2`kM-pdA0C#FW z8CP9?Z^lINkXBn?f?`{hZ#M>ORw42zIo2Vp%k{=san6KdwKyJNWvUWYf;@aBM9t(f zh4S%BnyxbCm*Ck1(oqY8N|(r+j;9tLLzi0_Dm;~7jzd`ZGF2*~kxRvssZ%6A>d-Mf zxOq399tY@wRVMcN!*4;MTd6sjg%+vat63vPHSIKG)-$yah z@d=*2zmuAdPch zYZ`27Kn2S`|BeGwhd)tBIs^M%48gzcqW&IlTBTwkxK<6(52SEHHy$<0r0>;2O;4N@|HRS+zpz{El8#LO4&hMcD z+=VOt0 Date: Sun, 2 Aug 2026 16:02:46 +0100 Subject: [PATCH 2/3] docs(debug-info): say who StructMember.dims is for --- packages/debug-info/src/types.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/debug-info/src/types.ts b/packages/debug-info/src/types.ts index 45c3117..5fc75a9 100644 --- a/packages/debug-info/src/types.ts +++ b/packages/debug-info/src/types.ts @@ -187,6 +187,13 @@ export interface StructMember { * The rank is not decoration: `x[i]` on a `[4][8]` member is a ROW, not an element, so a * consumer that only knows the flat count cannot spell an element access that type-checks * against the project's own header. + * + * Reported for SYMMETRY with {@link VariableShape}'s array arm — a member and a global are the + * same DWARF array type, and a reader that answers the rank question for one should answer it + * for the other. It is the consumer that differs: a consumer synthesizing its OWN struct + * declaration may flatten the member, since its access and its declaration then agree by + * construction and no foreign header is involved. Rank only becomes load-bearing where the + * declaration belongs to someone else. */ dims?: (number | null)[]; } From 12ebb4fd2cb26663c10624ceb1389a92e54f3d52 Mon Sep 17 00:00:00 2001 From: macabeus Date: Sun, 2 Aug 2026 16:54:31 +0100 Subject: [PATCH 3/3] test(debug-info): verify array rank on all four test projects, not just agbcc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `dims` was only exercised by agbcc-min. The facts it reads are producer- and byte-order-sensitive — the dimensions come from a DW_TAG_subrange chain whose bounds are read through the endian-aware reader, and DWARF 2 spells them differently from DWARF 3+ — so one toolchain is not evidence. mips-min, ppc-min and devkitarm-min gain the same two shapes agbcc-min already had: `unsigned char g_grid3[2][3][4]` (a fully-bounded rank 3) and `struct Grid { int id; unsigned short cells[2][3]; }` (the same fact on a member). All four now report `dims: [2,3,4]` / `[2,3]` identically across GCC 2.95 (DWARF 2), GCC 14 (DWARF 3+), and both byte orders. They are wired into the EXISTING cross-project machinery rather than tested separately: `Grid` joins CANDIDATE_TYPES and `g_grid3`/`g_grid` join CANDIDATE_GLOBALS, so the layout, declaration-fact and variableShape comparisons all pick them up, and the "shares exactly this declaration set" pin records the new membership. Mutation-checked: flattening arrayDims to a single product turns the shared-shape test red on all four. `g_ext_grid` is NOT shared, and is now listed in CANDIDATE_GLOBALS so `skipped` says so out loud rather than leaving the asymmetry invisible: the unsized-outer-bound spelling (`extern T x[][4]` encoded as upper_bound 0) is a GCC 2.95 ENCODING quirk, so agbcc-min is the only place it can be pinned. devkitarm-min's block is APPENDED, not inserted — debug-macro.spec.ts pins the macro fixtures by exact line number and the file says so; inserting mid-file moved REG_DISPSTAT from 157 to 173 and broke three tests. 222 tests green (was 218), typecheck + lint clean, all four ELF/oracle artifacts rebuilt. --- .../src/__tests__/real-projects.spec.ts | 33 +++++++++- .../devkitarm-min/build/macinfo.o | Bin 19028 -> 19584 bytes .../test-projects/devkitarm-min/build/min.elf | Bin 9880 -> 10284 bytes .../devkitarm-min/build/oracle.json | 60 ++++++++++-------- .../test-projects/devkitarm-min/source/main.c | 20 ++++++ .../test-projects/mips-min/build/min.elf | Bin 5596 -> 5820 bytes .../test-projects/mips-min/build/oracle.json | 44 +++++++------ .../debug-info/test-projects/mips-min/main.c | 16 +++++ .../test-projects/ppc-min/build/main.o | Bin 5748 -> 6028 bytes .../test-projects/ppc-min/build/min.elf | Bin 8440 -> 8656 bytes .../ppc-min/build/oracle-obj.json | 4 +- .../test-projects/ppc-min/build/oracle.json | 8 ++- .../debug-info/test-projects/ppc-min/main.c | 16 +++++ 13 files changed, 147 insertions(+), 54 deletions(-) diff --git a/packages/debug-info/src/__tests__/real-projects.spec.ts b/packages/debug-info/src/__tests__/real-projects.spec.ts index 8fe2ccd..7cae60b 100644 --- a/packages/debug-info/src/__tests__/real-projects.spec.ts +++ b/packages/debug-info/src/__tests__/real-projects.spec.ts @@ -696,7 +696,7 @@ describe('cross-endian equivalence (same declarations, four toolchains, both byt // Every type/global any of the four declares. The ones not present in all four are // enumerated by name below, so a project that genuinely lacks a shape is skipped // EXPLICITLY rather than dropped silently. - const CANDIDATE_TYPES = ['Probe', 'Inner', 'Bits', 'Cv', 'UtilPair', 'Pair', 'Shape', 'Blob']; + const CANDIDATE_TYPES = ['Probe', 'Inner', 'Bits', 'Cv', 'UtilPair', 'Grid', 'Pair', 'Shape', 'Blob']; const CANDIDATE_GLOBALS = [ 'g_counter', 'g_probe', @@ -704,6 +704,9 @@ describe('cross-endian equivalence (same declarations, four toolchains, both byt 'g_cv', 'g_rom_table', 'g_util_pair', + 'g_grid3', + 'g_grid', + 'g_ext_grid', // agbcc-min only — the unsized-outer-bound spelling is a GCC 2.95 quirk 'g_pair', // little-endian sources only 'g_color', 'g_mode', @@ -746,8 +749,17 @@ describe('cross-endian equivalence (same declarations, four toolchains, both byt }); it('shares exactly this declaration set — every other shape is skipped BY NAME', () => { - expect(sharedTypes).toEqual(['Probe', 'Inner', 'Bits', 'Cv', 'UtilPair']); - expect(sharedGlobals).toEqual(['g_counter', 'g_probe', 'g_bits', 'g_cv', 'g_rom_table', 'g_util_pair']); + expect(sharedTypes).toEqual(['Probe', 'Inner', 'Bits', 'Cv', 'UtilPair', 'Grid']); + expect(sharedGlobals).toEqual([ + 'g_counter', + 'g_probe', + 'g_bits', + 'g_cv', + 'g_rom_table', + 'g_util_pair', + 'g_grid3', + 'g_grid', + ]); // The rest, and who lacks each. These are SOURCE facts (the big-endian projects // declare a different set of globals; agbcc/GCC 2.95 rejects anonymous unions and // flexible array members), not parser gaps — pinned so a shape silently vanishing @@ -758,6 +770,7 @@ describe('cross-endian equivalence (same declarations, four toolchains, both byt Blob: ['agbcc-min', 'mips-min', 'ppc-min'], }); expect(skipped(CANDIDATE_GLOBALS, hasGlobal)).toEqual({ + g_ext_grid: ['devkitarm-min', 'mips-min', 'ppc-min'], g_pair: ['mips-min', 'ppc-min'], g_color: ['mips-min', 'ppc-min'], g_mode: ['mips-min', 'ppc-min'], @@ -784,6 +797,7 @@ describe('cross-endian equivalence (same declarations, four toolchains, both byt Bits: { size: 8, members: 'hearts@0:1 stars@0:1 cross@0:2 wide@1:1 after@4:4' }, Cv: { size: 4, members: 'level@0:1 gain@2:2' }, UtilPair: { size: 4, members: 'lo@0:2 hi@2:2' }, + Grid: { size: 16, members: 'id@0:4 cells@4:12' }, }; it.each(sharedTypes)('every project reports the same byte layout for %s', (type) => { @@ -824,6 +838,19 @@ describe('cross-endian equivalence (same declarations, four toolchains, both byt g_cv: { kind: 'struct', structName: 'Cv', size: 4, volatile: true, const: false }, g_rom_table: { kind: 'array', elemSize: 2, elemSigned: true, length: 3, dims: [3], volatile: false, const: true }, g_util_pair: { kind: 'struct', structName: 'UtilPair', size: 4, volatile: false, const: false }, + // RANK is byte-order- and producer-independent: the dimensions come from the + // DW_TAG_subrange chain, which every producer spells in declaration order. A reader that + // multiplied them away (or read them under the wrong endianness) shows up right here. + g_grid3: { + kind: 'array', + elemSize: 1, + elemSigned: false, + length: 24, + dims: [2, 3, 4], + volatile: false, + const: false, + }, + g_grid: { kind: 'struct', structName: 'Grid', size: 16, volatile: false, const: false }, }; it.each(sharedGlobals)('every project classifies %s to the same shape — TypeIndex.variableShape', (name) => { diff --git a/packages/debug-info/test-projects/devkitarm-min/build/macinfo.o b/packages/debug-info/test-projects/devkitarm-min/build/macinfo.o index 9f00185d5f784e83110a38262b6d3e7a24468038..e0fd0e1dc73aae72baff969ff985ca1fa327d9d3 100644 GIT binary patch delta 2953 zcmZ9O3v5(H6o${ty|dkR+wS&3DP2pKE^KLm+5)0&rIZ%BTNDsMqd_fYTib@RVk>AA z-HMIIMTZ$hoGB*3A8U^QqLpyi*TuitpH8v#iSyY2u%&zEMQ#EULGA z2BHxmLqEpefVmoVWgIp+uIW$RMJ}7nxGh%Ifn5l4H?f{)6RIXOhZ}_hY|&A_f6#7I zvx^R~u_BwB>F8yYrTndST$SWTU=Mh`>6h&HYC(Do5vtm$fnCSBQH^f}Ba>c#&hA-R z!~dBAF8lM>u|?JSUIc?Jh@#+pJWOy0o<0gGwIF|teJ4C$K8I6Yn9<;HBYl$V_8C1b z|3<8iUoG*k1`8gtCvn~u7q*V@HymG2>r@3JX3tk&Ac+^Olm zU{FJO&m&B7X6L#@Tyl7d%6n?>>F{Pf&mAXu)Gr6m{nyIe0((fk>R*MHzW#1f2W5-N z?{Gh_6|;wjlFh5on@N!VHv{Q&Jd`)`V(`dNN)>OYc8%gmD+|vQu2GrV$9=w8;W>B} zMo{$qbQ~e!et711aU6S@`WsL6WTq3(f=3a`Z!TR&`!X4kh1iRXb+|&|6g)MYai?uD<$-V)sk^IKA2{4+wyMcF3i-l@9Die= zDbNt;DAGQR%zox8n^8Xhf99#Rv?$lf&qP+`7N|niVjHt+Lp+vyQ51&FKiiWvrbZ4| z`uEkV#df^m^h{IdbEa=MrpT1|lu=Pr5;VrQ(9}bfMo_)nC|{9w?7qgmZhWx6+cq|} z=50<5_4lTFx+BTHu0eZWQ(H+dT-4jSe&CMvw6Uu{MaiClfgyXMX?ONuS87A&raLzD z*juh1i}ZGKDAq0B*47xA+1;~cL;qciuU}prsb5fAUt4GE7bb(eQvBob7h~9V;js$8 zXtwi=0(cH{)%&T#E1R!S={q6NfC>@7S9ky=gi=6;n!q(ErJ~zFUKZXO_AdhyD4dA( zDzN1eeKYD?Q6}P(s1IMFkqd_tKWr2_@Y6jYZz&G1*CBhaLYe4b1ob+UiG+`%J_iMd z$&23!&b~zNL7jh@_6{9DeLBiS`-2qBI3qCf4BoO`Ee)mru0Qriw#nN9JKFNVZQTgf z=#UpmV@Zca1Eet+?mK5n=IrK_Wfn81oT!BD;mlk$RyddACvn;gQH8dt#go(6j~T3R zplig-tDr9@>JU97yk9sfd`b9@@TBku;h(}hzVt|0DvU8}iB^JXcB~agKNHhRiQdY@ z8b2bMzegOuN4Q_epCGosEj%XVS2f$eV$LEuBl;I6X8XIsnc#qn;>gEgU>y<86)q93 z5w2%e6Ag*pCL9&+7rr7q%A84bO!UXhDxx1XP8}!wgAFmF^Ah00n^|zML5EY5Ns(+u#y=esuJBQ>=SNb zR^SSXeoFWp6O%e1e3yx1I4=J5CtS%Q`a*b80)7^rV`3oZnds=E5Esbn$j5}gkO_Z@ zaF+O+MYjr9iydc^!IGLdkh=v+S3(755G@ka3c zh?_1N=aF(#7>JB*@5~^B}Z9^ieezCVEs`Rhz_TfZK7iQbn6EU;5k!Y#?IuX@w z-2M&2S$s=2*y@g`Ufyh1bi_;__G*(iuqQe~rZ|o-i+!#mYEHpkgA7IXOh+isU4+p% b_)7vzu@^eR#>Ld$^Zc`yg-kcvon`e800~;F delta 2383 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 rL#i+5*FKJ^w{ls}b%5{T%m?w6QFT67C- (hi) ? (hi) : (x)) #define NO_BODY + +// ---- RANK. A flat element count cannot say how many subscripts reach an ELEMENT, and +// `g[i]` on a `[2][3]` is a ROW. The per-dimension extents are their own fact +// (variableShape().dims / StructMember.dims), and they are ABI- and byte-order-independent, +// so all four toolchains must report them identically. (agbcc-min additionally carries the +// `extern T x[][4]` idiom, whose unsized outer bound is a GCC 2.95 ENCODING quirk — modern +// producers spell it differently, so it is pinned there rather than shared.) +unsigned char g_grid3[2][3][4]; // fully-bounded rank 3: dims [2,3,4], length 24 + +struct Grid { // Grid: id @0 (4) cells @4 (12: [2][3] of u16) size 16 + int id; + unsigned short cells[2][3]; // the same fact one level down, on a member +}; +struct Grid g_grid; + +__attribute__((noinline)) int rank_poke(int i) { // keeps the two shapes above live + g_grid3[1][2][3] = (unsigned char) i; + g_grid.cells[1][2] = (unsigned short) g_grid.id; + return g_grid.id; +} diff --git a/packages/debug-info/test-projects/mips-min/build/min.elf b/packages/debug-info/test-projects/mips-min/build/min.elf index 45b5a4c926fc31f3c0b9fae5eea5477789835ef9..cd3ce495a27eae5f4b4ece1232a677cb881799be 100755 GIT binary patch delta 2503 zcmYjSZ){uD6+ibr-xtSD;uk-sbxJzy*i8amMbL(lQq$S2&7Y<&E(8RN*3NaZ#G@p} zc7bjMTcJ$-kg0*YX;cJcRe=waMWTU_*fLhCj#aFaHm#bFh6EovF=_e0L_bs$toxlC zr{Y=n+R=d#2`fil$e4~H3m@^WVILTKRjOf(&)cV zQu9@?9*hu%HGJq{YQFD-XD8Yx-v94UKYA_j{C{4ZTaG>o9VNQx{@&l+{IqvzzPj>z z>RMSN=j^#^*waqC;~o+%4$V-qu;VOr;(~ro^i~ul6Fy2U%v+xL>#~rrD3$P1Dt!=B~y$V^eHevv#08`!5UPyM{SF1q`ogSCtDk1VWDQ5Oe4B}0+d5wL#A zqS`Te+4_{c%j?u;wg)|VoaFMP<>-U5xAQ7Xzy4L3Ny>~~kSijiqrt8EA*)NQ>4Mc+ zIm0#F(1UU@8=rNWlrTyT)3P1s^8`kinN1s zjjc}J#>+Qhm6QcW_@_4tdd+@@x=mJOpQM-{qJoE@Zx+Lm9{BCE^`d86MWpU9I*)2#6FA(lbGpjarQ3G{F=%9 zDknM79{_#U2&!DnYg~dA@9qkw4;km?y&!o>yk6eJYfJL_PYGT(DXc}}K3;oTIF0mP zlLopOvfrdo12J#luQ=a*iacTn4iY~S)5GmpDqhq3BREy*NlT8??Z6X&QH=2lcS0JtD}s0 z(!)1cq5|@)!N@cK8A{k$Y(qX`plV23+#^D!)gXO`Phf!fd|Jhm8`7l6KsYFtp#LhA z&E-fGU$Q$YUu+TM;%?eXNl|7Mp@l`i$k`Co;87P#otSQj!v+VTtvh|Qbl8D#fVO2P zCsE&9szbgkrMbrje8(uw_ho=?V;7(;g7b2GtAH-D_K0yzBi26gFu!G1046VQn6Nq` z#=#IRY}_-k!bf86+1p4k%r_PSL=f9i9PwNIu^o%8A`x*(w4ff;!=fVJY9wA0ufjX%;`TcwS7FyA6CChtnRP6EZ_K&)QuxfIJ)#mqa$f91h z_rj>HA!r+QTm6s2uK6Ased}V=1tB{1qA#ppY2H<_oOz{O6|jYhJgB;?A0JSG5ncv| z##CUx3La8B52@g=ilkM*dgg#q_Lz#>9V(nrkrB0(9l8#vZ4WYM+`|k5LwH6GvgbF3 zm48eH(<+=+erOJ=_?QYmVAkJexsz7G10%{m#NaM}%0WJcL0h}HJ3=Ujl*AEatk3o1 zz6@T%HD5%3;!B9S?(z>frrOg-`LgHcPRy2dvgO=NshlmAC^vQdc!^3gbH#Fm-?!$-CL_6-Y?1P_vr|PHHFWyuG|avQ$J|p?dh$fJ zI7Ks4*&>4&m446v{Ot%{oI5r}VB zY29~sfn{hG?gcXcq#Hax!pw7nvYsy{^ELf>>&;Zva2ryWUvcpGb2N|7_DvKAeFJ%X zvn_D}*={HFS9O2jJC#*%;f7b5vB49(_}O}l%Z_=l;dKQ1%iuSo$ZScIUUxUAb zc{AXR-bna8lm+Z9|4R-0&3GS@g`21|PP(aa)OyKzz`~)w^_lYnp@)J$yFJ1H zjSp#>?;t3@vFJ;^&E2j8Zi}jdt?GyyQ`n+h)FW=JxrP-NpsLGmOf2b_-Cl87UjUua z|8jfPDpCvUP$&lJV5rCTVN>EqdNR~4{RMp{)T`DZ_=|oU7Hj&WP_I~jsiQ}>*}9LX lEjrWDW4Ga9#3oL4bldHH2=;fq+!5>eA68#sY<`?B{U0E+i=_Yn delta 2265 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 delta 2086 zcmYk6ZEO@p7{{NP-Pzl_>s{||uXjMta&KHkT1qvPE3FiW70a9Q<_iJo3kBi}oNajx zcr|Ds#%QmDMwG-FUp^Q#P0$Y-HGDvcMuQrNd_V}3til4Uk6s)XID*|;?u zh`qy_14?}o?E_n0VyPxSkn9X@SIj+>Ro!kf_fjqh+HH~>PZx;TGE>gvEzFb;@qE-^ zDk&iuTZYze%jbFXoNBUm2;T}7o{!ed$>k2k26wqru}=tjg|FQIp#L%b628yG-oGGf*h=Ri1=U~5<_C0!5V zG({0x=gtfoW5=et$|^S*=I5Wvjpo!<{Bod=R)i4i4)oIsl!OB6Ran_^*=j-~00%!) zRftmPoM&t47Chh3B7Dm8zC3NVuFq32xFBeRiOdig_WTU%2(|}%oFd-5fD*1MnQ)I2 z3O)+anoB)ct&g!DhXJr_Jx&V(euo+1U{L#Qc4D`RO2ERo8I+6E!4jA*bNg~6PNWkr6v zh-E}1D}wN4MJy*G84*J?rM!+K(pCa_s~tx$%i#twCL$!Nhrzfg3wB8g!m;H7^9V9N;Hzr?$iyL1CwGgSsM%Iu8rso6 zxT%C1wr+A+S%?Zmb+RjzEGN99aXUtO+(wl2cmZ^?I*1lS_Za_zgva+2P4WEwU{BwI zSv=l;6Auwht@`D;P+`Wi=z6wsqG=w#bklUN$auKGrpu0S{WP~4d>Ub#U)G3TLi0vh z3g;ew0SZ0_6{X+N=ISW^IJ5{=C|zBvwP!8(VWN6Z->3Dx(4W?0)teo|$~@1D+VlN* zZKBNXK=d@q@S5xe8&FQao!n=)Xm$Xx*@<$9H>Fs^rra4L9Od%gxYVas))yjAO$p)b*lNjdgP zc%H|I0*aB3m%wG!sX=F_HsO=uhc#m&KCTn}06vPQ{7QdQ>z{*v(KZ#_W=_+QQQ z@b|-F+_4dGgVwP%+{nre(cSC|c{bX@dQX_KF7<1=%gOSZ4RV{)$gayV_dX|{lxLiI zJhWWe@m)N$S&qhMv0LTwc-9JGDg1&w8_%)z@~?O!OUiUzfk&3hd+Hk5VOdh0l6)Bt zYf_$6y(9A1x`JhWiJJeA@kEwKj>}@AVEI15E<7VQCvt4DJe(+Se@RY4_hSm$FE1$P hsqrL)tC*8yQ!;A>fwWz&O=c638^Ax&yi2_=`X4;m5WWBa diff --git a/packages/debug-info/test-projects/ppc-min/build/min.elf b/packages/debug-info/test-projects/ppc-min/build/min.elf index 44fee28690cde98c9df76abcd17863761cf78a89..8108423d30745f67a88849561ac1f898e370e328 100755 GIT binary patch delta 2056 zcmYjRT}+c#7=F+9edlYTg&zBLZ7HSwN-KhbvZ%2rD8`|Hf9N#CZOTt!{767c1-7Y$ z?0>ectE& zIloVLF6^3#vj@3EoZkY_Zsqnx*+gz=!gv4goBNZG9&d}?5s`(l{+dPc`B3g@f3|*7 zKz*lxsf4I(Xhiv;fVx&un@kDg@?9b7s(?)ug0KEEat0xJwAynkX^6_RsqSmZDrN5P{r!8bIw*@-Md1l_~@If2IG^2aDRs}XShhr45GdkR&B`@ zLiqbZ*nMCU>`nlXPgp$m*3!~aBPz`}x8eK>&Yd`)!ubi#b8?fmqfDUGxU}@_G0xN2 zsoB_%AeNDrv}nOZK8~2bt?ek13tGWP;sCoU4~mlP7Y6Y`0HcT$E8p}_fiq<+M&zF| z9R2`c?Kr#h6fm3)6gL_MO$`i(zx*7>Cawz*l^%l+3}>K#5Hdo*#GzXm6D~q|7RPbw zIu12D7#jHpDZ@Cq+ze9aKIIZ7AXh@=>{CFHxaYC|pu9Cz*cDS+;cpt!GhHT1%zhsr4ZK zmI8nhE@F9X%2|iweTs8_D-JapknG+@vaXTbT2Hcrll)Z!$%dOsy1spR36u}YcjCsd z_f>Quc8z7RxZUWXIf(lEo>eHi)yk`y@yNB1M#sk<8H|qZu%S^g!w6{>g-h@Ck*^Bp z&aY3~r`E@o&qR&7%02ipu1u>{FY|RfTdN!6vBS& z?&pvbMDMS$Kl8H}+4B%U$R-Cs1ANR6koV`Rnw}=-h||rz&C!>(_UqN(ZBL2HfEFBqiQ<6Sy}39e<=nn)&{&+Mgm-} z?Jga!A7`w^Vz^;u5w3P?jBRt(xmv6wvK$uEi(Rf|EaoJV6G_E+pt!{KG74^?tIvTR0L zSbyE-t{C@}ac;(V*tAHCM7cN46FA1WDCaIBc~^50_mM!U*L7LCs1GUzbP}}$8@a&VlQ$yctXbAZ z$24P?oQuZU9eFQWVFoZCJ0hP(%gtafieF0GF4sa1`GQ@cg=XcDy@ubwJ(-c0>~gcL W8B_iuf40m05&A^$Vqa-$|NaGe6*BAq delta 1897 zcmX|BU2IfE6h3qBo$a#QpJ{h#cgvREySps~TB!zQ3#F8lBBdZjAP|(;?T<@^l-eyV zD7eL+AO_>EBS8#_HHtoH8j@;^Mu{dw9>55`$cqvCU^Gp%i9aDeP``7x^(HfOzVH0Z zxo6JI&9=K6voS%rcuZa;GOp&fRg13N;bXxM&SeHZd#Sbl)}~Zo?YT<(%=zmxxw{85 zZ#Z+a&Etwr#Z_H%x1#l}ikj~zYFbXBX{&0SxTe$|yX1>Rud+`0D0rgRm~5U<1nz|X znFk^B4~=rUsKtgZ+>54r3gTLL55fxrx;Sm(3nNc{AJg|uhSYyrf6A!MKVC|uXD{UmVaN)IgfcE z3ugt}JnFNCMuusn4}6beo6qaZFkcU{O=pAa8zED0ejnja5S2uao2|spk;t^I;{Ta( zGi_wX+gO76MVBDna0XFC%G-qb7K$U9*Me*?hzr%dj^%vO-fw2PKr;W^dX}w1PU+v4 z{4el+^uk6IMx1e@E7dldAxmsVK1Km&9DKMGVxjxzuWZ4Q8xL_YFHMUe@81q~GgqRWP$&9cBwZF=21E&Q5&B#(+1r~zIo$L>mtzzz zh7H=OE_R9gsRESE4#fTbquApC(G4*xE{3suBX+vc5!<-p8>F4w#qCs??CT@3 z{eRW8FG<_EE!urOv>kcFW(oSwxPox4fL>0^^ufgV4v?W?oyRhT-haKB| z3~?XEZVaM{{B03mnvD3i9LDH^%PcTw^ry(*7LmU#xLP7@>3zXy=s0o|CxlzT)ov~8 zx!TkE_2Az9aq|0H{3g1@Dk9Un))DLcP5zER0=*%@6z3VIxFb;HKLpbAAa$VV1wwQL z1O#+`M_?5civq$d_WS4Uy<)0u@l9dSA9`shq#G($Wm=>R$Wl+KEODg$kSvQhvSf)Y zivz`Ee1){*GGabs%hHuH5|brMrSv#*sVBgqKPJnfGF~mq9I2wx54)%=i%I3kGH4@g z8wg0-Q;xWK5Rk$XFia9cDw2lc8)4qj|5O~&kA?TH!Nux5aun}JdL%iVru4xh!z1?5 z!Sq0Cu)ojdhb2$3lzO6PU?fecSsPajPV_k->o)w7{Po`e0#;gPhS4AJpmX`=^xzR=y@k$ZeF~UgL=P~xRT>x#Lf(1( zv%vfm@Nu*LdEl;j%=hLrFt_kRyjK;qaA&v#J6wPP6AJ++kWe>pc0Qp?(8qxn0(_{O zs}AUQsuELos-i-h)n`RkXRF7At-bcBVcyW=c1(2Y_v~6v`CDkR7Jbu>dMa*1d|BVM tqei$}N1R$C{I}lZEW