From 098dcda93a2fede6e81663fc163adcfb512b6c38 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Fri, 5 Jan 2024 14:49:44 -0500 Subject: [PATCH] arm32: parse dwarf info tree, convert to number --- src/common/binutils.ts | 51 ++++++++++++++++++++++------------------- src/platform/arm32.ts | 7 +++++- src/worker/tools/arm.ts | 3 ++- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/common/binutils.ts b/src/common/binutils.ts index 4d881dbd..bf643bb5 100644 --- a/src/common/binutils.ts +++ b/src/common/binutils.ts @@ -34,6 +34,8 @@ function getASCII(view: DataView, offset: number): string { // https://chromium.googlesource.com/breakpad/breakpad/+/linux-dwarf/src/common/dwarf/dwarf2reader.cc // https://wiki.osdev.org/DWARF // https://dwarfstd.org/doc/dwarf-2.0.0.pdf +// https://dwarfstd.org/doc/Debugging%20using%20DWARF-2012.pdf +// https://dwarfstd.org/doc/DWARF5.pdf export class ELFParser { readonly dataView: DataView; @@ -189,9 +191,6 @@ class ElfSymbolTableEntry { } } -// https://dwarfstd.org/doc/Debugging%20using%20DWARF-2012.pdf -// https://dwarfstd.org/doc/DWARF5.pdf - // Tag names and codes. enum DwarfTag { DW_TAG_padding = 0x00, @@ -702,7 +701,7 @@ class ByteReader { return value; } - readUnsignedLEB128(): bigint { + readUnsignedLEB128(): number | bigint { let result = BigInt(0); let shift = BigInt(0); while (true) { @@ -713,10 +712,10 @@ class ByteReader { } shift += BigInt(7); } - return result; + return shift < 31 ? Number(result) : result; } - readSignedLEB128(): bigint { + readSignedLEB128(): number | bigint { let result = BigInt(0); let shift = BigInt(0); let byte = 0; @@ -732,39 +731,44 @@ class ByteReader { // Sign extend if the highest bit of the last byte is set. result |= -(BigInt(1) << shift); } - return result; + return shift < 31 ? Number(result) : result; } - readOffset(): number | bigint { + readOffset(): number { if (this.offsetSize === 4) { const value = this.readFourBytes(); return value; + /* } else if (this.offsetSize === 8) { const value = this.readEightBytes(); return value; + */ } else { throw new Error('Invalid offset size'); } } - readAddress(): number | bigint { + readAddress(): number { if (this.addressSize === 4) { const value = this.readFourBytes(); return value; + /* } else if (this.addressSize === 8) { const value = this.readEightBytes(); return value; + */ } else { throw new Error('Invalid address size'); } } - readInitialLength(): bigint | number { + readInitialLength(): number { const initial_length = this.readFourBytes(); // In DWARF2/3, if the initial length is all 1 bits, then the offset // size is 8 and we need to read the next 8 bytes for the real length. if (initial_length === 0xffffffff) { - this.offsetSize = 8; - return this.readEightBytes(); + throw new Error('64-bit DWARF is not supported'); + //this.offsetSize = 8; + //return this.readEightBytes(); } else { this.offsetSize = 4; return initial_length; @@ -831,6 +835,7 @@ class DWARFCompilationUnit { contentOffset: number; abbrevOffset: number; abbrevs: Abbrev[] = []; + root: {}; constructor(protected infoReader: ByteReader, protected debugstrs: DataView) { const baseOffset = infoReader.offset; @@ -860,33 +865,38 @@ class DWARFCompilationUnit { this.abbrevs = parseAbbrevs(abbrevReader); // extract slice with DIEs const slice = this.infoReader.slice(this.contentOffset, this.contentLength); - this.processDIEs(new ByteReader(slice, true)); + this.root = this.processDIEs(new ByteReader(slice, true)); // skip to next cu section this.skip(); } processDIEs(reader: ByteReader) { - let die_stack = []; + let die_stack : any[] = [{children:[]}]; // TODO: capture tree structure while (!reader.isEOF()) { let absolute_offset = reader.offset + this.contentOffset; let abbrev_num = Number(reader.readUnsignedLEB128()); //console.log('DIE', absolute_offset.toString(16), abbrev_num); if (abbrev_num == 0) { - if (die_stack.length == 0) throw new Error('DIE stack underflow @ offset ' + reader.offset); - die_stack.pop(); + let item = die_stack.pop(); + if (!item) throw new Error('DIE stack underflow @ offset ' + reader.offset); continue; } let abbrev = this.abbrevs[abbrev_num - 1]; if (!abbrev) throw new Error('Invalid abbreviation number ' + abbrev_num); let obj = this.processDIE(reader, abbrev); + let top = die_stack[die_stack.length - 1]; + if (!top.children) top.children = []; + top.children.push(obj); if (abbrev.has_children) { die_stack.push(obj); } } + if (die_stack.length != 1) throw new Error('DIE stack not empty'); + return die_stack[0]; } processDIE(reader: ByteReader, abbrev: Abbrev) { //console.log('processDIE', abbrev); - let obj = {}; + let obj = {tag: DwarfTag[abbrev.tag]}; // iterate through attributes for (let attr of abbrev.attributes) { let form = attr.form; @@ -1153,7 +1163,6 @@ class DWARFLineInfo { opcode -= this.opcode_base; let advance_address = Math.floor(opcode / this.line_range) * this.min_insn_length; let advance_line = (opcode % this.line_range) + this.line_base; - //console.log('advance', advance_address, advance_line, this.lsm); this.checkPassPC(); this.lsm.address += advance_address; this.lsm.line_num += advance_line; @@ -1214,7 +1223,6 @@ class DWARFLineInfo { case DwarfLineNumberOps.DW_LNS_extended_op: { const extended_op_len = this.opReader.readUnsignedLEB128(); const extended_op = this.opReader.readOneByte(); - //console.log('extended', extended_op, extended_op_len); switch (extended_op) { case DwarfLineNumberExtendedOps.DW_LNE_end_sequence: this.lsm.end_sequence = true; @@ -1225,11 +1233,8 @@ class DWARFLineInfo { case DwarfLineNumberExtendedOps.DW_LNE_define_file: // TODO break; - //case DwarfLineNumberExtendedOps.DW_LNE_set_discriminator: - // TODO - break; default: - //console.log('Unknown DWARF extended opcode ' + extended_op); + console.log('Unknown DWARF extended opcode ' + extended_op); this.opReader.offset += Number(extended_op_len); break; } diff --git a/src/platform/arm32.ts b/src/platform/arm32.ts index 01110bd8..4b53c5ca 100644 --- a/src/platform/arm32.ts +++ b/src/platform/arm32.ts @@ -66,7 +66,12 @@ class ARM32Platform extends BaseARMMachinePlatform implements Plat {name:'I/O',start:0x4000000,size:0x100,type:'io'}, ] } }; getPlatformName() { return "ARM7"; } - getDebugTree() { return this.machine.cpu.getDebugTree(); } + getDebugTree() { + return { + ...this.machine.cpu.getDebugTree(), + dwarf: this.debugSymbols.debuginfo + } + } disassemble(pc:number, read:(addr:number)=>number) : DisasmLine { var is_thumb = this.machine.cpu.isThumb(); var capstone = is_thumb ? this.capstone_thumb : this.capstone_arm; diff --git a/src/worker/tools/arm.ts b/src/worker/tools/arm.ts index a14b859f..1a9dde09 100644 --- a/src/worker/tools/arm.ts +++ b/src/worker/tools/arm.ts @@ -445,7 +445,8 @@ export async function linkARMTCC(step: BuildStep): Promise { listings: listings, errors: errors, symbolmap: symbolmap, - segments: segments + segments: segments, + debuginfo: dwarf }; } }