|
|
|
@ -47,6 +47,153 @@ elf_status elf_init(elf_ctx *ctx, void *info) {
|
|
|
|
|
return EL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// leb128 (little-endian base 128) is a variable-length
|
|
|
|
|
// compression algoritm in DWARF
|
|
|
|
|
void read_uleb128(uint64 *out, char **off) {
|
|
|
|
|
uint64 value = 0; int shift = 0; uint8 b;
|
|
|
|
|
for (;;) {
|
|
|
|
|
b = *(uint8 *)(*off); (*off)++;
|
|
|
|
|
value |= ((uint64)b & 0x7F) << shift;
|
|
|
|
|
shift += 7;
|
|
|
|
|
if ((b & 0x80) == 0) break;
|
|
|
|
|
}
|
|
|
|
|
if (out) *out = value;
|
|
|
|
|
}
|
|
|
|
|
void read_sleb128(int64 *out, char **off) {
|
|
|
|
|
int64 value = 0; int shift = 0; uint8 b;
|
|
|
|
|
for (;;) {
|
|
|
|
|
b = *(uint8 *)(*off); (*off)++;
|
|
|
|
|
value |= ((uint64_t)b & 0x7F) << shift;
|
|
|
|
|
shift += 7;
|
|
|
|
|
if ((b & 0x80) == 0) break;
|
|
|
|
|
}
|
|
|
|
|
if (shift < 64 && (b & 0x40)) value |= -(1 << shift);
|
|
|
|
|
if (out) *out = value;
|
|
|
|
|
}
|
|
|
|
|
// Since reading below types through pointer cast requires aligned address,
|
|
|
|
|
// so we can only read them byte by byte
|
|
|
|
|
void read_uint64(uint64 *out, char **off) {
|
|
|
|
|
*out = 0;
|
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
|
|
|
*out |= (uint64)(**off) << (i << 3); (*off)++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void read_uint32(uint32 *out, char **off) {
|
|
|
|
|
*out = 0;
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
*out |= (uint32)(**off) << (i << 3); (*off)++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void read_uint16(uint16 *out, char **off) {
|
|
|
|
|
*out = 0;
|
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
|
*out |= (uint16)(**off) << (i << 3); (*off)++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* analyzis the data in the debug_line section
|
|
|
|
|
*
|
|
|
|
|
* the function needs 3 parameters: elf context, data in the debug_line section
|
|
|
|
|
* and length of debug_line section
|
|
|
|
|
*
|
|
|
|
|
* make 3 arrays:
|
|
|
|
|
* "process->dir" stores all directory paths of code files
|
|
|
|
|
* "process->file" stores all code file names of code files and their directory path index of array "dir"
|
|
|
|
|
* "process->line" stores all relationships map instruction addresses to code line numbers
|
|
|
|
|
* and their code file name index of array "file"
|
|
|
|
|
*/
|
|
|
|
|
void make_addr_line(elf_ctx *ctx, char *debug_line, uint64 length) {
|
|
|
|
|
process *p = ((elf_info *)ctx->info)->p;
|
|
|
|
|
p->debugline = debug_line;
|
|
|
|
|
// directory name char pointer array
|
|
|
|
|
p->dir = (char **)((((uint64)debug_line + length + 7) >> 3) << 3); int dir_ind = 0, dir_base;
|
|
|
|
|
// file name char pointer array
|
|
|
|
|
p->file = (code_file *)(p->dir + 64); int file_ind = 0, file_base;
|
|
|
|
|
// table array
|
|
|
|
|
p->line = (addr_line *)(p->file + 64); p->line_ind = 0;
|
|
|
|
|
char *off = debug_line;
|
|
|
|
|
while (off < debug_line + length) { // iterate each compilation unit(CU)
|
|
|
|
|
debug_header *dh = (debug_header *)off; off += sizeof(debug_header);
|
|
|
|
|
dir_base = dir_ind; file_base = file_ind;
|
|
|
|
|
// get directory name char pointer in this CU
|
|
|
|
|
while (*off != 0) {
|
|
|
|
|
p->dir[dir_ind++] = off; while (*off != 0) off++; off++;
|
|
|
|
|
}
|
|
|
|
|
off++;
|
|
|
|
|
// get file name char pointer in this CU
|
|
|
|
|
while (*off != 0) {
|
|
|
|
|
p->file[file_ind].file = off; while (*off != 0) off++; off++;
|
|
|
|
|
uint64 dir; read_uleb128(&dir, &off);
|
|
|
|
|
p->file[file_ind++].dir = dir - 1 + dir_base;
|
|
|
|
|
read_uleb128(NULL, &off); read_uleb128(NULL, &off);
|
|
|
|
|
}
|
|
|
|
|
off++; addr_line regs; regs.addr = 0; regs.file = 1; regs.line = 1;
|
|
|
|
|
// simulate the state machine op code
|
|
|
|
|
for (;;) {
|
|
|
|
|
uint8 op = *(off++);
|
|
|
|
|
switch (op) {
|
|
|
|
|
case 0: // Extended Opcodes
|
|
|
|
|
read_uleb128(NULL, &off); op = *(off++);
|
|
|
|
|
switch (op) {
|
|
|
|
|
case 1: // DW_LNE_end_sequence
|
|
|
|
|
if (p->line_ind > 0 && p->line[p->line_ind - 1].addr == regs.addr) p->line_ind--;
|
|
|
|
|
p->line[p->line_ind] = regs; p->line[p->line_ind].file += file_base - 1;
|
|
|
|
|
p->line_ind++; goto endop;
|
|
|
|
|
case 2: // DW_LNE_set_address
|
|
|
|
|
read_uint64(®s.addr, &off); break;
|
|
|
|
|
// ignore DW_LNE_define_file
|
|
|
|
|
case 4: // DW_LNE_set_discriminator
|
|
|
|
|
read_uleb128(NULL, &off); break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 1: // DW_LNS_copy
|
|
|
|
|
if (p->line_ind > 0 && p->line[p->line_ind - 1].addr == regs.addr) p->line_ind--;
|
|
|
|
|
p->line[p->line_ind] = regs; p->line[p->line_ind].file += file_base - 1;
|
|
|
|
|
p->line_ind++; break;
|
|
|
|
|
case 2: { // DW_LNS_advance_pc
|
|
|
|
|
uint64 delta; read_uleb128(&delta, &off);
|
|
|
|
|
regs.addr += delta * dh->min_instruction_length;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 3: { // DW_LNS_advance_line
|
|
|
|
|
int64 delta; read_sleb128(&delta, &off);
|
|
|
|
|
regs.line += delta; break; } case 4: // DW_LNS_set_file
|
|
|
|
|
read_uleb128(®s.file, &off); break;
|
|
|
|
|
case 5: // DW_LNS_set_column
|
|
|
|
|
read_uleb128(NULL, &off); break;
|
|
|
|
|
case 6: // DW_LNS_negate_stmt
|
|
|
|
|
case 7: // DW_LNS_set_basic_block
|
|
|
|
|
break;
|
|
|
|
|
case 8: { // DW_LNS_const_add_pc
|
|
|
|
|
int adjust = 255 - dh->opcode_base;
|
|
|
|
|
int delta = (adjust / dh->line_range) * dh->min_instruction_length;
|
|
|
|
|
regs.addr += delta; break;
|
|
|
|
|
}
|
|
|
|
|
case 9: { // DW_LNS_fixed_advanced_pc
|
|
|
|
|
uint16 delta; read_uint16(&delta, &off);
|
|
|
|
|
regs.addr += delta;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// ignore 10, 11 and 12
|
|
|
|
|
default: { // Special Opcodes
|
|
|
|
|
int adjust = op - dh->opcode_base;
|
|
|
|
|
int addr_delta = (adjust / dh->line_range) * dh->min_instruction_length;
|
|
|
|
|
int line_delta = dh->line_base + (adjust % dh->line_range);
|
|
|
|
|
regs.addr += addr_delta;
|
|
|
|
|
regs.line += line_delta;
|
|
|
|
|
if (p->line_ind > 0 && p->line[p->line_ind - 1].addr == regs.addr) p->line_ind--;
|
|
|
|
|
p->line[p->line_ind] = regs; p->line[p->line_ind].file += file_base - 1;
|
|
|
|
|
p->line_ind++; break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
endop:;
|
|
|
|
|
}
|
|
|
|
|
// for (int i = 0; i < p->line_ind; i++)
|
|
|
|
|
// sprint("%p %d %d\n", p->line[i].addr, p->line[i].line, p->line[i].file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// load the elf segments to memory regions as we are in Bare mode in lab1
|
|
|
|
|
//
|
|
|
|
|