vbagx/source/vba/gba/elf.cpp

2984 lines
76 KiB
C++

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