rlm@1: #include rlm@1: #include rlm@1: #include rlm@1: rlm@1: #include "../Port.h" rlm@1: #include "../NLS.h" rlm@1: #include "../common/System.h" // systemMessage rlm@1: #include "GBAGlobals.h" rlm@1: #include "elf.h" rlm@1: rlm@1: #define elfReadMemory(addr) \ rlm@1: READ32LE((&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) rlm@1: rlm@1: #define DW_TAG_array_type 0x01 rlm@1: #define DW_TAG_enumeration_type 0x04 rlm@1: #define DW_TAG_formal_parameter 0x05 rlm@1: #define DW_TAG_label 0x0a rlm@1: #define DW_TAG_lexical_block 0x0b rlm@1: #define DW_TAG_member 0x0d rlm@1: #define DW_TAG_pointer_type 0x0f rlm@1: #define DW_TAG_reference_type 0x10 rlm@1: #define DW_TAG_compile_unit 0x11 rlm@1: #define DW_TAG_structure_type 0x13 rlm@1: #define DW_TAG_subroutine_type 0x15 rlm@1: #define DW_TAG_typedef 0x16 rlm@1: #define DW_TAG_union_type 0x17 rlm@1: #define DW_TAG_unspecified_parameters 0x18 rlm@1: #define DW_TAG_inheritance 0x1c rlm@1: #define DW_TAG_inlined_subroutine 0x1d rlm@1: #define DW_TAG_subrange_type 0x21 rlm@1: #define DW_TAG_base_type 0x24 rlm@1: #define DW_TAG_const_type 0x26 rlm@1: #define DW_TAG_enumerator 0x28 rlm@1: #define DW_TAG_subprogram 0x2e rlm@1: #define DW_TAG_variable 0x34 rlm@1: #define DW_TAG_volatile_type 0x35 rlm@1: rlm@1: #define DW_AT_sibling 0x01 rlm@1: #define DW_AT_location 0x02 rlm@1: #define DW_AT_name 0x03 rlm@1: #define DW_AT_byte_size 0x0b rlm@1: #define DW_AT_bit_offset 0x0c rlm@1: #define DW_AT_bit_size 0x0d rlm@1: #define DW_AT_stmt_list 0x10 rlm@1: #define DW_AT_low_pc 0x11 rlm@1: #define DW_AT_high_pc 0x12 rlm@1: #define DW_AT_language 0x13 rlm@1: #define DW_AT_compdir 0x1b rlm@1: #define DW_AT_const_value 0x1c rlm@1: #define DW_AT_containing_type 0x1d rlm@1: #define DW_AT_inline 0x20 rlm@1: #define DW_AT_producer 0x25 rlm@1: #define DW_AT_prototyped 0x27 rlm@1: #define DW_AT_upper_bound 0x2f rlm@1: #define DW_AT_abstract_origin 0x31 rlm@1: #define DW_AT_accessibility 0x32 rlm@1: #define DW_AT_artificial 0x34 rlm@1: #define DW_AT_data_member_location 0x38 rlm@1: #define DW_AT_decl_file 0x3a rlm@1: #define DW_AT_decl_line 0x3b rlm@1: #define DW_AT_declaration 0x3c rlm@1: #define DW_AT_encoding 0x3e rlm@1: #define DW_AT_external 0x3f rlm@1: #define DW_AT_frame_base 0x40 rlm@1: #define DW_AT_macro_info 0x43 rlm@1: #define DW_AT_specification 0x47 rlm@1: #define DW_AT_type 0x49 rlm@1: #define DW_AT_virtuality 0x4c rlm@1: #define DW_AT_vtable_elem_location 0x4d rlm@1: // DWARF 2.1/3.0 extensions rlm@1: #define DW_AT_entry_pc 0x52 rlm@1: #define DW_AT_ranges 0x55 rlm@1: // ARM Compiler extensions rlm@1: #define DW_AT_proc_body 0x2000 rlm@1: #define DW_AT_save_offset 0x2001 rlm@1: #define DW_AT_user_2002 0x2002 rlm@1: // MIPS extensions rlm@1: #define DW_AT_MIPS_linkage_name 0x2007 rlm@1: rlm@1: #define DW_FORM_addr 0x01 rlm@1: #define DW_FORM_data2 0x05 rlm@1: #define DW_FORM_data4 0x06 rlm@1: #define DW_FORM_string 0x08 rlm@1: #define DW_FORM_block 0x09 rlm@1: #define DW_FORM_block1 0x0a rlm@1: #define DW_FORM_data1 0x0b rlm@1: #define DW_FORM_flag 0x0c rlm@1: #define DW_FORM_sdata 0x0d rlm@1: #define DW_FORM_strp 0x0e rlm@1: #define DW_FORM_udata 0x0f rlm@1: #define DW_FORM_ref_addr 0x10 rlm@1: #define DW_FORM_ref4 0x13 rlm@1: #define DW_FORM_ref_udata 0x15 rlm@1: #define DW_FORM_indirect 0x16 rlm@1: rlm@1: #define DW_OP_addr 0x03 rlm@1: #define DW_OP_plus_uconst 0x23 rlm@1: #define DW_OP_reg0 0x50 rlm@1: #define DW_OP_reg1 0x51 rlm@1: #define DW_OP_reg2 0x52 rlm@1: #define DW_OP_reg3 0x53 rlm@1: #define DW_OP_reg4 0x54 rlm@1: #define DW_OP_reg5 0x55 rlm@1: #define DW_OP_reg6 0x56 rlm@1: #define DW_OP_reg7 0x57 rlm@1: #define DW_OP_reg8 0x58 rlm@1: #define DW_OP_reg9 0x59 rlm@1: #define DW_OP_reg10 0x5a rlm@1: #define DW_OP_reg11 0x5b rlm@1: #define DW_OP_reg12 0x5c rlm@1: #define DW_OP_reg13 0x5d rlm@1: #define DW_OP_reg14 0x5e rlm@1: #define DW_OP_reg15 0x5f rlm@1: #define DW_OP_fbreg 0x91 rlm@1: rlm@1: #define DW_LNS_extended_op 0x00 rlm@1: #define DW_LNS_copy 0x01 rlm@1: #define DW_LNS_advance_pc 0x02 rlm@1: #define DW_LNS_advance_line 0x03 rlm@1: #define DW_LNS_set_file 0x04 rlm@1: #define DW_LNS_set_column 0x05 rlm@1: #define DW_LNS_negate_stmt 0x06 rlm@1: #define DW_LNS_set_basic_block 0x07 rlm@1: #define DW_LNS_const_add_pc 0x08 rlm@1: #define DW_LNS_fixed_advance_pc 0x09 rlm@1: rlm@1: #define DW_LNE_end_sequence 0x01 rlm@1: #define DW_LNE_set_address 0x02 rlm@1: #define DW_LNE_define_file 0x03 rlm@1: rlm@1: #define DW_CFA_advance_loc 0x01 rlm@1: #define DW_CFA_offset 0x02 rlm@1: #define DW_CFA_restore 0x03 rlm@1: #define DW_CFA_set_loc 0x01 rlm@1: #define DW_CFA_advance_loc1 0x02 rlm@1: #define DW_CFA_advance_loc2 0x03 rlm@1: #define DW_CFA_advance_loc4 0x04 rlm@1: #define DW_CFA_offset_extended 0x05 rlm@1: #define DW_CFA_restore_extended 0x06 rlm@1: #define DW_CFA_undefined 0x07 rlm@1: #define DW_CFA_same_value 0x08 rlm@1: #define DW_CFA_register 0x09 rlm@1: #define DW_CFA_remember_state 0x0a rlm@1: #define DW_CFA_restore_state 0x0b rlm@1: #define DW_CFA_def_cfa 0x0c rlm@1: #define DW_CFA_def_cfa_register 0x0d rlm@1: #define DW_CFA_def_cfa_offset 0x0e rlm@1: #define DW_CFA_nop 0x00 rlm@1: rlm@1: #define CASE_TYPE_TAG \ rlm@1: case DW_TAG_const_type: \ rlm@1: case DW_TAG_volatile_type: \ rlm@1: case DW_TAG_pointer_type: \ rlm@1: case DW_TAG_base_type: \ rlm@1: case DW_TAG_array_type: \ rlm@1: case DW_TAG_structure_type: \ rlm@1: case DW_TAG_union_type: \ rlm@1: case DW_TAG_typedef: \ rlm@1: case DW_TAG_subroutine_type: \ rlm@1: case DW_TAG_enumeration_type: \ rlm@1: case DW_TAG_enumerator: \ rlm@1: case DW_TAG_reference_type rlm@1: rlm@1: struct ELFcie rlm@1: { rlm@1: ELFcie *next; rlm@1: u32 offset; rlm@1: u8 * augmentation; rlm@1: u32 codeAlign; rlm@1: s32 dataAlign; rlm@1: int returnAddress; rlm@1: u8 * data; rlm@1: u32 dataLen; rlm@1: }; rlm@1: rlm@1: struct ELFfde rlm@1: { rlm@1: ELFcie *cie; rlm@1: u32 address; rlm@1: u32 end; rlm@1: u8 * data; rlm@1: u32 dataLen; rlm@1: }; rlm@1: rlm@1: enum ELFRegMode rlm@1: { rlm@1: REG_NOT_SET, rlm@1: REG_OFFSET, rlm@1: REG_REGISTER rlm@1: }; rlm@1: rlm@1: struct ELFFrameStateRegister rlm@1: { rlm@1: ELFRegMode mode; rlm@1: int reg; rlm@1: s32 offset; rlm@1: }; rlm@1: rlm@1: struct ELFFrameStateRegisters rlm@1: { rlm@1: ELFFrameStateRegister regs[16]; rlm@1: ELFFrameStateRegisters *previous; rlm@1: }; rlm@1: rlm@1: enum ELFCfaMode rlm@1: { rlm@1: CFA_NOT_SET, rlm@1: CFA_REG_OFFSET rlm@1: }; rlm@1: rlm@1: struct ELFFrameState rlm@1: { rlm@1: ELFFrameStateRegisters registers; rlm@1: rlm@1: ELFCfaMode cfaMode; rlm@1: int cfaRegister; rlm@1: s32 cfaOffset; rlm@1: rlm@1: u32 pc; rlm@1: rlm@1: int dataAlign; rlm@1: int codeAlign; rlm@1: int returnAddress; rlm@1: }; rlm@1: rlm@1: extern bool8 cpuIsMultiBoot; rlm@1: rlm@1: Symbol *elfSymbols = NULL; rlm@1: char * elfSymbolsStrTab = NULL; rlm@1: int elfSymbolsCount = 0; rlm@1: rlm@1: ELFSectionHeader **elfSectionHeaders = NULL; rlm@1: char *elfSectionHeadersStringTable = NULL; rlm@1: int elfSectionHeadersCount = 0; rlm@1: u8 * elfFileData = NULL; rlm@1: rlm@1: CompileUnit *elfCompileUnits = NULL; rlm@1: DebugInfo * elfDebugInfo = NULL; rlm@1: char * elfDebugStrings = NULL; rlm@1: rlm@1: ELFcie * elfCies = NULL; rlm@1: ELFfde **elfFdes = NULL; rlm@1: int elfFdeCount = 0; rlm@1: rlm@1: CompileUnit *elfCurrentUnit = NULL; rlm@1: rlm@1: u32 elfRead4Bytes(u8 *); rlm@1: u16 elfRead2Bytes(u8 *); rlm@1: rlm@1: CompileUnit *elfGetCompileUnit(u32 addr) rlm@1: { rlm@1: if (elfCompileUnits) rlm@1: { rlm@1: CompileUnit *unit = elfCompileUnits; rlm@1: while (unit) rlm@1: { rlm@1: if (unit->lowPC) rlm@1: { rlm@1: if (addr >= unit->lowPC && addr < unit->highPC) rlm@1: return unit; rlm@1: } rlm@1: else rlm@1: { rlm@1: ARanges *r = unit->ranges; rlm@1: if (r) rlm@1: { rlm@1: int count = r->count; rlm@1: for (int j = 0; j < count; j++) rlm@1: { rlm@1: if (addr >= r->ranges[j].lowPC && addr < r->ranges[j].highPC) rlm@1: return unit; rlm@1: } rlm@1: } rlm@1: } rlm@1: unit = unit->next; rlm@1: } rlm@1: } rlm@1: return NULL; rlm@1: } rlm@1: rlm@1: char *elfGetAddressSymbol(u32 addr) rlm@1: { rlm@1: static char buffer[256]; rlm@1: rlm@1: CompileUnit *unit = elfGetCompileUnit(addr); rlm@1: // found unit, need to find function rlm@1: if (unit) rlm@1: { rlm@1: Function *func = unit->functions; rlm@1: while (func) rlm@1: { rlm@1: if (addr >= func->lowPC && addr < func->highPC) rlm@1: { rlm@1: int offset = addr - func->lowPC; rlm@1: char *name = func->name; rlm@1: if (!name) rlm@1: name = ""; rlm@1: if (offset) rlm@1: sprintf(buffer, "%s+%d", name, offset); rlm@1: else rlm@1: strcpy(buffer, name); rlm@1: return buffer; rlm@1: } rlm@1: func = func->next; rlm@1: } rlm@1: } rlm@1: rlm@1: if (elfSymbolsCount) rlm@1: { rlm@1: for (int i = 0; i < elfSymbolsCount; i++) rlm@1: { rlm@1: Symbol *s = &elfSymbols[i]; rlm@1: if ((addr >= s->value) && addr < (s->value+s->size)) rlm@1: { rlm@1: int offset = addr-s->value; rlm@1: char *name = s->name; rlm@1: if (name == NULL) rlm@1: name = ""; rlm@1: if (offset) rlm@1: sprintf(buffer, "%s+%d", name, addr-s->value); rlm@1: else rlm@1: strcpy(buffer, name); rlm@1: return buffer; rlm@1: } rlm@1: else if (addr == s->value) rlm@1: { rlm@1: if (s->name) rlm@1: strcpy(buffer, s->name); rlm@1: else rlm@1: strcpy(buffer, ""); rlm@1: return buffer; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: return ""; rlm@1: } rlm@1: rlm@1: bool elfFindLineInModule(u32 *addr, char *name, int line) rlm@1: { rlm@1: CompileUnit *unit = elfCompileUnits; rlm@1: rlm@1: while (unit) rlm@1: { rlm@1: if (unit->lineInfoTable) rlm@1: { rlm@1: int i; rlm@1: int count = unit->lineInfoTable->fileCount; rlm@1: char *found = NULL; rlm@1: for (i = 0; i < count; i++) rlm@1: { rlm@1: if (strcmp(name, unit->lineInfoTable->files[i]) == 0) rlm@1: { rlm@1: found = unit->lineInfoTable->files[i]; rlm@1: break; rlm@1: } rlm@1: } rlm@1: // found a matching filename... try to find line now rlm@1: if (found) rlm@1: { rlm@1: LineInfoItem *table = unit->lineInfoTable->lines; rlm@1: count = unit->lineInfoTable->number; rlm@1: for (i = 0; i < count; i++) rlm@1: { rlm@1: if (table[i].file == found && table[i].line == line) rlm@1: { rlm@1: *addr = table[i].address; rlm@1: return true; rlm@1: } rlm@1: } rlm@1: // we can only find a single match rlm@1: return false; rlm@1: } rlm@1: } rlm@1: unit = unit->next; rlm@1: } rlm@1: return false; rlm@1: } rlm@1: rlm@1: int elfFindLine(CompileUnit *unit, Function * /* func */, u32 addr, char **f) rlm@1: { rlm@1: int currentLine = -1; rlm@1: if (unit->hasLineInfo) rlm@1: { rlm@1: int count = unit->lineInfoTable->number; rlm@1: LineInfoItem *table = unit->lineInfoTable->lines; rlm@1: int i; rlm@1: for (i = 0; i < count; i++) rlm@1: { rlm@1: if (addr <= table[i].address) rlm@1: break; rlm@1: } rlm@1: if (i == count) rlm@1: i--; rlm@1: *f = table[i].file; rlm@1: currentLine = table[i].line; rlm@1: } rlm@1: return currentLine; rlm@1: } rlm@1: rlm@1: bool elfFindLineInUnit(u32 *addr, CompileUnit *unit, int line) rlm@1: { rlm@1: if (unit->hasLineInfo) rlm@1: { rlm@1: int count = unit->lineInfoTable->number; rlm@1: LineInfoItem *table = unit->lineInfoTable->lines; rlm@1: int i; rlm@1: for (i = 0; i < count; i++) rlm@1: { rlm@1: if (line == table[i].line) rlm@1: { rlm@1: *addr = table[i].address; rlm@1: return true; rlm@1: } rlm@1: } rlm@1: } rlm@1: return false; rlm@1: } rlm@1: rlm@1: bool elfGetCurrentFunction(u32 addr, Function **f, CompileUnit **u) rlm@1: { rlm@1: CompileUnit *unit = elfGetCompileUnit(addr); rlm@1: // found unit, need to find function rlm@1: if (unit) rlm@1: { rlm@1: Function *func = unit->functions; rlm@1: while (func) rlm@1: { rlm@1: if (addr >= func->lowPC && addr < func->highPC) rlm@1: { rlm@1: *f = func; rlm@1: *u = unit; rlm@1: return true; rlm@1: } rlm@1: func = func->next; rlm@1: } rlm@1: } rlm@1: return false; rlm@1: } rlm@1: rlm@1: bool elfGetObject(char *name, Function *f, CompileUnit *u, Object **o) rlm@1: { rlm@1: if (f && u) rlm@1: { rlm@1: Object *v = f->variables; rlm@1: rlm@1: while (v) rlm@1: { rlm@1: if (strcmp(name, v->name) == 0) rlm@1: { rlm@1: *o = v; rlm@1: return true; rlm@1: } rlm@1: v = v->next; rlm@1: } rlm@1: v = f->parameters; rlm@1: while (v) rlm@1: { rlm@1: if (strcmp(name, v->name) == 0) rlm@1: { rlm@1: *o = v; rlm@1: return true; rlm@1: } rlm@1: v = v->next; rlm@1: } rlm@1: v = u->variables; rlm@1: while (v) rlm@1: { rlm@1: if (strcmp(name, v->name) == 0) rlm@1: { rlm@1: *o = v; rlm@1: return true; rlm@1: } rlm@1: v = v->next; rlm@1: } rlm@1: } rlm@1: rlm@1: CompileUnit *c = elfCompileUnits; rlm@1: rlm@1: while (c) rlm@1: { rlm@1: if (c != u) rlm@1: { rlm@1: Object *v = c->variables; rlm@1: while (v) rlm@1: { rlm@1: if (strcmp(name, v->name) == 0) rlm@1: { rlm@1: *o = v; rlm@1: return true; rlm@1: } rlm@1: v = v->next; rlm@1: } rlm@1: } rlm@1: c = c->next; rlm@1: } rlm@1: rlm@1: return false; rlm@1: } rlm@1: rlm@1: char *elfGetSymbol(int i, u32 *value, u32 *size, int *type) rlm@1: { rlm@1: if (i < elfSymbolsCount) rlm@1: { rlm@1: Symbol *s = &elfSymbols[i]; rlm@1: *value = s->value; rlm@1: *size = s->size; rlm@1: *type = s->type; rlm@1: return s->name; rlm@1: } rlm@1: return NULL; rlm@1: } rlm@1: rlm@1: bool elfGetSymbolAddress(char *sym, u32 *addr, u32 *size, int *type) rlm@1: { rlm@1: if (elfSymbolsCount) rlm@1: { rlm@1: for (int i = 0; i < elfSymbolsCount; i++) rlm@1: { rlm@1: Symbol *s = &elfSymbols[i]; rlm@1: if (strcmp(sym, s->name) == 0) rlm@1: { rlm@1: *addr = s->value; rlm@1: *size = s->size; rlm@1: *type = s->type; rlm@1: return true; rlm@1: } rlm@1: } rlm@1: } rlm@1: return false; rlm@1: } rlm@1: rlm@1: ELFfde *elfGetFde(u32 address) rlm@1: { rlm@1: if (elfFdes) rlm@1: { rlm@1: int i; rlm@1: for (i = 0; i < elfFdeCount; i++) rlm@1: { rlm@1: if (address >= elfFdes[i]->address && rlm@1: address < elfFdes[i]->end) rlm@1: { rlm@1: return elfFdes[i]; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: return NULL; rlm@1: } rlm@1: rlm@1: void elfExecuteCFAInstructions(ELFFrameState *state, u8 *data, u32 len, rlm@1: u32 pc) rlm@1: { rlm@1: u8 *end = data + len; rlm@1: int bytes; rlm@1: int reg; rlm@1: ELFFrameStateRegisters *fs; rlm@1: rlm@1: while (data < end && state->pc < pc) rlm@1: { rlm@1: u8 op = *data++; rlm@1: rlm@1: switch (op >> 6) rlm@1: { rlm@1: case DW_CFA_advance_loc: rlm@1: state->pc += (op & 0x3f) * state->codeAlign; rlm@1: break; rlm@1: case DW_CFA_offset: rlm@1: reg = op & 0x3f; rlm@1: state->registers.regs[reg].mode = REG_OFFSET; rlm@1: state->registers.regs[reg].offset = state->dataAlign * rlm@1: (s32)elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: break; rlm@1: case DW_CFA_restore: rlm@1: // we don't care much about the other possible settings, rlm@1: // so just setting to unset is enough for now rlm@1: state->registers.regs[op & 0x3f].mode = REG_NOT_SET; rlm@1: break; rlm@1: case 0: rlm@1: switch (op & 0x3f) rlm@1: { rlm@1: case DW_CFA_nop: rlm@1: break; rlm@1: case DW_CFA_advance_loc1: rlm@1: state->pc += state->codeAlign * (*data++); rlm@1: break; rlm@1: case DW_CFA_advance_loc2: rlm@1: state->pc += state->codeAlign * elfRead2Bytes(data); rlm@1: data += 2; rlm@1: break; rlm@1: case DW_CFA_advance_loc4: rlm@1: state->pc += state->codeAlign * elfRead4Bytes(data); rlm@1: data += 4; rlm@1: break; rlm@1: case DW_CFA_offset_extended: rlm@1: reg = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: state->registers.regs[reg].mode = REG_OFFSET; rlm@1: state->registers.regs[reg].offset = state->dataAlign * rlm@1: (s32)elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: break; rlm@1: case DW_CFA_restore_extended: rlm@1: case DW_CFA_undefined: rlm@1: case DW_CFA_same_value: rlm@1: reg = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: state->registers.regs[reg].mode = REG_NOT_SET; rlm@1: break; rlm@1: case DW_CFA_register: rlm@1: reg = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: state->registers.regs[reg].mode = REG_REGISTER; rlm@1: state->registers.regs[reg].reg = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: break; rlm@1: case DW_CFA_remember_state: rlm@1: fs = (ELFFrameStateRegisters *)calloc(1, rlm@1: sizeof(ELFFrameStateRegisters)); rlm@1: memcpy(fs, &state->registers, sizeof(ELFFrameStateRegisters)); rlm@1: state->registers.previous = fs; rlm@1: break; rlm@1: case DW_CFA_restore_state: rlm@1: if (state->registers.previous == NULL) rlm@1: { rlm@1: printf("Error: previous frame state is NULL.\n"); rlm@1: return; rlm@1: } rlm@1: fs = state->registers.previous; rlm@1: memcpy(&state->registers, fs, sizeof(ELFFrameStateRegisters)); rlm@1: free(fs); rlm@1: break; rlm@1: case DW_CFA_def_cfa: rlm@1: state->cfaRegister = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: state->cfaOffset = (s32)elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: state->cfaMode = CFA_REG_OFFSET; rlm@1: break; rlm@1: case DW_CFA_def_cfa_register: rlm@1: state->cfaRegister = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: state->cfaMode = CFA_REG_OFFSET; rlm@1: break; rlm@1: case DW_CFA_def_cfa_offset: rlm@1: state->cfaOffset = (s32)elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: state->cfaMode = CFA_REG_OFFSET; rlm@1: break; rlm@1: default: rlm@1: printf("Unknown CFA opcode %08x\n", op); rlm@1: return; rlm@1: } rlm@1: break; rlm@1: default: rlm@1: printf("Unknown CFA opcode %08x\n", op); rlm@1: return; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: ELFFrameState *elfGetFrameState(ELFfde *fde, u32 address) rlm@1: { rlm@1: ELFFrameState *state = (ELFFrameState *)calloc(1, sizeof(ELFFrameState)); rlm@1: state->pc = fde->address; rlm@1: state->dataAlign = fde->cie->dataAlign; rlm@1: state->codeAlign = fde->cie->codeAlign; rlm@1: state->returnAddress = fde->cie->returnAddress; rlm@1: rlm@1: elfExecuteCFAInstructions(state, rlm@1: fde->cie->data, rlm@1: fde->cie->dataLen, rlm@1: 0xffffffff); rlm@1: elfExecuteCFAInstructions(state, rlm@1: fde->data, rlm@1: fde->dataLen, rlm@1: address); rlm@1: rlm@1: return state; rlm@1: } rlm@1: rlm@1: void elfPrintCallChain(u32 address) rlm@1: { rlm@1: int count = 1; rlm@1: rlm@1: reg_pair regs[15]; rlm@1: reg_pair newRegs[15]; rlm@1: rlm@1: memcpy(®s[0], ®[0], sizeof(reg_pair) * 15); rlm@1: rlm@1: while (count < 20) rlm@1: { rlm@1: char *addr = elfGetAddressSymbol(address); rlm@1: if (*addr == 0) rlm@1: addr = "???"; rlm@1: rlm@1: printf("%08x %s\n", address, addr); rlm@1: rlm@1: ELFfde *fde = elfGetFde(address); rlm@1: rlm@1: if (fde == NULL) rlm@1: { rlm@1: break; rlm@1: } rlm@1: rlm@1: ELFFrameState *state = elfGetFrameState(fde, address); rlm@1: rlm@1: if (!state) rlm@1: { rlm@1: break; rlm@1: } rlm@1: rlm@1: if (state->cfaMode == CFA_REG_OFFSET) rlm@1: { rlm@1: memcpy(&newRegs[0], ®s[0], sizeof(reg_pair) * 15); rlm@1: u32 addr = 0; rlm@1: for (int i = 0; i < 15; i++) rlm@1: { rlm@1: ELFFrameStateRegister *r = &state->registers. rlm@1: regs[i]; rlm@1: rlm@1: switch (r->mode) rlm@1: { rlm@1: case REG_NOT_SET: rlm@1: newRegs[i].I = regs[i].I; rlm@1: break; rlm@1: case REG_OFFSET: rlm@1: newRegs[i].I = elfReadMemory(regs[state->cfaRegister].I + rlm@1: state->cfaOffset + rlm@1: r->offset); rlm@1: break; rlm@1: case REG_REGISTER: rlm@1: newRegs[i].I = regs[r->reg].I; rlm@1: break; rlm@1: default: rlm@1: printf("Unknown register mode: %d\n", r->mode); rlm@1: break; rlm@1: } rlm@1: } rlm@1: memcpy(regs, newRegs, sizeof(reg_pair)*15); rlm@1: addr = newRegs[14].I; rlm@1: addr &= 0xfffffffe; rlm@1: address = addr; rlm@1: count++; rlm@1: } rlm@1: else rlm@1: { rlm@1: printf("CFA not set\n"); rlm@1: break; rlm@1: } rlm@1: if (state->registers.previous) rlm@1: { rlm@1: ELFFrameStateRegisters *prev = state->registers.previous; rlm@1: rlm@1: while (prev) rlm@1: { rlm@1: ELFFrameStateRegisters *p = prev->previous; rlm@1: free(prev); rlm@1: prev = p; rlm@1: } rlm@1: } rlm@1: free(state); rlm@1: } rlm@1: } rlm@1: rlm@1: u32 elfDecodeLocation(Function *f, ELFBlock *o, LocationType *type, u32 base) rlm@1: { rlm@1: u32 framebase = 0; rlm@1: if (f && f->frameBase) rlm@1: { rlm@1: ELFBlock *b = f->frameBase; rlm@1: switch (*b->data) rlm@1: { rlm@1: case DW_OP_reg0: rlm@1: case DW_OP_reg1: rlm@1: case DW_OP_reg2: rlm@1: case DW_OP_reg3: rlm@1: case DW_OP_reg4: rlm@1: case DW_OP_reg5: rlm@1: case DW_OP_reg6: rlm@1: case DW_OP_reg7: rlm@1: case DW_OP_reg8: rlm@1: case DW_OP_reg9: rlm@1: case DW_OP_reg10: rlm@1: case DW_OP_reg11: rlm@1: case DW_OP_reg12: rlm@1: case DW_OP_reg13: rlm@1: case DW_OP_reg14: rlm@1: case DW_OP_reg15: rlm@1: framebase = reg[*b->data-0x50].I; rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown frameBase %02x\n", *b->data); rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: ELFBlock *loc = o; rlm@1: u32 location = 0; rlm@1: int bytes = 0; rlm@1: if (loc) rlm@1: { rlm@1: switch (*loc->data) rlm@1: { rlm@1: case DW_OP_addr: rlm@1: location = elfRead4Bytes(loc->data+1); rlm@1: *type = LOCATION_memory; rlm@1: break; rlm@1: case DW_OP_plus_uconst: rlm@1: location = base + elfReadLEB128(loc->data+1, &bytes); rlm@1: *type = LOCATION_memory; rlm@1: break; rlm@1: case DW_OP_reg0: rlm@1: case DW_OP_reg1: rlm@1: case DW_OP_reg2: rlm@1: case DW_OP_reg3: rlm@1: case DW_OP_reg4: rlm@1: case DW_OP_reg5: rlm@1: case DW_OP_reg6: rlm@1: case DW_OP_reg7: rlm@1: case DW_OP_reg8: rlm@1: case DW_OP_reg9: rlm@1: case DW_OP_reg10: rlm@1: case DW_OP_reg11: rlm@1: case DW_OP_reg12: rlm@1: case DW_OP_reg13: rlm@1: case DW_OP_reg14: rlm@1: case DW_OP_reg15: rlm@1: location = *loc->data - 0x50; rlm@1: *type = LOCATION_register; rlm@1: break; rlm@1: case DW_OP_fbreg: rlm@1: { rlm@1: int bytes; rlm@1: s32 off = elfReadSignedLEB128(loc->data+1, &bytes); rlm@1: location = framebase + off; rlm@1: *type = LOCATION_memory; rlm@1: break; rlm@1: } rlm@1: default: rlm@1: fprintf(stderr, "Unknown location %02x\n", *loc->data); rlm@1: break; rlm@1: } rlm@1: } rlm@1: return location; rlm@1: } rlm@1: rlm@1: u32 elfDecodeLocation(Function *f, ELFBlock *o, LocationType *type) rlm@1: { rlm@1: return elfDecodeLocation(f, o, type, 0); rlm@1: } rlm@1: rlm@1: // reading function rlm@1: rlm@1: u32 elfRead4Bytes(u8 *data) rlm@1: { rlm@1: u32 value = *data++; rlm@1: value |= (*data++ << 8); rlm@1: value |= (*data++ << 16); rlm@1: value |= (*data << 24); rlm@1: return value; rlm@1: } rlm@1: rlm@1: u16 elfRead2Bytes(u8 *data) rlm@1: { rlm@1: u16 value = *data++; rlm@1: value |= (*data << 8); rlm@1: return value; rlm@1: } rlm@1: rlm@1: char *elfReadString(u8 *data, int *bytesRead) rlm@1: { rlm@1: if (*data == 0) rlm@1: { rlm@1: *bytesRead = 1; rlm@1: return NULL; rlm@1: } rlm@1: *bytesRead = strlen((char *)data) + 1; rlm@1: return (char *)data; rlm@1: } rlm@1: rlm@1: s32 elfReadSignedLEB128(u8 *data, int *bytesRead) rlm@1: { rlm@1: s32 result = 0; rlm@1: int shift = 0; rlm@1: int count = 0; rlm@1: rlm@1: u8 byte; rlm@1: do rlm@1: { rlm@1: byte = *data++; rlm@1: count++; rlm@1: result |= (byte & 0x7f) << shift; rlm@1: shift += 7; rlm@1: } rlm@1: while (byte & 0x80); rlm@1: if ((shift < 32) && (byte & 0x40)) rlm@1: result |= -(1 << shift); rlm@1: *bytesRead = count; rlm@1: return result; rlm@1: } rlm@1: rlm@1: u32 elfReadLEB128(u8 *data, int *bytesRead) rlm@1: { rlm@1: u32 result = 0; rlm@1: int shift = 0; rlm@1: int count = 0; rlm@1: u8 byte; rlm@1: do rlm@1: { rlm@1: byte = *data++; rlm@1: count++; rlm@1: result |= (byte & 0x7f) << shift; rlm@1: shift += 7; rlm@1: } rlm@1: while (byte & 0x80); rlm@1: *bytesRead = count; rlm@1: return result; rlm@1: } rlm@1: rlm@1: u8 *elfReadSection(u8 *data, ELFSectionHeader *sh) rlm@1: { rlm@1: return data + READ32LE(&sh->offset); rlm@1: } rlm@1: rlm@1: ELFSectionHeader *elfGetSectionByName(char *name) rlm@1: { rlm@1: for (int i = 0; i < elfSectionHeadersCount; i++) rlm@1: { rlm@1: if (strcmp(name, rlm@1: &elfSectionHeadersStringTable[READ32LE(&elfSectionHeaders[i]-> rlm@1: name)]) == 0) rlm@1: { rlm@1: return elfSectionHeaders[i]; rlm@1: } rlm@1: } rlm@1: return NULL; rlm@1: } rlm@1: rlm@1: ELFSectionHeader *elfGetSectionByNumber(int number) rlm@1: { rlm@1: if (number < elfSectionHeadersCount) rlm@1: { rlm@1: return elfSectionHeaders[number]; rlm@1: } rlm@1: return NULL; rlm@1: } rlm@1: rlm@1: CompileUnit *elfGetCompileUnitForData(u8 *data) rlm@1: { rlm@1: u8 *end = elfCurrentUnit->top + 4 + elfCurrentUnit->length; rlm@1: rlm@1: if (data >= elfCurrentUnit->top && data < end) rlm@1: return elfCurrentUnit; rlm@1: rlm@1: CompileUnit *unit = elfCompileUnits; rlm@1: rlm@1: while (unit) rlm@1: { rlm@1: end = unit->top + 4 + unit->length; rlm@1: rlm@1: if (data >= unit->top && data < end) rlm@1: return unit; rlm@1: rlm@1: unit = unit->next; rlm@1: } rlm@1: rlm@1: printf("Error: cannot find reference to compile unit at offset %08x\n", rlm@1: (int)(data - elfDebugInfo->infodata)); rlm@1: exit(-1); rlm@1: } rlm@1: rlm@1: u8 *elfReadAttribute(u8 *data, ELFAttr *attr) rlm@1: { rlm@1: int bytes; rlm@1: int form = attr->form; rlm@1: start: rlm@1: switch (form) rlm@1: { rlm@1: case DW_FORM_addr: rlm@1: attr->value = elfRead4Bytes(data); rlm@1: data += 4; rlm@1: break; rlm@1: case DW_FORM_data2: rlm@1: attr->value = elfRead2Bytes(data); rlm@1: data += 2; rlm@1: break; rlm@1: case DW_FORM_data4: rlm@1: attr->value = elfRead4Bytes(data); rlm@1: data += 4; rlm@1: break; rlm@1: case DW_FORM_string: rlm@1: attr->string = (char *)data; rlm@1: data += strlen(attr->string)+1; rlm@1: break; rlm@1: case DW_FORM_strp: rlm@1: attr->string = elfDebugStrings + elfRead4Bytes(data); rlm@1: data += 4; rlm@1: break; rlm@1: case DW_FORM_block: rlm@1: attr->block = (ELFBlock *)malloc(sizeof(ELFBlock)); rlm@1: attr->block->length = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: attr->block->data = data; rlm@1: data += attr->block->length; rlm@1: break; rlm@1: case DW_FORM_block1: rlm@1: attr->block = (ELFBlock *)malloc(sizeof(ELFBlock)); rlm@1: attr->block->length = *data++; rlm@1: attr->block->data = data; rlm@1: data += attr->block->length; rlm@1: break; rlm@1: case DW_FORM_data1: rlm@1: attr->value = *data++; rlm@1: break; rlm@1: case DW_FORM_flag: rlm@1: attr->flag = (*data++) ? true : false; rlm@1: break; rlm@1: case DW_FORM_sdata: rlm@1: attr->value = elfReadSignedLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: break; rlm@1: case DW_FORM_udata: rlm@1: attr->value = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: break; rlm@1: case DW_FORM_ref_addr: rlm@1: attr->value = (elfDebugInfo->infodata + elfRead4Bytes(data)) - rlm@1: elfGetCompileUnitForData(data)->top; rlm@1: data += 4; rlm@1: break; rlm@1: case DW_FORM_ref4: rlm@1: attr->value = elfRead4Bytes(data); rlm@1: data += 4; rlm@1: break; rlm@1: case DW_FORM_ref_udata: rlm@1: attr->value = (elfDebugInfo->infodata + rlm@1: (elfGetCompileUnitForData(data)->top - rlm@1: elfDebugInfo->infodata) + rlm@1: elfReadLEB128(data, &bytes)) - rlm@1: elfCurrentUnit->top; rlm@1: data += bytes; rlm@1: break; rlm@1: case DW_FORM_indirect: rlm@1: form = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: goto start; rlm@1: default: rlm@1: fprintf(stderr, "Unsupported FORM %02x\n", form); rlm@1: exit(-1); rlm@1: } rlm@1: return data; rlm@1: } rlm@1: rlm@1: ELFAbbrev *elfGetAbbrev(ELFAbbrev **table, u32 number) rlm@1: { rlm@1: int hash = number % 121; rlm@1: rlm@1: ELFAbbrev *abbrev = table[hash]; rlm@1: rlm@1: while (abbrev) rlm@1: { rlm@1: if (abbrev->number == number) rlm@1: return abbrev; rlm@1: abbrev = abbrev->next; rlm@1: } rlm@1: return NULL; rlm@1: } rlm@1: rlm@1: ELFAbbrev * *elfReadAbbrevs(u8 *data, u32 offset) rlm@1: { rlm@1: data += offset; rlm@1: ELFAbbrev **abbrevs = (ELFAbbrev * *)calloc(sizeof(ELFAbbrev *)*121, 1); rlm@1: int bytes = 0; rlm@1: u32 number = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: while (number) rlm@1: { rlm@1: ELFAbbrev *abbrev = (ELFAbbrev *)calloc(sizeof(ELFAbbrev), 1); rlm@1: rlm@1: // read tag information rlm@1: abbrev->number = number; rlm@1: abbrev->tag = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: abbrev->hasChildren = *data++ ? true : false; rlm@1: rlm@1: // read attributes rlm@1: int name = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: int form = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: rlm@1: while (name) rlm@1: { rlm@1: if ((abbrev->numAttrs % 4) == 0) rlm@1: { rlm@1: abbrev->attrs = (ELFAttr *)realloc(abbrev->attrs, rlm@1: (abbrev->numAttrs + 4) * rlm@1: sizeof(ELFAttr)); rlm@1: } rlm@1: abbrev->attrs[abbrev->numAttrs].name = name; rlm@1: abbrev->attrs[abbrev->numAttrs++].form = form; rlm@1: rlm@1: name = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: form = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: } rlm@1: rlm@1: int hash = number % 121; rlm@1: abbrev->next = abbrevs[hash]; rlm@1: abbrevs[hash] = abbrev; rlm@1: rlm@1: number = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: rlm@1: if (elfGetAbbrev(abbrevs, number) != NULL) rlm@1: break; rlm@1: } rlm@1: rlm@1: return abbrevs; rlm@1: } rlm@1: rlm@1: void elfParseCFA(u8 *top) rlm@1: { rlm@1: ELFSectionHeader *h = elfGetSectionByName(".debug_frame"); rlm@1: rlm@1: if (h == NULL) rlm@1: { rlm@1: return; rlm@1: } rlm@1: rlm@1: u8 *data = elfReadSection(top, h); rlm@1: rlm@1: u8 *topOffset = data; rlm@1: rlm@1: u8 *end = data + READ32LE(&h->size); rlm@1: rlm@1: ELFcie *cies = NULL; rlm@1: rlm@1: while (data < end) rlm@1: { rlm@1: u32 offset = data - topOffset; rlm@1: u32 len = elfRead4Bytes(data); rlm@1: data += 4; rlm@1: rlm@1: u8 *dataEnd = data + len; rlm@1: rlm@1: u32 id = elfRead4Bytes(data); rlm@1: data += 4; rlm@1: rlm@1: if (id == 0xffffffff) rlm@1: { rlm@1: // skip version rlm@1: *data++; rlm@1: rlm@1: ELFcie *cie = (ELFcie *)calloc(1, sizeof(ELFcie)); rlm@1: rlm@1: cie->next = cies; rlm@1: cies = cie; rlm@1: rlm@1: cie->offset = offset; rlm@1: rlm@1: cie->augmentation = data; rlm@1: while (*data) rlm@1: data++; rlm@1: data++; rlm@1: rlm@1: if (*cie->augmentation) rlm@1: { rlm@1: fprintf(stderr, "Error: augmentation not supported\n"); rlm@1: exit(-1); rlm@1: } rlm@1: rlm@1: int bytes; rlm@1: cie->codeAlign = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: rlm@1: cie->dataAlign = elfReadSignedLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: rlm@1: cie->returnAddress = *data++; rlm@1: rlm@1: cie->data = data; rlm@1: cie->dataLen = dataEnd - data; rlm@1: } rlm@1: else rlm@1: { rlm@1: ELFfde *fde = (ELFfde *)calloc(1, sizeof(ELFfde)); rlm@1: rlm@1: ELFcie *cie = cies; rlm@1: rlm@1: while (cie != NULL) rlm@1: { rlm@1: if (cie->offset == id) rlm@1: break; rlm@1: cie = cie->next; rlm@1: } rlm@1: rlm@1: if (!cie) rlm@1: { rlm@1: fprintf(stderr, "Cannot find CIE %08x\n", id); rlm@1: exit(-1); rlm@1: } rlm@1: rlm@1: fde->cie = cie; rlm@1: rlm@1: fde->address = elfRead4Bytes(data); rlm@1: data += 4; rlm@1: rlm@1: fde->end = fde->address + elfRead4Bytes(data); rlm@1: data += 4; rlm@1: rlm@1: fde->data = data; rlm@1: fde->dataLen = dataEnd - data; rlm@1: rlm@1: if ((elfFdeCount %10) == 0) rlm@1: { rlm@1: elfFdes = (ELFfde * *)realloc(elfFdes, (elfFdeCount+10) * rlm@1: sizeof(ELFfde *)); rlm@1: } rlm@1: elfFdes[elfFdeCount++] = fde; rlm@1: } rlm@1: data = dataEnd; rlm@1: } rlm@1: rlm@1: elfCies = cies; rlm@1: } rlm@1: rlm@1: void elfAddLine(LineInfo *l, u32 a, int file, int line, int *max) rlm@1: { rlm@1: if (l->number == *max) rlm@1: { rlm@1: *max += 1000; rlm@1: l->lines = (LineInfoItem *)realloc(l->lines, *max*sizeof(LineInfoItem)); rlm@1: } rlm@1: LineInfoItem *li = &l->lines[l->number]; rlm@1: li->file = l->files[file-1]; rlm@1: li->address = a; rlm@1: li->line = line; rlm@1: l->number++; rlm@1: } rlm@1: rlm@1: void elfParseLineInfo(CompileUnit *unit, u8 *top) rlm@1: { rlm@1: ELFSectionHeader *h = elfGetSectionByName(".debug_line"); rlm@1: if (h == NULL) rlm@1: { rlm@1: fprintf(stderr, "No line information found\n"); rlm@1: return; rlm@1: } rlm@1: LineInfo *l = unit->lineInfoTable = (LineInfo *)calloc(1, sizeof(LineInfo)); rlm@1: l->number = 0; rlm@1: int max = 1000; rlm@1: l->lines = (LineInfoItem *)malloc(1000*sizeof(LineInfoItem)); rlm@1: rlm@1: u8 *data = elfReadSection(top, h); rlm@1: data += unit->lineInfo; rlm@1: u32 totalLen = elfRead4Bytes(data); rlm@1: data += 4; rlm@1: u8 *end = data + totalLen; rlm@1: // u16 version = elfRead2Bytes(data); rlm@1: data += 2; rlm@1: // u32 offset = elfRead4Bytes(data); rlm@1: data += 4; rlm@1: int minInstrSize = *data++; rlm@1: int defaultIsStmt = *data++; rlm@1: int lineBase = (s8)*data++; rlm@1: int lineRange = *data++; rlm@1: int opcodeBase = *data++; rlm@1: u8 *stdOpLen = (u8 *)malloc(opcodeBase * sizeof(u8)); rlm@1: stdOpLen[0] = 1; rlm@1: int i; rlm@1: for (i = 1; i < opcodeBase; i++) rlm@1: stdOpLen[i] = *data++; rlm@1: rlm@1: free(stdOpLen); // todo rlm@1: int bytes = 0; rlm@1: rlm@1: char *s; rlm@1: while ((s = elfReadString(data, &bytes)) != NULL) rlm@1: { rlm@1: data += bytes; rlm@1: // fprintf(stderr, "Directory is %s\n", s); rlm@1: } rlm@1: data += bytes; rlm@1: int count = 4; rlm@1: int index = 0; rlm@1: l->files = (char * *)malloc(sizeof(char *)*count); rlm@1: rlm@1: while ((s = elfReadString(data, &bytes)) != NULL) rlm@1: { rlm@1: l->files[index++] = s; rlm@1: rlm@1: data += bytes; rlm@1: // directory rlm@1: elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: // time rlm@1: elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: // size rlm@1: elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: // fprintf(stderr, "File is %s\n", s); rlm@1: if (index == count) rlm@1: { rlm@1: count += 4; rlm@1: l->files = (char * *)realloc(l->files, sizeof(char *)*count); rlm@1: } rlm@1: } rlm@1: l->fileCount = index; rlm@1: data += bytes; rlm@1: rlm@1: while (data < end) rlm@1: { rlm@1: u32 address = 0; rlm@1: int file = 1; rlm@1: int line = 1; rlm@1: int col = 0; rlm@1: int isStmt = defaultIsStmt; rlm@1: int basicBlock = 0; rlm@1: int endSeq = 0; rlm@1: rlm@1: while (!endSeq) rlm@1: { rlm@1: int op = *data++; rlm@1: switch (op) rlm@1: { rlm@1: case DW_LNS_extended_op: rlm@1: { rlm@1: data++; rlm@1: op = *data++; rlm@1: switch (op) rlm@1: { rlm@1: case DW_LNE_end_sequence: rlm@1: endSeq = 1; rlm@1: break; rlm@1: case DW_LNE_set_address: rlm@1: address = elfRead4Bytes(data); rlm@1: data += 4; rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown extended LINE opcode %02x\n", op); rlm@1: exit(-1); rlm@1: } rlm@1: break; rlm@1: } rlm@1: case DW_LNS_copy: rlm@1: // fprintf(stderr, "Address %08x line %d (%d)\n", address, line, file); rlm@1: elfAddLine(l, address, file, line, &max); rlm@1: basicBlock = 0; rlm@1: break; rlm@1: case DW_LNS_advance_pc: rlm@1: address += minInstrSize * elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: break; rlm@1: case DW_LNS_advance_line: rlm@1: line += elfReadSignedLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: break; rlm@1: case DW_LNS_set_file: rlm@1: file = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: break; rlm@1: case DW_LNS_set_column: rlm@1: col = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: break; rlm@1: case DW_LNS_negate_stmt: rlm@1: isStmt = !isStmt; rlm@1: break; rlm@1: case DW_LNS_set_basic_block: rlm@1: basicBlock = 1; rlm@1: break; rlm@1: case DW_LNS_const_add_pc: rlm@1: address += (minInstrSize *((255 - opcodeBase)/lineRange)); rlm@1: break; rlm@1: case DW_LNS_fixed_advance_pc: rlm@1: address += elfRead2Bytes(data); rlm@1: data += 2; rlm@1: break; rlm@1: default: rlm@1: op = op - opcodeBase; rlm@1: address += (op / lineRange) * minInstrSize; rlm@1: line += lineBase + (op % lineRange); rlm@1: elfAddLine(l, address, file, line, &max); rlm@1: // fprintf(stderr, "Address %08x line %d (%d)\n", address, line,file); rlm@1: basicBlock = 1; rlm@1: break; rlm@1: } rlm@1: } rlm@1: } rlm@1: l->lines = (LineInfoItem *)realloc(l->lines, l->number*sizeof(LineInfoItem)); rlm@1: } rlm@1: rlm@1: u8 *elfSkipData(u8 *data, ELFAbbrev *abbrev, ELFAbbrev **abbrevs) rlm@1: { rlm@1: int i; rlm@1: int bytes; rlm@1: rlm@1: for (i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: data = elfReadAttribute(data, &abbrev->attrs[i]); rlm@1: if (abbrev->attrs[i].form == DW_FORM_block1) rlm@1: free(abbrev->attrs[i].block); rlm@1: } rlm@1: rlm@1: if (abbrev->hasChildren) rlm@1: { rlm@1: int nesting = 1; rlm@1: while (nesting) rlm@1: { rlm@1: u32 abbrevNum = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: rlm@1: if (!abbrevNum) rlm@1: { rlm@1: nesting--; rlm@1: continue; rlm@1: } rlm@1: rlm@1: abbrev = elfGetAbbrev(abbrevs, abbrevNum); rlm@1: rlm@1: for (i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: data = elfReadAttribute(data, &abbrev->attrs[i]); rlm@1: if (abbrev->attrs[i].form == DW_FORM_block1) rlm@1: free(abbrev->attrs[i].block); rlm@1: } rlm@1: rlm@1: if (abbrev->hasChildren) rlm@1: { rlm@1: nesting++; rlm@1: } rlm@1: } rlm@1: } rlm@1: return data; rlm@1: } rlm@1: rlm@1: Type *elfParseType(CompileUnit *unit, u32); rlm@1: u8 *elfParseObject(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit, rlm@1: Object **object); rlm@1: u8 *elfParseFunction(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit, rlm@1: Function **function); rlm@1: void elfCleanUp(Function *); rlm@1: rlm@1: void elfAddType(Type *type, CompileUnit *unit, u32 offset) rlm@1: { rlm@1: if (type->next == NULL) rlm@1: { rlm@1: if (unit->types != type && type->offset == 0) rlm@1: { rlm@1: type->offset = offset; rlm@1: type->next = unit->types; rlm@1: unit->types = type; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: void elfParseType(u8 *data, u32 offset, ELFAbbrev *abbrev, CompileUnit *unit, rlm@1: Type **type) rlm@1: { rlm@1: switch (abbrev->tag) rlm@1: { rlm@1: case DW_TAG_typedef: rlm@1: { rlm@1: u32 typeref = 0; rlm@1: char *name = NULL; rlm@1: for (int i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbrev->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_name: rlm@1: name = attr->string; rlm@1: break; rlm@1: case DW_AT_type: rlm@1: typeref = attr->value; rlm@1: break; rlm@1: case DW_AT_decl_file: rlm@1: case DW_AT_decl_line: rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown attribute for typedef %02x\n", attr->name); rlm@1: break; rlm@1: } rlm@1: } rlm@1: if (abbrev->hasChildren) rlm@1: fprintf(stderr, "Unexpected children for typedef\n"); rlm@1: *type = elfParseType(unit, typeref); rlm@1: if (name) rlm@1: (*type)->name = name; rlm@1: return; rlm@1: break; rlm@1: } rlm@1: case DW_TAG_union_type: rlm@1: case DW_TAG_structure_type: rlm@1: { rlm@1: Type *t = (Type *)calloc(sizeof(Type), 1); rlm@1: if (abbrev->tag == DW_TAG_structure_type) rlm@1: t->type = TYPE_struct; rlm@1: else rlm@1: t->type = TYPE_union; rlm@1: rlm@1: Struct *s = (Struct *)calloc(sizeof(Struct), 1); rlm@1: t->structure = s; rlm@1: elfAddType(t, unit, offset); rlm@1: rlm@1: for (int i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbrev->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_name: rlm@1: t->name = attr->string; rlm@1: break; rlm@1: case DW_AT_byte_size: rlm@1: t->size = attr->value; rlm@1: break; rlm@1: case DW_AT_decl_file: rlm@1: case DW_AT_decl_line: rlm@1: case DW_AT_sibling: rlm@1: case DW_AT_containing_type: // todo? rlm@1: case DW_AT_declaration: rlm@1: case DW_AT_specification: // TODO: rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown attribute for struct %02x\n", attr->name); rlm@1: break; rlm@1: } rlm@1: } rlm@1: if (abbrev->hasChildren) rlm@1: { rlm@1: int bytes; rlm@1: u32 num = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: int index = 0; rlm@1: while (num) rlm@1: { rlm@1: ELFAbbrev *abbr = elfGetAbbrev(unit->abbrevs, num); rlm@1: rlm@1: switch (abbr->tag) rlm@1: { rlm@1: case DW_TAG_member: rlm@1: { rlm@1: if ((index % 4) == 0) rlm@1: s->members = (Member *)realloc(s->members, rlm@1: sizeof(Member)*(index+4)); rlm@1: Member *m = &s->members[index]; rlm@1: m->location = NULL; rlm@1: m->bitOffset = 0; rlm@1: m->bitSize = 0; rlm@1: m->byteSize = 0; rlm@1: for (int i = 0; i < abbr->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbr->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_name: rlm@1: m->name = attr->string; rlm@1: break; rlm@1: case DW_AT_type: rlm@1: m->type = elfParseType(unit, attr->value); rlm@1: break; rlm@1: case DW_AT_data_member_location: rlm@1: m->location = attr->block; rlm@1: break; rlm@1: case DW_AT_byte_size: rlm@1: m->byteSize = attr->value; rlm@1: break; rlm@1: case DW_AT_bit_offset: rlm@1: m->bitOffset = attr->value; rlm@1: break; rlm@1: case DW_AT_bit_size: rlm@1: m->bitSize = attr->value; rlm@1: break; rlm@1: case DW_AT_decl_file: rlm@1: case DW_AT_decl_line: rlm@1: case DW_AT_accessibility: rlm@1: case DW_AT_artificial: // todo? rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown member attribute %02x\n", rlm@1: attr->name); rlm@1: } rlm@1: } rlm@1: index++; rlm@1: break; rlm@1: } rlm@1: case DW_TAG_subprogram: rlm@1: { rlm@1: Function *fnc = NULL; rlm@1: data = elfParseFunction(data, abbr, unit, &fnc); rlm@1: if (fnc != NULL) rlm@1: { rlm@1: if (unit->lastFunction) rlm@1: unit->lastFunction->next = fnc; rlm@1: else rlm@1: unit->functions = fnc; rlm@1: unit->lastFunction = fnc; rlm@1: } rlm@1: break; rlm@1: } rlm@1: case DW_TAG_inheritance: rlm@1: // TODO: add support rlm@1: data = elfSkipData(data, abbr, unit->abbrevs); rlm@1: break; rlm@1: CASE_TYPE_TAG: rlm@1: // skip types... parsed only when used rlm@1: data = elfSkipData(data, abbr, unit->abbrevs); rlm@1: break; rlm@1: case DW_TAG_variable: rlm@1: data = elfSkipData(data, abbr, unit->abbrevs); rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown struct tag %02x %s\n", abbr->tag, t->name); rlm@1: data = elfSkipData(data, abbr, unit->abbrevs); rlm@1: break; rlm@1: } rlm@1: num = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: } rlm@1: s->memberCount = index; rlm@1: } rlm@1: *type = t; rlm@1: return; rlm@1: break; rlm@1: } rlm@1: case DW_TAG_base_type: rlm@1: { rlm@1: Type *t = (Type *)calloc(sizeof(Type), 1); rlm@1: rlm@1: t->type = TYPE_base; rlm@1: elfAddType(t, unit, offset); rlm@1: for (int i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbrev->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_name: rlm@1: t->name = attr->string; rlm@1: break; rlm@1: case DW_AT_encoding: rlm@1: t->encoding = attr->value; rlm@1: break; rlm@1: case DW_AT_byte_size: rlm@1: t->size = attr->value; rlm@1: break; rlm@1: case DW_AT_bit_size: rlm@1: t->bitSize = attr->value; rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown attribute for base type %02x\n", rlm@1: attr->name); rlm@1: break; rlm@1: } rlm@1: } rlm@1: if (abbrev->hasChildren) rlm@1: fprintf(stderr, "Unexpected children for base type\n"); rlm@1: *type = t; rlm@1: return; rlm@1: break; rlm@1: } rlm@1: case DW_TAG_pointer_type: rlm@1: { rlm@1: Type *t = (Type *)calloc(sizeof(Type), 1); rlm@1: rlm@1: t->type = TYPE_pointer; rlm@1: rlm@1: elfAddType(t, unit, offset); rlm@1: rlm@1: for (int i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbrev->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_type: rlm@1: t->pointer = elfParseType(unit, attr->value); rlm@1: break; rlm@1: case DW_AT_byte_size: rlm@1: t->size = attr->value; rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown pointer type attribute %02x\n", attr->name); rlm@1: break; rlm@1: } rlm@1: } rlm@1: if (abbrev->hasChildren) rlm@1: fprintf(stderr, "Unexpected children for pointer type\n"); rlm@1: *type = t; rlm@1: return; rlm@1: break; rlm@1: } rlm@1: case DW_TAG_reference_type: rlm@1: { rlm@1: Type *t = (Type *)calloc(sizeof(Type), 1); rlm@1: rlm@1: t->type = TYPE_reference; rlm@1: rlm@1: elfAddType(t, unit, offset); rlm@1: rlm@1: for (int i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbrev->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_type: rlm@1: t->pointer = elfParseType(unit, attr->value); rlm@1: break; rlm@1: case DW_AT_byte_size: rlm@1: t->size = attr->value; rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown ref type attribute %02x\n", attr->name); rlm@1: break; rlm@1: } rlm@1: } rlm@1: if (abbrev->hasChildren) rlm@1: fprintf(stderr, "Unexpected children for ref type\n"); rlm@1: *type = t; rlm@1: return; rlm@1: break; rlm@1: } rlm@1: case DW_TAG_volatile_type: rlm@1: { rlm@1: u32 typeref = 0; rlm@1: rlm@1: for (int i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbrev->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_type: rlm@1: typeref = attr->value; rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown volatile attribute for type %02x\n", rlm@1: attr->name); rlm@1: break; rlm@1: } rlm@1: } rlm@1: if (abbrev->hasChildren) rlm@1: fprintf(stderr, "Unexpected children for volatile type\n"); rlm@1: *type = elfParseType(unit, typeref); rlm@1: return; rlm@1: break; rlm@1: } rlm@1: case DW_TAG_const_type: rlm@1: { rlm@1: u32 typeref = 0; rlm@1: rlm@1: for (int i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbrev->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_type: rlm@1: typeref = attr->value; rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown const attribute for type %02x\n", rlm@1: attr->name); rlm@1: break; rlm@1: } rlm@1: } rlm@1: if (abbrev->hasChildren) rlm@1: fprintf(stderr, "Unexpected children for const type\n"); rlm@1: *type = elfParseType(unit, typeref); rlm@1: return; rlm@1: break; rlm@1: } rlm@1: case DW_TAG_enumeration_type: rlm@1: { rlm@1: Type *t = (Type *)calloc(sizeof(Type), 1); rlm@1: t->type = TYPE_enum; rlm@1: Enum *e = (Enum *)calloc(sizeof(Enum), 1); rlm@1: t->enumeration = e; rlm@1: elfAddType(t, unit, offset); rlm@1: int count = 0; rlm@1: for (int i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbrev->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_name: rlm@1: t->name = attr->string; rlm@1: break; rlm@1: case DW_AT_byte_size: rlm@1: t->size = attr->value; rlm@1: break; rlm@1: case DW_AT_sibling: rlm@1: case DW_AT_decl_file: rlm@1: case DW_AT_decl_line: rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown enum attribute %02x\n", attr->name); rlm@1: } rlm@1: } rlm@1: if (abbrev->hasChildren) rlm@1: { rlm@1: int bytes; rlm@1: u32 num = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: while (num) rlm@1: { rlm@1: ELFAbbrev *abbr = elfGetAbbrev(unit->abbrevs, num); rlm@1: rlm@1: switch (abbr->tag) rlm@1: { rlm@1: case DW_TAG_enumerator: rlm@1: { rlm@1: count++; rlm@1: e->members = (EnumMember *)realloc(e->members, rlm@1: count*sizeof(EnumMember)); rlm@1: EnumMember *m = &e->members[count-1]; rlm@1: for (int i = 0; i < abbr->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbr->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_name: rlm@1: m->name = attr->string; rlm@1: break; rlm@1: case DW_AT_const_value: rlm@1: m->value = attr->value; rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown sub param attribute %02x\n", rlm@1: attr->name); rlm@1: } rlm@1: } rlm@1: break; rlm@1: } rlm@1: default: rlm@1: fprintf(stderr, "Unknown enum tag %02x\n", abbr->tag); rlm@1: data = elfSkipData(data, abbr, unit->abbrevs); rlm@1: break; rlm@1: } rlm@1: num = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: } rlm@1: } rlm@1: e->count = count; rlm@1: *type = t; rlm@1: return; rlm@1: break; rlm@1: } rlm@1: case DW_TAG_subroutine_type: rlm@1: { rlm@1: Type *t = (Type *)calloc(sizeof(Type), 1); rlm@1: t->type = TYPE_function; rlm@1: FunctionType *f = (FunctionType *)calloc(sizeof(FunctionType), 1); rlm@1: t->function = f; rlm@1: elfAddType(t, unit, offset); rlm@1: for (int i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbrev->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_prototyped: rlm@1: case DW_AT_sibling: rlm@1: break; rlm@1: case DW_AT_type: rlm@1: f->returnType = elfParseType(unit, attr->value); rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown subroutine attribute %02x\n", attr->name); rlm@1: } rlm@1: } rlm@1: if (abbrev->hasChildren) rlm@1: { rlm@1: int bytes; rlm@1: u32 num = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: Object *lastVar = NULL; rlm@1: while (num) rlm@1: { rlm@1: ELFAbbrev *abbr = elfGetAbbrev(unit->abbrevs, num); rlm@1: rlm@1: switch (abbr->tag) rlm@1: { rlm@1: case DW_TAG_formal_parameter: rlm@1: { rlm@1: Object *o; rlm@1: data = elfParseObject(data, abbr, unit, &o); rlm@1: if (f->args) rlm@1: lastVar->next = o; rlm@1: else rlm@1: f->args = o; rlm@1: lastVar = o; rlm@1: break; rlm@1: } rlm@1: case DW_TAG_unspecified_parameters: rlm@1: // no use in the debugger yet rlm@1: data = elfSkipData(data, abbr, unit->abbrevs); rlm@1: break; rlm@1: CASE_TYPE_TAG: rlm@1: // skip types... parsed only when used rlm@1: data = elfSkipData(data, abbr, unit->abbrevs); rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown subroutine tag %02x\n", abbr->tag); rlm@1: data = elfSkipData(data, abbr, unit->abbrevs); rlm@1: break; rlm@1: } rlm@1: num = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: } rlm@1: } rlm@1: *type = t; rlm@1: return; rlm@1: break; rlm@1: } rlm@1: case DW_TAG_array_type: rlm@1: { rlm@1: u32 typeref = 0; rlm@1: int i; rlm@1: Array *array = (Array *)calloc(sizeof(Array), 1); rlm@1: Type * t = (Type *)calloc(sizeof(Type), 1); rlm@1: t->type = TYPE_array; rlm@1: elfAddType(t, unit, offset); rlm@1: rlm@1: for (i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbrev->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_sibling: rlm@1: break; rlm@1: case DW_AT_type: rlm@1: typeref = attr->value; rlm@1: array->type = elfParseType(unit, typeref); rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown array attribute %02x\n", attr->name); rlm@1: } rlm@1: } rlm@1: if (abbrev->hasChildren) rlm@1: { rlm@1: int bytes; rlm@1: u32 num = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: int index = 0; rlm@1: int maxBounds = 0; rlm@1: while (num) rlm@1: { rlm@1: ELFAbbrev *abbr = elfGetAbbrev(unit->abbrevs, num); rlm@1: rlm@1: switch (abbr->tag) rlm@1: { rlm@1: case DW_TAG_subrange_type: rlm@1: { rlm@1: if (maxBounds == index) rlm@1: { rlm@1: maxBounds += 4; rlm@1: array->bounds = (int *)realloc(array->bounds, rlm@1: sizeof(int)*maxBounds); rlm@1: } rlm@1: for (int i = 0; i < abbr->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbr->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_upper_bound: rlm@1: array->bounds[index] = attr->value+1; rlm@1: break; rlm@1: case DW_AT_type: // ignore rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown subrange attribute %02x\n", rlm@1: attr->name); rlm@1: } rlm@1: } rlm@1: index++; rlm@1: break; rlm@1: } rlm@1: default: rlm@1: fprintf(stderr, "Unknown array tag %02x\n", abbr->tag); rlm@1: data = elfSkipData(data, abbr, unit->abbrevs); rlm@1: break; rlm@1: } rlm@1: num = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: } rlm@1: array->maxBounds = index; rlm@1: } rlm@1: t->size = array->type->size; rlm@1: for (i = 0; i < array->maxBounds; i++) rlm@1: t->size *= array->bounds[i]; rlm@1: t->array = array; rlm@1: *type = t; rlm@1: return; rlm@1: break; rlm@1: } rlm@1: default: rlm@1: fprintf(stderr, "Unknown type TAG %02x\n", abbrev->tag); rlm@1: exit(-1); rlm@1: } rlm@1: } rlm@1: rlm@1: Type *elfParseType(CompileUnit *unit, u32 offset) rlm@1: { rlm@1: Type *t = unit->types; rlm@1: rlm@1: while (t) rlm@1: { rlm@1: if (t->offset == offset) rlm@1: return t; rlm@1: t = t->next; rlm@1: } rlm@1: if (offset == 0) rlm@1: { rlm@1: Type *t = (Type *)calloc(sizeof(Type), 1); rlm@1: t->type = TYPE_void; rlm@1: t->offset = 0; rlm@1: elfAddType(t, unit, 0); rlm@1: return t; rlm@1: } rlm@1: u8 *data = unit->top + offset; rlm@1: int bytes; rlm@1: int abbrevNum = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: Type *type = NULL; rlm@1: rlm@1: ELFAbbrev *abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); rlm@1: rlm@1: elfParseType(data, offset, abbrev, unit, &type); rlm@1: return type; rlm@1: } rlm@1: rlm@1: void elfGetObjectAttributes(CompileUnit *unit, u32 offset, Object *o) rlm@1: { rlm@1: u8 *data = unit->top + offset; rlm@1: int bytes; rlm@1: u32 abbrevNum = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: rlm@1: if (!abbrevNum) rlm@1: { rlm@1: return; rlm@1: } rlm@1: rlm@1: ELFAbbrev *abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); rlm@1: rlm@1: for (int i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbrev->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_location: rlm@1: o->location = attr->block; rlm@1: break; rlm@1: case DW_AT_name: rlm@1: if (o->name == NULL) rlm@1: o->name = attr->string; rlm@1: break; rlm@1: case DW_AT_MIPS_linkage_name: rlm@1: o->name = attr->string; rlm@1: break; rlm@1: case DW_AT_decl_file: rlm@1: o->file = attr->value; rlm@1: break; rlm@1: case DW_AT_decl_line: rlm@1: o->line = attr->value; rlm@1: break; rlm@1: case DW_AT_type: rlm@1: o->type = elfParseType(unit, attr->value); rlm@1: break; rlm@1: case DW_AT_external: rlm@1: o->external = attr->flag; rlm@1: break; rlm@1: case DW_AT_const_value: rlm@1: case DW_AT_abstract_origin: rlm@1: case DW_AT_declaration: rlm@1: case DW_AT_artificial: rlm@1: // todo rlm@1: break; rlm@1: case DW_AT_specification: rlm@1: // TODO: rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown object attribute %02x\n", attr->name); rlm@1: break; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: u8 *elfParseObject(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit, rlm@1: Object **object) rlm@1: { rlm@1: Object *o = (Object *)calloc(sizeof(Object), 1); rlm@1: rlm@1: o->next = NULL; rlm@1: rlm@1: for (int i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbrev->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_location: rlm@1: o->location = attr->block; rlm@1: break; rlm@1: case DW_AT_name: rlm@1: if (o->name == NULL) rlm@1: o->name = attr->string; rlm@1: break; rlm@1: case DW_AT_MIPS_linkage_name: rlm@1: o->name = attr->string; rlm@1: break; rlm@1: case DW_AT_decl_file: rlm@1: o->file = attr->value; rlm@1: break; rlm@1: case DW_AT_decl_line: rlm@1: o->line = attr->value; rlm@1: break; rlm@1: case DW_AT_type: rlm@1: o->type = elfParseType(unit, attr->value); rlm@1: break; rlm@1: case DW_AT_external: rlm@1: o->external = attr->flag; rlm@1: break; rlm@1: case DW_AT_abstract_origin: rlm@1: elfGetObjectAttributes(unit, attr->value, o); rlm@1: break; rlm@1: case DW_AT_const_value: rlm@1: case DW_AT_declaration: rlm@1: case DW_AT_artificial: rlm@1: break; rlm@1: case DW_AT_specification: rlm@1: // TODO: rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown object attribute %02x\n", attr->name); rlm@1: break; rlm@1: } rlm@1: } rlm@1: *object = o; rlm@1: return data; rlm@1: } rlm@1: rlm@1: u8 *elfParseBlock(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit, rlm@1: Function *func, Object **lastVar) rlm@1: { rlm@1: int bytes; rlm@1: u32 start = func->lowPC; rlm@1: u32 end = func->highPC; rlm@1: rlm@1: for (int i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbrev->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_sibling: rlm@1: break; rlm@1: case DW_AT_low_pc: rlm@1: start = attr->value; rlm@1: break; rlm@1: case DW_AT_high_pc: rlm@1: end = attr->value; rlm@1: break; rlm@1: case DW_AT_ranges: // ignore for now rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown block attribute %02x\n", attr->name); rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: if (abbrev->hasChildren) rlm@1: { rlm@1: int nesting = 1; rlm@1: rlm@1: while (nesting) rlm@1: { rlm@1: u32 abbrevNum = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: rlm@1: if (!abbrevNum) rlm@1: { rlm@1: nesting--; rlm@1: continue; rlm@1: } rlm@1: rlm@1: abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); rlm@1: rlm@1: switch (abbrev->tag) rlm@1: { rlm@1: CASE_TYPE_TAG: // types only parsed when used rlm@1: case DW_TAG_label: // not needed rlm@1: data = elfSkipData(data, abbrev, unit->abbrevs); rlm@1: break; rlm@1: case DW_TAG_lexical_block: rlm@1: data = elfParseBlock(data, abbrev, unit, func, lastVar); rlm@1: break; rlm@1: case DW_TAG_subprogram: rlm@1: { rlm@1: Function *f = NULL; rlm@1: data = elfParseFunction(data, abbrev, unit, &f); rlm@1: if (f != NULL) rlm@1: { rlm@1: if (unit->lastFunction) rlm@1: unit->lastFunction->next = f; rlm@1: else rlm@1: unit->functions = f; rlm@1: unit->lastFunction = f; rlm@1: } rlm@1: break; rlm@1: } rlm@1: case DW_TAG_variable: rlm@1: { rlm@1: Object *o; rlm@1: data = elfParseObject(data, abbrev, unit, &o); rlm@1: if (o->startScope == 0) rlm@1: o->startScope = start; rlm@1: if (o->endScope == 0) rlm@1: o->endScope = 0; rlm@1: if (func->variables) rlm@1: (*lastVar)->next = o; rlm@1: else rlm@1: func->variables = o; rlm@1: *lastVar = o; rlm@1: break; rlm@1: } rlm@1: case DW_TAG_inlined_subroutine: rlm@1: // TODO: rlm@1: data = elfSkipData(data, abbrev, unit->abbrevs); rlm@1: break; rlm@1: default: rlm@1: { rlm@1: fprintf(stderr, "Unknown block TAG %02x\n", abbrev->tag); rlm@1: data = elfSkipData(data, abbrev, unit->abbrevs); rlm@1: break; rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: return data; rlm@1: } rlm@1: rlm@1: void elfGetFunctionAttributes(CompileUnit *unit, u32 offset, Function *func) rlm@1: { rlm@1: u8 *data = unit->top + offset; rlm@1: int bytes; rlm@1: u32 abbrevNum = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: rlm@1: if (!abbrevNum) rlm@1: { rlm@1: return; rlm@1: } rlm@1: rlm@1: ELFAbbrev *abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); rlm@1: rlm@1: for (int i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbrev->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_sibling: rlm@1: break; rlm@1: case DW_AT_name: rlm@1: if (func->name == NULL) rlm@1: func->name = attr->string; rlm@1: break; rlm@1: case DW_AT_MIPS_linkage_name: rlm@1: func->name = attr->string; rlm@1: break; rlm@1: case DW_AT_low_pc: rlm@1: func->lowPC = attr->value; rlm@1: break; rlm@1: case DW_AT_high_pc: rlm@1: func->highPC = attr->value; rlm@1: break; rlm@1: case DW_AT_decl_file: rlm@1: func->file = attr->value; rlm@1: break; rlm@1: case DW_AT_decl_line: rlm@1: func->line = attr->value; rlm@1: break; rlm@1: case DW_AT_external: rlm@1: func->external = attr->flag; rlm@1: break; rlm@1: case DW_AT_frame_base: rlm@1: func->frameBase = attr->block; rlm@1: break; rlm@1: case DW_AT_type: rlm@1: func->returnType = elfParseType(unit, attr->value); rlm@1: break; rlm@1: case DW_AT_inline: rlm@1: case DW_AT_specification: rlm@1: case DW_AT_declaration: rlm@1: case DW_AT_artificial: rlm@1: case DW_AT_prototyped: rlm@1: case DW_AT_proc_body: rlm@1: case DW_AT_save_offset: rlm@1: case DW_AT_user_2002: rlm@1: case DW_AT_virtuality: rlm@1: case DW_AT_containing_type: rlm@1: case DW_AT_accessibility: rlm@1: // todo; rlm@1: break; rlm@1: case DW_AT_vtable_elem_location: rlm@1: free(attr->block); rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown function attribute %02x\n", attr->name); rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: return; rlm@1: } rlm@1: rlm@1: u8 *elfParseFunction(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit, rlm@1: Function **f) rlm@1: { rlm@1: Function *func = (Function *)calloc(sizeof(Function), 1); rlm@1: *f = func; rlm@1: rlm@1: int bytes; rlm@1: bool mangled = false; rlm@1: bool declaration = false; rlm@1: for (int i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbrev->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_sibling: rlm@1: break; rlm@1: case DW_AT_name: rlm@1: if (func->name == NULL) rlm@1: func->name = attr->string; rlm@1: break; rlm@1: case DW_AT_MIPS_linkage_name: rlm@1: func->name = attr->string; rlm@1: mangled = true; rlm@1: break; rlm@1: case DW_AT_low_pc: rlm@1: func->lowPC = attr->value; rlm@1: break; rlm@1: case DW_AT_high_pc: rlm@1: func->highPC = attr->value; rlm@1: break; rlm@1: case DW_AT_prototyped: rlm@1: break; rlm@1: case DW_AT_decl_file: rlm@1: func->file = attr->value; rlm@1: break; rlm@1: case DW_AT_decl_line: rlm@1: func->line = attr->value; rlm@1: break; rlm@1: case DW_AT_external: rlm@1: func->external = attr->flag; rlm@1: break; rlm@1: case DW_AT_frame_base: rlm@1: func->frameBase = attr->block; rlm@1: break; rlm@1: case DW_AT_type: rlm@1: func->returnType = elfParseType(unit, attr->value); rlm@1: break; rlm@1: case DW_AT_abstract_origin: rlm@1: elfGetFunctionAttributes(unit, attr->value, func); rlm@1: break; rlm@1: case DW_AT_declaration: rlm@1: declaration = attr->flag; rlm@1: break; rlm@1: case DW_AT_inline: rlm@1: case DW_AT_specification: rlm@1: case DW_AT_artificial: rlm@1: case DW_AT_proc_body: rlm@1: case DW_AT_save_offset: rlm@1: case DW_AT_user_2002: rlm@1: case DW_AT_virtuality: rlm@1: case DW_AT_containing_type: rlm@1: case DW_AT_accessibility: rlm@1: // todo; rlm@1: break; rlm@1: case DW_AT_vtable_elem_location: rlm@1: free(attr->block); rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown function attribute %02x\n", attr->name); rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: if (declaration) rlm@1: { rlm@1: elfCleanUp(func); rlm@1: free(func); rlm@1: *f = NULL; rlm@1: rlm@1: while (1) rlm@1: { rlm@1: u32 abbrevNum = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: rlm@1: if (!abbrevNum) rlm@1: { rlm@1: return data; rlm@1: } rlm@1: rlm@1: abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); rlm@1: rlm@1: data = elfSkipData(data, abbrev, unit->abbrevs); rlm@1: } rlm@1: } rlm@1: rlm@1: if (abbrev->hasChildren) rlm@1: { rlm@1: int nesting = 1; rlm@1: Object *lastParam = NULL; rlm@1: Object *lastVar = NULL; rlm@1: rlm@1: while (nesting) rlm@1: { rlm@1: u32 abbrevNum = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: rlm@1: if (!abbrevNum) rlm@1: { rlm@1: nesting--; rlm@1: continue; rlm@1: } rlm@1: rlm@1: abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); rlm@1: rlm@1: switch (abbrev->tag) rlm@1: { rlm@1: CASE_TYPE_TAG: // no need to parse types. only parsed when used rlm@1: case DW_TAG_label: // not needed rlm@1: data = elfSkipData(data, abbrev, unit->abbrevs); rlm@1: break; rlm@1: case DW_TAG_subprogram: rlm@1: { rlm@1: Function *fnc = NULL; rlm@1: data = elfParseFunction(data, abbrev, unit, &fnc); rlm@1: if (fnc != NULL) rlm@1: { rlm@1: if (unit->lastFunction == NULL) rlm@1: unit->functions = fnc; rlm@1: else rlm@1: unit->lastFunction->next = fnc; rlm@1: unit->lastFunction = fnc; rlm@1: } rlm@1: break; rlm@1: } rlm@1: case DW_TAG_lexical_block: rlm@1: { rlm@1: data = elfParseBlock(data, abbrev, unit, func, &lastVar); rlm@1: break; rlm@1: } rlm@1: case DW_TAG_formal_parameter: rlm@1: { rlm@1: Object *o; rlm@1: data = elfParseObject(data, abbrev, unit, &o); rlm@1: if (func->parameters) rlm@1: lastParam->next = o; rlm@1: else rlm@1: func->parameters = o; rlm@1: lastParam = o; rlm@1: break; rlm@1: } rlm@1: case DW_TAG_variable: rlm@1: { rlm@1: Object *o; rlm@1: data = elfParseObject(data, abbrev, unit, &o); rlm@1: if (func->variables) rlm@1: lastVar->next = o; rlm@1: else rlm@1: func->variables = o; rlm@1: lastVar = o; rlm@1: break; rlm@1: } rlm@1: case DW_TAG_unspecified_parameters: rlm@1: case DW_TAG_inlined_subroutine: rlm@1: { rlm@1: // todo rlm@1: for (int i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: data = elfReadAttribute(data, &abbrev->attrs[i]); rlm@1: if (abbrev->attrs[i].form == DW_FORM_block1) rlm@1: free(abbrev->attrs[i].block); rlm@1: } rlm@1: rlm@1: if (abbrev->hasChildren) rlm@1: nesting++; rlm@1: break; rlm@1: } rlm@1: default: rlm@1: { rlm@1: fprintf(stderr, "Unknown function TAG %02x\n", abbrev->tag); rlm@1: data = elfSkipData(data, abbrev, unit->abbrevs); rlm@1: break; rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: return data; rlm@1: } rlm@1: rlm@1: u8 *elfParseUnknownData(u8 *data, ELFAbbrev *abbrev, ELFAbbrev **abbrevs) rlm@1: { rlm@1: int i; rlm@1: int bytes; rlm@1: // switch(abbrev->tag) { rlm@1: // default: rlm@1: fprintf(stderr, "Unknown TAG %02x\n", abbrev->tag); rlm@1: rlm@1: for (i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: data = elfReadAttribute(data, &abbrev->attrs[i]); rlm@1: if (abbrev->attrs[i].form == DW_FORM_block1) rlm@1: free(abbrev->attrs[i].block); rlm@1: } rlm@1: rlm@1: if (abbrev->hasChildren) rlm@1: { rlm@1: int nesting = 1; rlm@1: while (nesting) rlm@1: { rlm@1: u32 abbrevNum = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: rlm@1: if (!abbrevNum) rlm@1: { rlm@1: nesting--; rlm@1: continue; rlm@1: } rlm@1: rlm@1: abbrev = elfGetAbbrev(abbrevs, abbrevNum); rlm@1: rlm@1: fprintf(stderr, "Unknown TAG %02x\n", abbrev->tag); rlm@1: rlm@1: for (i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: data = elfReadAttribute(data, &abbrev->attrs[i]); rlm@1: if (abbrev->attrs[i].form == DW_FORM_block1) rlm@1: free(abbrev->attrs[i].block); rlm@1: } rlm@1: rlm@1: if (abbrev->hasChildren) rlm@1: { rlm@1: nesting++; rlm@1: } rlm@1: } rlm@1: } rlm@1: // } rlm@1: return data; rlm@1: } rlm@1: rlm@1: u8 *elfParseCompileUnitChildren(u8 *data, CompileUnit *unit) rlm@1: { rlm@1: int bytes; rlm@1: u32 abbrevNum = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: Object *lastObj = NULL; rlm@1: while (abbrevNum) rlm@1: { rlm@1: ELFAbbrev *abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); rlm@1: switch (abbrev->tag) rlm@1: { rlm@1: case DW_TAG_subprogram: rlm@1: { rlm@1: Function *func = NULL; rlm@1: data = elfParseFunction(data, abbrev, unit, &func); rlm@1: if (func != NULL) rlm@1: { rlm@1: if (unit->lastFunction) rlm@1: unit->lastFunction->next = func; rlm@1: else rlm@1: unit->functions = func; rlm@1: unit->lastFunction = func; rlm@1: } rlm@1: break; rlm@1: } rlm@1: CASE_TYPE_TAG: rlm@1: data = elfSkipData(data, abbrev, unit->abbrevs); rlm@1: break; rlm@1: case DW_TAG_variable: rlm@1: { rlm@1: Object *var = NULL; rlm@1: data = elfParseObject(data, abbrev, unit, &var); rlm@1: if (lastObj) rlm@1: lastObj->next = var; rlm@1: else rlm@1: unit->variables = var; rlm@1: lastObj = var; rlm@1: break; rlm@1: } rlm@1: default: rlm@1: data = elfParseUnknownData(data, abbrev, unit->abbrevs); rlm@1: break; rlm@1: } rlm@1: rlm@1: abbrevNum = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: } rlm@1: return data; rlm@1: } rlm@1: rlm@1: CompileUnit *elfParseCompUnit(u8 *data, u8 *abbrevData) rlm@1: { rlm@1: int bytes; rlm@1: u8 *top = data; rlm@1: rlm@1: u32 length = elfRead4Bytes(data); rlm@1: data += 4; rlm@1: rlm@1: u16 version = elfRead2Bytes(data); rlm@1: data += 2; rlm@1: rlm@1: u32 offset = elfRead4Bytes(data); rlm@1: data += 4; rlm@1: rlm@1: u8 addrSize = *data++; rlm@1: rlm@1: if (version != 2) rlm@1: { rlm@1: fprintf(stderr, "Unsupported debugging information version %d\n", version); rlm@1: return NULL; rlm@1: } rlm@1: rlm@1: if (addrSize != 4) rlm@1: { rlm@1: fprintf(stderr, "Unsupported address size %d\n", addrSize); rlm@1: return NULL; rlm@1: } rlm@1: rlm@1: ELFAbbrev **abbrevs = elfReadAbbrevs(abbrevData, offset); rlm@1: rlm@1: u32 abbrevNum = elfReadLEB128(data, &bytes); rlm@1: data += bytes; rlm@1: rlm@1: ELFAbbrev *abbrev = elfGetAbbrev(abbrevs, abbrevNum); rlm@1: rlm@1: CompileUnit *unit = (CompileUnit *)calloc(sizeof(CompileUnit), 1); rlm@1: unit->top = top; rlm@1: unit->length = length; rlm@1: unit->abbrevs = abbrevs; rlm@1: unit->next = NULL; rlm@1: rlm@1: elfCurrentUnit = unit; rlm@1: rlm@1: int i; rlm@1: rlm@1: for (i = 0; i < abbrev->numAttrs; i++) rlm@1: { rlm@1: ELFAttr *attr = &abbrev->attrs[i]; rlm@1: data = elfReadAttribute(data, attr); rlm@1: rlm@1: switch (attr->name) rlm@1: { rlm@1: case DW_AT_name: rlm@1: unit->name = attr->string; rlm@1: break; rlm@1: case DW_AT_stmt_list: rlm@1: unit->hasLineInfo = true; rlm@1: unit->lineInfo = attr->value; rlm@1: break; rlm@1: case DW_AT_low_pc: rlm@1: unit->lowPC = attr->value; rlm@1: break; rlm@1: case DW_AT_high_pc: rlm@1: unit->highPC = attr->value; rlm@1: break; rlm@1: case DW_AT_compdir: rlm@1: unit->compdir = attr->string; rlm@1: break; rlm@1: // ignore rlm@1: case DW_AT_language: rlm@1: case DW_AT_producer: rlm@1: case DW_AT_macro_info: rlm@1: case DW_AT_entry_pc: rlm@1: break; rlm@1: default: rlm@1: fprintf(stderr, "Unknown attribute %02x\n", attr->name); rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: if (abbrev->hasChildren) rlm@1: elfParseCompileUnitChildren(data, unit); rlm@1: rlm@1: return unit; rlm@1: } rlm@1: rlm@1: void elfParseAranges(u8 *data) rlm@1: { rlm@1: ELFSectionHeader *sh = elfGetSectionByName(".debug_aranges"); rlm@1: if (sh == NULL) rlm@1: { rlm@1: fprintf(stderr, "No aranges found\n"); rlm@1: return; rlm@1: } rlm@1: rlm@1: data = elfReadSection(data, sh); rlm@1: u8 *end = data + READ32LE(&sh->size); rlm@1: rlm@1: int max = 4; rlm@1: ARanges *ranges = (ARanges *)calloc(sizeof(ARanges), 4); rlm@1: rlm@1: int index = 0; rlm@1: rlm@1: while (data < end) rlm@1: { rlm@1: u32 len = elfRead4Bytes(data); rlm@1: data += 4; rlm@1: // u16 version = elfRead2Bytes(data); rlm@1: data += 2; rlm@1: u32 offset = elfRead4Bytes(data); rlm@1: data += 4; rlm@1: // u8 addrSize = *data++; rlm@1: // u8 segSize = *data++; rlm@1: data += 2; // remove if uncommenting above rlm@1: data += 4; rlm@1: ranges[index].count = (len-20)/8; rlm@1: ranges[index].offset = offset; rlm@1: ranges[index].ranges = (ARange *)calloc(sizeof(ARange), (len-20)/8); rlm@1: int i = 0; rlm@1: while (true) rlm@1: { rlm@1: u32 addr = elfRead4Bytes(data); rlm@1: data += 4; rlm@1: u32 len = elfRead4Bytes(data); rlm@1: data += 4; rlm@1: if (addr == 0 && len == 0) rlm@1: break; rlm@1: ranges[index].ranges[i].lowPC = addr; rlm@1: ranges[index].ranges[i].highPC = addr+len; rlm@1: i++; rlm@1: } rlm@1: index++; rlm@1: if (index == max) rlm@1: { rlm@1: max += 4; rlm@1: ranges = (ARanges *)realloc(ranges, max*sizeof(ARanges)); rlm@1: } rlm@1: } rlm@1: elfDebugInfo->numRanges = index; rlm@1: elfDebugInfo->ranges = ranges; rlm@1: } rlm@1: rlm@1: void elfReadSymtab(u8 *data) rlm@1: { rlm@1: ELFSectionHeader *sh = elfGetSectionByName(".symtab"); rlm@1: int table = READ32LE(&sh->link); rlm@1: rlm@1: char *strtable = (char *)elfReadSection(data, elfGetSectionByNumber(table)); rlm@1: rlm@1: ELFSymbol *symtab = (ELFSymbol *)elfReadSection(data, sh); rlm@1: rlm@1: int count = READ32LE(&sh->size) / sizeof(ELFSymbol); rlm@1: elfSymbolsCount = 0; rlm@1: rlm@1: elfSymbols = (Symbol *)malloc(sizeof(Symbol)*count); rlm@1: rlm@1: int i; rlm@1: rlm@1: for (i = 0; i < count; i++) rlm@1: { rlm@1: ELFSymbol *s = &symtab[i]; rlm@1: int type = s->info & 15; rlm@1: int binding = s->info >> 4; rlm@1: rlm@1: if (binding) rlm@1: { rlm@1: Symbol *sym = &elfSymbols[elfSymbolsCount]; rlm@1: sym->name = &strtable[READ32LE(&s->name)]; rlm@1: sym->binding = binding; rlm@1: sym->type = type; rlm@1: sym->value = READ32LE(&s->value); rlm@1: sym->size = READ32LE(&s->size); rlm@1: elfSymbolsCount++; rlm@1: } rlm@1: } rlm@1: for (i = 0; i < count; i++) rlm@1: { rlm@1: ELFSymbol *s = &symtab[i]; rlm@1: int bind = s->info>>4; rlm@1: int type = s->info & 15; rlm@1: rlm@1: if (!bind) rlm@1: { rlm@1: Symbol *sym = &elfSymbols[elfSymbolsCount]; rlm@1: sym->name = &strtable[READ32LE(&s->name)]; rlm@1: sym->binding = (s->info >> 4); rlm@1: sym->type = type; rlm@1: sym->value = READ32LE(&s->value); rlm@1: sym->size = READ32LE(&s->size); rlm@1: elfSymbolsCount++; rlm@1: } rlm@1: } rlm@1: elfSymbolsStrTab = strtable; rlm@1: // free(symtab); rlm@1: } rlm@1: rlm@1: bool elfReadProgram(ELFHeader *eh, u8 *data, int& size, bool parseDebug) rlm@1: { rlm@1: int count = READ16LE(&eh->e_phnum); rlm@1: int i; rlm@1: rlm@1: if (READ32LE(&eh->e_entry) == 0x2000000) rlm@1: cpuIsMultiBoot = true; rlm@1: rlm@1: // read program headers... should probably move this code down rlm@1: u8 *p = data + READ32LE(&eh->e_phoff); rlm@1: size = 0; rlm@1: for (i = 0; i < count; i++) rlm@1: { rlm@1: ELFProgramHeader *ph = (ELFProgramHeader *)p; rlm@1: p += sizeof(ELFProgramHeader); rlm@1: if (READ16LE(&eh->e_phentsize) != sizeof(ELFProgramHeader)) rlm@1: { rlm@1: p += READ16LE(&eh->e_phentsize) - sizeof(ELFProgramHeader); rlm@1: } rlm@1: rlm@1: // printf("PH %d %08x %08x %08x %08x %08x %08x %08x %08x\n", rlm@1: // i, ph->type, ph->offset, ph->vaddr, ph->paddr, rlm@1: // ph->filesz, ph->memsz, ph->flags, ph->align); rlm@1: if (cpuIsMultiBoot) rlm@1: { rlm@1: if (READ32LE(&ph->paddr) >= 0x2000000 && rlm@1: READ32LE(&ph->paddr) <= 0x203ffff) rlm@1: { rlm@1: memcpy(&workRAM[READ32LE(&ph->paddr) & 0x3ffff], rlm@1: data + READ32LE(&ph->offset), rlm@1: READ32LE(&ph->filesz)); rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: if (READ32LE(&ph->paddr) >= 0x8000000 && rlm@1: READ32LE(&ph->paddr) <= 0x9ffffff) rlm@1: { rlm@1: memcpy(&rom[READ32LE(&ph->paddr) & 0x1ffffff], rlm@1: data + READ32LE(&ph->offset), rlm@1: READ32LE(&ph->filesz)); rlm@1: size += READ32LE(&ph->filesz); rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: char *stringTable = NULL; rlm@1: rlm@1: // read section headers rlm@1: p = data + READ32LE(&eh->e_shoff); rlm@1: count = READ16LE(&eh->e_shnum); rlm@1: rlm@1: ELFSectionHeader **sh = (ELFSectionHeader * *) rlm@1: malloc(sizeof(ELFSectionHeader *) * count); rlm@1: rlm@1: for (i = 0; i < count; i++) rlm@1: { rlm@1: sh[i] = (ELFSectionHeader *)p; rlm@1: p += sizeof(ELFSectionHeader); rlm@1: if (READ16LE(&eh->e_shentsize) != sizeof(ELFSectionHeader)) rlm@1: p += READ16LE(&eh->e_shentsize) - sizeof(ELFSectionHeader); rlm@1: } rlm@1: rlm@1: if (READ16LE(&eh->e_shstrndx) != 0) rlm@1: { rlm@1: stringTable = (char *)elfReadSection(data, rlm@1: sh[READ16LE(&eh->e_shstrndx)]); rlm@1: } rlm@1: rlm@1: elfSectionHeaders = sh; rlm@1: elfSectionHeadersStringTable = stringTable; rlm@1: elfSectionHeadersCount = count; rlm@1: rlm@1: for (i = 0; i < count; i++) rlm@1: { rlm@1: // printf("SH %d %-20s %08x %08x %08x %08x %08x %08x %08x %08x\n", rlm@1: // i, &stringTable[sh[i]->name], sh[i]->name, sh[i]->type, rlm@1: // sh[i]->flags, sh[i]->addr, sh[i]->offset, sh[i]->size, rlm@1: // sh[i]->link, sh[i]->info); rlm@1: if (READ32LE(&sh[i]->flags) & 2) // load section rlm@1: { rlm@1: if (cpuIsMultiBoot) rlm@1: { rlm@1: if (READ32LE(&sh[i]->addr) >= 0x2000000 && rlm@1: READ32LE(&sh[i]->addr) <= 0x203ffff) rlm@1: { rlm@1: memcpy(&workRAM[READ32LE(&sh[i]->addr) & 0x3ffff], data + rlm@1: READ32LE(&sh[i]->offset), rlm@1: READ32LE(&sh[i]->size)); rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: if (READ32LE(&sh[i]->addr) >= 0x8000000 && rlm@1: READ32LE(&sh[i]->addr) <= 0x9ffffff) rlm@1: { rlm@1: memcpy(&rom[READ32LE(&sh[i]->addr) & 0x1ffffff], rlm@1: data + READ32LE(&sh[i]->offset), rlm@1: READ32LE(&sh[i]->size)); rlm@1: size += READ32LE(&sh[i]->size); rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: if (parseDebug) rlm@1: { rlm@1: fprintf(stderr, "Parsing debug info\n"); rlm@1: rlm@1: ELFSectionHeader *dbgHeader = elfGetSectionByName(".debug_info"); rlm@1: if (dbgHeader == NULL) rlm@1: { rlm@1: fprintf(stderr, "Cannot find debug information\n"); rlm@1: goto end; rlm@1: } rlm@1: rlm@1: ELFSectionHeader *h = elfGetSectionByName(".debug_abbrev"); rlm@1: if (h == NULL) rlm@1: { rlm@1: fprintf(stderr, "Cannot find abbreviation table\n"); rlm@1: goto end; rlm@1: } rlm@1: rlm@1: elfDebugInfo = (DebugInfo *)calloc(sizeof(DebugInfo), 1); rlm@1: u8 *abbrevdata = elfReadSection(data, h); rlm@1: rlm@1: h = elfGetSectionByName(".debug_str"); rlm@1: rlm@1: if (h == NULL) rlm@1: elfDebugStrings = NULL; rlm@1: else rlm@1: elfDebugStrings = (char *)elfReadSection(data, h); rlm@1: rlm@1: u8 *debugdata = elfReadSection(data, dbgHeader); rlm@1: rlm@1: elfDebugInfo->debugdata = data; rlm@1: elfDebugInfo->infodata = debugdata; rlm@1: rlm@1: u32 total = READ32LE(&dbgHeader->size); rlm@1: u8 *end = debugdata + total; rlm@1: u8 *ddata = debugdata; rlm@1: rlm@1: CompileUnit *last = NULL; rlm@1: CompileUnit *unit = NULL; rlm@1: rlm@1: while (ddata < end) rlm@1: { rlm@1: unit = elfParseCompUnit(ddata, abbrevdata); rlm@1: unit->offset = ddata-debugdata; rlm@1: elfParseLineInfo(unit, data); rlm@1: if (last == NULL) rlm@1: elfCompileUnits = unit; rlm@1: else rlm@1: last->next = unit; rlm@1: last = unit; rlm@1: ddata += 4 + unit->length; rlm@1: } rlm@1: elfParseAranges(data); rlm@1: CompileUnit *comp = elfCompileUnits; rlm@1: while (comp) rlm@1: { rlm@1: ARanges *r = elfDebugInfo->ranges; rlm@1: for (int i = 0; i < elfDebugInfo->numRanges; i++) rlm@1: if (r[i].offset == comp->offset) rlm@1: { rlm@1: comp->ranges = &r[i]; rlm@1: break; rlm@1: } rlm@1: comp = comp->next; rlm@1: } rlm@1: elfParseCFA(data); rlm@1: elfReadSymtab(data); rlm@1: } rlm@1: end: rlm@1: if (sh) rlm@1: { rlm@1: free(sh); rlm@1: } rlm@1: rlm@1: elfSectionHeaders = NULL; rlm@1: elfSectionHeadersStringTable = NULL; rlm@1: elfSectionHeadersCount = 0; rlm@1: rlm@1: return true; rlm@1: } rlm@1: rlm@1: extern bool8 parseDebug; rlm@1: rlm@1: bool elfRead(const char *name, int& siz, FILE *f) rlm@1: { rlm@1: fseek(f, 0, SEEK_END); rlm@1: long size = ftell(f); rlm@1: elfFileData = (u8 *)malloc(size); rlm@1: fseek(f, 0, SEEK_SET); rlm@1: fread(elfFileData, 1, size, f); rlm@1: fclose(f); rlm@1: rlm@1: ELFHeader *header = (ELFHeader *)elfFileData; rlm@1: rlm@1: if (READ32LE(&header->magic) != 0x464C457F || rlm@1: READ16LE(&header->e_machine) != 40 || rlm@1: header->clazz != 1) rlm@1: { rlm@1: systemMessage(0, N_("Not a valid ELF file %s"), name); rlm@1: free(elfFileData); rlm@1: elfFileData = NULL; rlm@1: return false; rlm@1: } rlm@1: rlm@1: if (!elfReadProgram(header, elfFileData, siz, parseDebug)) rlm@1: { rlm@1: free(elfFileData); rlm@1: elfFileData = NULL; rlm@1: return false; rlm@1: } rlm@1: rlm@1: return true; rlm@1: } rlm@1: rlm@1: void elfCleanUp(Object *o) rlm@1: { rlm@1: free(o->location); rlm@1: } rlm@1: rlm@1: void elfCleanUp(Function *func) rlm@1: { rlm@1: Object *o = func->parameters; rlm@1: while (o) rlm@1: { rlm@1: elfCleanUp(o); rlm@1: Object *next = o->next; rlm@1: free(o); rlm@1: o = next; rlm@1: } rlm@1: rlm@1: o = func->variables; rlm@1: while (o) rlm@1: { rlm@1: elfCleanUp(o); rlm@1: Object *next = o->next; rlm@1: free(o); rlm@1: o = next; rlm@1: } rlm@1: free(func->frameBase); rlm@1: } rlm@1: rlm@1: void elfCleanUp(ELFAbbrev **abbrevs) rlm@1: { rlm@1: for (int i = 0; i < 121; i++) rlm@1: { rlm@1: ELFAbbrev *abbrev = abbrevs[i]; rlm@1: rlm@1: while (abbrev) rlm@1: { rlm@1: free(abbrev->attrs); rlm@1: ELFAbbrev *next = abbrev->next; rlm@1: free(abbrev); rlm@1: rlm@1: abbrev = next; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: void elfCleanUp(Type *t) rlm@1: { rlm@1: switch (t->type) rlm@1: { rlm@1: case TYPE_function: rlm@1: if (t->function) rlm@1: { rlm@1: Object *o = t->function->args; rlm@1: while (o) rlm@1: { rlm@1: elfCleanUp(o); rlm@1: Object *next = o->next; rlm@1: free(o); rlm@1: o = next; rlm@1: } rlm@1: free(t->function); rlm@1: } rlm@1: break; rlm@1: case TYPE_array: rlm@1: if (t->array) rlm@1: { rlm@1: free(t->array->bounds); rlm@1: free(t->array); rlm@1: } rlm@1: break; rlm@1: case TYPE_struct: rlm@1: case TYPE_union: rlm@1: if (t->structure) rlm@1: { rlm@1: for (int i = 0; i < t->structure->memberCount; i++) rlm@1: { rlm@1: free(t->structure->members[i].location); rlm@1: } rlm@1: free(t->structure->members); rlm@1: free(t->structure); rlm@1: } rlm@1: break; rlm@1: case TYPE_enum: rlm@1: if (t->enumeration) rlm@1: { rlm@1: free(t->enumeration->members); rlm@1: free(t->enumeration); rlm@1: } rlm@1: break; rlm@1: case TYPE_base: rlm@1: case TYPE_pointer: rlm@1: case TYPE_void: rlm@1: case TYPE_reference: rlm@1: break; // nothing to do rlm@1: } rlm@1: } rlm@1: rlm@1: void elfCleanUp(CompileUnit *comp) rlm@1: { rlm@1: elfCleanUp(comp->abbrevs); rlm@1: free(comp->abbrevs); rlm@1: Function *func = comp->functions; rlm@1: while (func) rlm@1: { rlm@1: elfCleanUp(func); rlm@1: Function *next = func->next; rlm@1: free(func); rlm@1: func = next; rlm@1: } rlm@1: Type *t = comp->types; rlm@1: while (t) rlm@1: { rlm@1: elfCleanUp(t); rlm@1: Type *next = t->next; rlm@1: free(t); rlm@1: t = next; rlm@1: } rlm@1: Object *o = comp->variables; rlm@1: while (o) rlm@1: { rlm@1: elfCleanUp(o); rlm@1: Object *next = o->next; rlm@1: free(o); rlm@1: o = next; rlm@1: } rlm@1: if (comp->lineInfoTable) rlm@1: { rlm@1: free(comp->lineInfoTable->lines); rlm@1: free(comp->lineInfoTable->files); rlm@1: free(comp->lineInfoTable); rlm@1: } rlm@1: } rlm@1: rlm@1: void elfCleanUp() rlm@1: { rlm@1: CompileUnit *comp = elfCompileUnits; rlm@1: rlm@1: while (comp) rlm@1: { rlm@1: elfCleanUp(comp); rlm@1: CompileUnit *next = comp->next; rlm@1: free(comp); rlm@1: comp = next; rlm@1: } rlm@1: elfCompileUnits = NULL; rlm@1: free(elfSymbols); rlm@1: elfSymbols = NULL; rlm@1: // free(elfSymbolsStrTab); rlm@1: elfSymbolsStrTab = NULL; rlm@1: rlm@1: elfDebugStrings = NULL; rlm@1: if (elfDebugInfo) rlm@1: { rlm@1: int num = elfDebugInfo->numRanges; rlm@1: int i; rlm@1: for (i = 0; i < num; i++) rlm@1: { rlm@1: free(elfDebugInfo->ranges[i].ranges); rlm@1: } rlm@1: free(elfDebugInfo->ranges); rlm@1: free(elfDebugInfo); rlm@1: elfDebugInfo = NULL; rlm@1: } rlm@1: rlm@1: if (elfFdes) rlm@1: { rlm@1: if (elfFdeCount) rlm@1: { rlm@1: for (int i = 0; i < elfFdeCount; i++) rlm@1: free(elfFdes[i]); rlm@1: } rlm@1: free(elfFdes); rlm@1: rlm@1: elfFdes = NULL; rlm@1: elfFdeCount = 0; rlm@1: } rlm@1: rlm@1: ELFcie *cie = elfCies; rlm@1: while (cie) rlm@1: { rlm@1: ELFcie *next = cie->next; rlm@1: free(cie); rlm@1: cie = next; rlm@1: } rlm@1: elfCies = NULL; rlm@1: rlm@1: if (elfFileData) rlm@1: { rlm@1: free(elfFileData); rlm@1: elfFileData = NULL; rlm@1: } rlm@1: } rlm@1: