arm32: parse dwarf info tree, convert to number

This commit is contained in:
Steven Hugg 2024-01-05 14:49:44 -05:00
parent 886e19611e
commit 098dcda93a
3 changed files with 36 additions and 25 deletions

View File

@ -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://chromium.googlesource.com/breakpad/breakpad/+/linux-dwarf/src/common/dwarf/dwarf2reader.cc
// https://wiki.osdev.org/DWARF // https://wiki.osdev.org/DWARF
// https://dwarfstd.org/doc/dwarf-2.0.0.pdf // 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 { export class ELFParser {
readonly dataView: DataView; 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. // Tag names and codes.
enum DwarfTag { enum DwarfTag {
DW_TAG_padding = 0x00, DW_TAG_padding = 0x00,
@ -702,7 +701,7 @@ class ByteReader {
return value; return value;
} }
readUnsignedLEB128(): bigint { readUnsignedLEB128(): number | bigint {
let result = BigInt(0); let result = BigInt(0);
let shift = BigInt(0); let shift = BigInt(0);
while (true) { while (true) {
@ -713,10 +712,10 @@ class ByteReader {
} }
shift += BigInt(7); shift += BigInt(7);
} }
return result; return shift < 31 ? Number(result) : result;
} }
readSignedLEB128(): bigint { readSignedLEB128(): number | bigint {
let result = BigInt(0); let result = BigInt(0);
let shift = BigInt(0); let shift = BigInt(0);
let byte = 0; let byte = 0;
@ -732,39 +731,44 @@ class ByteReader {
// Sign extend if the highest bit of the last byte is set. // Sign extend if the highest bit of the last byte is set.
result |= -(BigInt(1) << shift); result |= -(BigInt(1) << shift);
} }
return result; return shift < 31 ? Number(result) : result;
} }
readOffset(): number | bigint { readOffset(): number {
if (this.offsetSize === 4) { if (this.offsetSize === 4) {
const value = this.readFourBytes(); const value = this.readFourBytes();
return value; return value;
/*
} else if (this.offsetSize === 8) { } else if (this.offsetSize === 8) {
const value = this.readEightBytes(); const value = this.readEightBytes();
return value; return value;
*/
} else { } else {
throw new Error('Invalid offset size'); throw new Error('Invalid offset size');
} }
} }
readAddress(): number | bigint { readAddress(): number {
if (this.addressSize === 4) { if (this.addressSize === 4) {
const value = this.readFourBytes(); const value = this.readFourBytes();
return value; return value;
/*
} else if (this.addressSize === 8) { } else if (this.addressSize === 8) {
const value = this.readEightBytes(); const value = this.readEightBytes();
return value; return value;
*/
} else { } else {
throw new Error('Invalid address size'); throw new Error('Invalid address size');
} }
} }
readInitialLength(): bigint | number { readInitialLength(): number {
const initial_length = this.readFourBytes(); const initial_length = this.readFourBytes();
// In DWARF2/3, if the initial length is all 1 bits, then the offset // 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. // size is 8 and we need to read the next 8 bytes for the real length.
if (initial_length === 0xffffffff) { if (initial_length === 0xffffffff) {
this.offsetSize = 8; throw new Error('64-bit DWARF is not supported');
return this.readEightBytes(); //this.offsetSize = 8;
//return this.readEightBytes();
} else { } else {
this.offsetSize = 4; this.offsetSize = 4;
return initial_length; return initial_length;
@ -831,6 +835,7 @@ class DWARFCompilationUnit {
contentOffset: number; contentOffset: number;
abbrevOffset: number; abbrevOffset: number;
abbrevs: Abbrev[] = []; abbrevs: Abbrev[] = [];
root: {};
constructor(protected infoReader: ByteReader, protected debugstrs: DataView) { constructor(protected infoReader: ByteReader, protected debugstrs: DataView) {
const baseOffset = infoReader.offset; const baseOffset = infoReader.offset;
@ -860,33 +865,38 @@ class DWARFCompilationUnit {
this.abbrevs = parseAbbrevs(abbrevReader); this.abbrevs = parseAbbrevs(abbrevReader);
// extract slice with DIEs // extract slice with DIEs
const slice = this.infoReader.slice(this.contentOffset, this.contentLength); 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 // skip to next cu section
this.skip(); this.skip();
} }
processDIEs(reader: ByteReader) { processDIEs(reader: ByteReader) {
let die_stack = []; let die_stack : any[] = [{children:[]}];
// TODO: capture tree structure // TODO: capture tree structure
while (!reader.isEOF()) { while (!reader.isEOF()) {
let absolute_offset = reader.offset + this.contentOffset; let absolute_offset = reader.offset + this.contentOffset;
let abbrev_num = Number(reader.readUnsignedLEB128()); let abbrev_num = Number(reader.readUnsignedLEB128());
//console.log('DIE', absolute_offset.toString(16), abbrev_num); //console.log('DIE', absolute_offset.toString(16), abbrev_num);
if (abbrev_num == 0) { if (abbrev_num == 0) {
if (die_stack.length == 0) throw new Error('DIE stack underflow @ offset ' + reader.offset); let item = die_stack.pop();
die_stack.pop(); if (!item) throw new Error('DIE stack underflow @ offset ' + reader.offset);
continue; continue;
} }
let abbrev = this.abbrevs[abbrev_num - 1]; let abbrev = this.abbrevs[abbrev_num - 1];
if (!abbrev) throw new Error('Invalid abbreviation number ' + abbrev_num); if (!abbrev) throw new Error('Invalid abbreviation number ' + abbrev_num);
let obj = this.processDIE(reader, abbrev); 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) { if (abbrev.has_children) {
die_stack.push(obj); 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) { processDIE(reader: ByteReader, abbrev: Abbrev) {
//console.log('processDIE', abbrev); //console.log('processDIE', abbrev);
let obj = {}; let obj = {tag: DwarfTag[abbrev.tag]};
// iterate through attributes // iterate through attributes
for (let attr of abbrev.attributes) { for (let attr of abbrev.attributes) {
let form = attr.form; let form = attr.form;
@ -1153,7 +1163,6 @@ class DWARFLineInfo {
opcode -= this.opcode_base; opcode -= this.opcode_base;
let advance_address = Math.floor(opcode / this.line_range) * this.min_insn_length; let advance_address = Math.floor(opcode / this.line_range) * this.min_insn_length;
let advance_line = (opcode % this.line_range) + this.line_base; let advance_line = (opcode % this.line_range) + this.line_base;
//console.log('advance', advance_address, advance_line, this.lsm);
this.checkPassPC(); this.checkPassPC();
this.lsm.address += advance_address; this.lsm.address += advance_address;
this.lsm.line_num += advance_line; this.lsm.line_num += advance_line;
@ -1214,7 +1223,6 @@ class DWARFLineInfo {
case DwarfLineNumberOps.DW_LNS_extended_op: { case DwarfLineNumberOps.DW_LNS_extended_op: {
const extended_op_len = this.opReader.readUnsignedLEB128(); const extended_op_len = this.opReader.readUnsignedLEB128();
const extended_op = this.opReader.readOneByte(); const extended_op = this.opReader.readOneByte();
//console.log('extended', extended_op, extended_op_len);
switch (extended_op) { switch (extended_op) {
case DwarfLineNumberExtendedOps.DW_LNE_end_sequence: case DwarfLineNumberExtendedOps.DW_LNE_end_sequence:
this.lsm.end_sequence = true; this.lsm.end_sequence = true;
@ -1225,11 +1233,8 @@ class DWARFLineInfo {
case DwarfLineNumberExtendedOps.DW_LNE_define_file: case DwarfLineNumberExtendedOps.DW_LNE_define_file:
// TODO // TODO
break; break;
//case DwarfLineNumberExtendedOps.DW_LNE_set_discriminator:
// TODO
break;
default: default:
//console.log('Unknown DWARF extended opcode ' + extended_op); console.log('Unknown DWARF extended opcode ' + extended_op);
this.opReader.offset += Number(extended_op_len); this.opReader.offset += Number(extended_op_len);
break; break;
} }

View File

@ -66,7 +66,12 @@ class ARM32Platform extends BaseARMMachinePlatform<ARM32Machine> implements Plat
{name:'I/O',start:0x4000000,size:0x100,type:'io'}, {name:'I/O',start:0x4000000,size:0x100,type:'io'},
] } }; ] } };
getPlatformName() { return "ARM7"; } 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 { disassemble(pc:number, read:(addr:number)=>number) : DisasmLine {
var is_thumb = this.machine.cpu.isThumb(); var is_thumb = this.machine.cpu.isThumb();
var capstone = is_thumb ? this.capstone_thumb : this.capstone_arm; var capstone = is_thumb ? this.capstone_thumb : this.capstone_arm;

View File

@ -445,7 +445,8 @@ export async function linkARMTCC(step: BuildStep): Promise<WorkerResult> {
listings: listings, listings: listings,
errors: errors, errors: errors,
symbolmap: symbolmap, symbolmap: symbolmap,
segments: segments segments: segments,
debuginfo: dwarf
}; };
} }
} }