Browse Source

We can print a value of an integer variable!!!

master
aolo2 3 years ago
parent
commit
dfac2e7be5
  1. 16
      command.c
  2. 4
      dwarf.c
  3. 132
      eh_frame.c
  4. 33
      elf_dwarf.h
  5. 10
      main.c
  6. 2
      res/004-scoped-variables.c
  7. 48
      util.c

16
command.c

@ -143,7 +143,19 @@ command_backtrace(struct mi_process proc)
} }
static void static void
command_print(struct mi_process proc, char *command, int command_length) command_print(struct mi_process proc, char *name, int name_length)
{ {
struct mi_registers regs = get_process_registers(proc);
u64 pc = regs.rip - proc.base_address;
u64 cfa = get_cfa_at_pc(proc, pc);
struct mi_variable *variable = get_variable(proc, name, name_length, pc);
if (variable) {
u64 address = cfa + variable->location;
long value = ptrace(PTRACE_PEEKDATA, proc.pid, address, NULL);
int val4 = value & 0x00000000FFFFFFFF;
printf("%.*s = %d\n", name_length, name, val4);
} else {
printf("variable %.*s not found\n", name_length, name);
}
} }

4
dwarf.c

@ -59,7 +59,7 @@ decode_leb128(u8 *at, u32 *dest)
u64 result = 0; u64 result = 0;
u64 shift = 0; u64 shift = 0;
while (1) { for (;;) {
u8 byte = at[offset++]; u8 byte = at[offset++];
result |= ((byte & 127) << shift); result |= ((byte & 127) << shift);
@ -88,7 +88,7 @@ decode_leb128s(u8 *at, s32 *dest)
u32 size = 32; u32 size = 32;
u8 byte; u8 byte;
while (1) { for (;;) {
byte = at[offset++]; byte = at[offset++];
result |= ((byte & 127) << shift); result |= ((byte & 127) << shift);
shift += 7; shift += 7;

132
eh_frame.c

@ -1,5 +1,6 @@
static u64 static u64
iterate_call_frame_instructions(u8 *data, u64 to_read) iterate_call_frame_instructions(struct dwarf_cie *cie, u8 *data, u64 to_read,
struct mi_registers *regs, struct dwarf_regset *regset, u64 location)
{ {
u64 read = 0; u64 read = 0;
@ -12,13 +13,15 @@ iterate_call_frame_instructions(u8 *data, u64 to_read)
if (high_two == DW_CFA_advance_loc) { if (high_two == DW_CFA_advance_loc) {
u8 delta = low_six; u8 delta = low_six;
if (regset) {
regset->loc += delta * cie->code_alignment;
}
} else if (high_two == DW_CFA_offset) { } else if (high_two == DW_CFA_offset) {
u8 reg = low_six; u8 reg = low_six;
u32 factored_offset; u32 factored_offset;
increment += decode_leb128(data, &factored_offset); increment += decode_leb128(data, &factored_offset);
} else if (high_two == DW_CFA_restore) { } else if (high_two == DW_CFA_restore) {
u8 reg = low_six; u8 reg = low_six;
} else if (high_two == 0) { } else if (high_two == 0) {
switch (low_six) { switch (low_six) {
case DW_CFA_nop: { case DW_CFA_nop: {
@ -29,6 +32,9 @@ iterate_call_frame_instructions(u8 *data, u64 to_read)
u64 address; u64 address;
memcpy(&address, data, 8); memcpy(&address, data, 8);
increment = 8; increment = 8;
if (regset) {
regset->loc = address; // TODO: encoding??
}
break; break;
} }
@ -36,6 +42,9 @@ iterate_call_frame_instructions(u8 *data, u64 to_read)
u8 advance; u8 advance;
memcpy(&advance, data, 1); memcpy(&advance, data, 1);
increment = 1; increment = 1;
if (regset) {
regset->loc += advance * cie->code_alignment;
}
break; break;
} }
@ -43,6 +52,9 @@ iterate_call_frame_instructions(u8 *data, u64 to_read)
u16 advance; u16 advance;
memcpy(&advance, data, 2); memcpy(&advance, data, 2);
increment = 2; increment = 2;
if (regset) {
regset->loc += advance * cie->code_alignment;
}
break; break;
} }
@ -50,6 +62,9 @@ iterate_call_frame_instructions(u8 *data, u64 to_read)
u32 advance; u32 advance;
memcpy(&advance, data, 4); memcpy(&advance, data, 4);
increment = 4; increment = 4;
if (regset) {
regset->loc += advance * cie->code_alignment;
}
break; break;
} }
@ -98,20 +113,35 @@ iterate_call_frame_instructions(u8 *data, u64 to_read)
case DW_CFA_def_cfa: { case DW_CFA_def_cfa: {
u32 reg; u32 reg;
u32 nonfactored_offset; u32 nonfactored_offset;
increment += decode_leb128(data, &reg); increment += decode_leb128(data, &reg);
increment += decode_leb128(data, &nonfactored_offset); increment += decode_leb128(data + increment, &nonfactored_offset);
if (regset) {
regset->cfa_offset = nonfactored_offset;
regset->cfa_register = reg;
}
break; break;
} }
case DW_CFA_def_cfa_register: { case DW_CFA_def_cfa_register: {
u32 reg; u32 reg;
increment += decode_leb128(data, &reg); increment += decode_leb128(data, &reg);
if (regset) {
regset->cfa_register = reg;
}
break; break;
} }
case DW_CFA_def_cfa_offset: { case DW_CFA_def_cfa_offset: {
u32 offset; u32 offset;
increment += decode_leb128(data, &offset); increment += decode_leb128(data, &offset);
if (regset) {
regset->cfa_offset = offset;
}
break; break;
} }
@ -188,6 +218,11 @@ iterate_call_frame_instructions(u8 *data, u64 to_read)
} }
} }
if (location && regset->loc > location) {
regset->cfa = regset->system[regset->cfa_register] + regset->cfa_offset;
break;
}
data += increment; data += increment;
read += increment + 1; read += increment + 1;
@ -236,8 +271,10 @@ read_one_cie(struct dwarf_cie *header, u64 length, u8 *data, u8 *original_data)
} }
header->has_z = has_z; header->has_z = has_z;
header->instructions = data;
header->instructions_length = header->length - (data - original_data - 4);
data += iterate_call_frame_instructions(data, header->length - (data - original_data - 4)); data += iterate_call_frame_instructions(header, data, header->instructions_length, 0, 0, 0);
if (has_R) { if (has_R) {
// NOTE(aolo2): this shit is undocumented. Best sources I could find: // NOTE(aolo2): this shit is undocumented. Best sources I could find:
@ -372,14 +409,13 @@ read_encoded_pointer(struct mi_process proc, struct dwarf_cie *cie, u8 *data, u6
} }
static u64 static u64
read_one_fde(struct mi_process proc, struct dwarf_cie *cie, u64 length, u32 cie_offset, u8 *data, u8 *original_data) read_one_fde(struct mi_process proc, struct dwarf_cie *cie, u64 length, u8 *data, u8 *original_data,
struct dwarf_fde *header)
{ {
struct dwarf_fde header = { 0 }; header->length = length;
header->cie = *cie;
header.length = length;
header.cie = (struct dwarf_cie *) (data - 4 - cie_offset);
u32 pointer_size = read_encoded_pointer(proc, cie, data, &header.low_pc); u32 pointer_size = read_encoded_pointer(proc, cie, data, &header->low_pc);
data += pointer_size; data += pointer_size;
u64 fde_length = 0; u64 fde_length = 0;
@ -394,21 +430,24 @@ read_one_fde(struct mi_process proc, struct dwarf_cie *cie, u64 length, u32 cie_
data += 8; data += 8;
} }
header.high_pc = header.low_pc + fde_length; header->high_pc = header->low_pc + fde_length;
if (cie->has_z) { if (cie->has_z) {
data += decode_leb128(data, &header.augmentation_data_length); data += decode_leb128(data, &header->augmentation_data_length);
header.augmentation_data = data; header->augmentation_data = data;
data += header.augmentation_data_length; data += header->augmentation_data_length;
} }
data += iterate_call_frame_instructions(data, header.length - (data - original_data - 4)); header->instructions = data;
header->instructions_length = header->length - (data - original_data - 4);
data += iterate_call_frame_instructions(cie, data, header->instructions_length, 0, 0, 0);
return(data - original_data); return(data - original_data);
} }
static u64 static u64
read_one_call_frame_record(struct mi_process proc, struct dwarf_cie *last_cie, u8 *data) read_one_call_frame_record(struct mi_process proc, struct dwarf_cie *last_cie, struct dwarf_fde *last_fde, int *is_cie, u8 *data)
{ {
u8 *original_data = data; u8 *original_data = data;
u64 length; u64 length;
@ -436,49 +475,76 @@ read_one_call_frame_record(struct mi_process proc, struct dwarf_cie *last_cie, u
if (cie_id == 0) { if (cie_id == 0) {
result = read_one_cie(last_cie, length, data, original_data); result = read_one_cie(last_cie, length, data, original_data);
*is_cie = 1;
} else { } else {
result = read_one_fde(proc, last_cie, length, cie_id, data, original_data); result = read_one_fde(proc, last_cie, length, data, original_data, last_fde);
*is_cie = 0;
} }
return(result); return(result);
} }
static void static struct dwarf_fde
parse_eh_frame(struct mi_process proc) eh_frame_find_fde(struct mi_process proc, u64 pc)
{ {
struct elf_section_table_entry_x64 eh_frame = get_section_entry(proc.elf, ".eh_frame"); struct elf_section_table_entry_x64 eh_frame = get_section_entry(proc.elf, ".eh_frame");
struct dwarf_cie last_cie = { 0 }; struct dwarf_cie last_cie = { 0 };
struct dwarf_fde last_fde = { 0 };
int is_cie = 0;
u64 read = 0; u64 read = 0;
for (;;) { for (;;) {
u64 size = read_one_call_frame_record(proc, &last_cie, proc.elf + eh_frame.offset_in_file + read); u64 size = read_one_call_frame_record(proc, &last_cie, &last_fde, &is_cie, proc.elf + eh_frame.offset_in_file + read);
if (!is_cie) {
if (last_fde.low_pc <= pc && pc < last_fde.high_pc) {
return(last_fde);
}
}
read += size; read += size;
if (read >= eh_frame.size) { if (read >= eh_frame.size) {
break; break;
} }
} }
}
static struct dwarf_fde * last_fde.length = 0;
eh_frame_find_fde(struct mi_process proc, u64 pc)
{
return(last_fde);
} }
static struct dwarf_regset static struct dwarf_regset
eh_frame_init_registers(struct mi_process proc, struct dwarf_cie *cie) eh_frame_init_registers(struct mi_process proc, struct mi_registers regs, struct dwarf_cie cie)
{ {
struct dwarf_regset regset = { 0 };
regset.system[0] = regs._sys.rax;
regset.system[1] = regs._sys.rdx;
regset.system[2] = regs._sys.rcx;
regset.system[3] = regs._sys.rbx;
regset.system[4] = regs._sys.rsi;
regset.system[5] = regs._sys.rdi;
regset.system[6] = regs._sys.rbp;
regset.system[7] = regs._sys.rsp;
regset.system[8] = regs._sys.r8;
regset.system[9] = regs._sys.r9;
regset.system[10] = regs._sys.r10;
regset.system[11] = regs._sys.r11;
regset.system[12] = regs._sys.r12;
regset.system[13] = regs._sys.r13;
regset.system[14] = regs._sys.r14;
regset.system[15] = regs._sys.r15;
iterate_call_frame_instructions(&cie, cie.instructions, cie.instructions_length, &regs, &regset, 0);
return(regset);
} }
static struct dwarf_regset static struct dwarf_regset
eh_frame_find_pc(struct mi_process proc, struct dwarf_fde *fde, struct dwarf_regset regs, u64 pc) eh_frame_find_pc(struct mi_process proc, struct dwarf_fde fde, struct mi_registers regs, struct dwarf_regset regset, u64 pc)
{
}
static u64
eh_frame_compute_cfa(struct mi_process proc, struct dwarf_regset regs)
{ {
regset.loc = fde.low_pc;
iterate_call_frame_instructions(&fde.cie, fde.instructions, fde.instructions_length, &regs, &regset, pc);
return(regset);
} }

33
elf_dwarf.h

@ -649,7 +649,9 @@ struct dwarf_cie {
u32 return_address_register; u32 return_address_register;
u32 augmentation_data_length; u32 augmentation_data_length;
u8 *augmentation_data; u8 *augmentation_data;
u8 *instructions; u8 *instructions;
u32 instructions_length;
int has_z; int has_z;
enum dwarf_cie_pointer_format pointer_format; enum dwarf_cie_pointer_format pointer_format;
@ -660,14 +662,41 @@ struct dwarf_cie {
struct dwarf_fde { struct dwarf_fde {
u32 length; u32 length;
u64 optional_length; u64 optional_length;
struct dwarf_cie *cie; struct dwarf_cie cie;
u64 low_pc; u64 low_pc;
u64 high_pc; u64 high_pc;
u32 augmentation_data_length; u32 augmentation_data_length;
u8 *augmentation_data; u8 *augmentation_data;
u8 *instructions; u8 *instructions;
u32 instructions_length;
};
enum dwarf_regset_register {
RAX = 0,
RDX = 1,
RCX = 2,
RBX = 3,
RSI = 4,
RDI = 5,
RBP = 6,
RSP = 7,
R8 = 8,
R9 = 9,
R10 = 10,
R11 = 11,
R12 = 12,
R13 = 13,
R14 = 14,
R15 = 15,
RA = 16
}; };
struct dwarf_regset { struct dwarf_regset {
s64 cfa; u64 loc;
u64 cfa;
u64 system[17];
enum dwarf_regset_register cfa_register;
u32 cfa_offset;
}; };

10
main.c

@ -22,7 +22,6 @@ main(int argc, char *argv[])
char *last_command = malloc(max_command_length + 1); char *last_command = malloc(max_command_length + 1);
parse_debug_info(process.elf, &process.debug); parse_debug_info(process.elf, &process.debug);
parse_eh_frame(process);
process.base_address = 0x555555554000UL; // get_executable_base_address(file, proc.pid); process.base_address = 0x555555554000UL; // get_executable_base_address(file, proc.pid);
process.main_address = get_address_of_subroutine(process, "main"); process.main_address = get_address_of_subroutine(process, "main");
@ -35,6 +34,15 @@ main(int argc, char *argv[])
parse_debug_line(process.elf, &process.debug); parse_debug_line(process.elf, &process.debug);
#if 0
command_start(process);
command_step(process);
command_step(process);
command_print(process, "test", 4);
return(0);
#endif
while ((command_length = getline(&command, &max_command_length, stdin))) { while ((command_length = getline(&command, &max_command_length, stdin))) {
if (command_length == 1) { if (command_length == 1) {
memset(command, 0, max_command_length); memset(command, 0, max_command_length);

2
res/004-scoped-variables.c

@ -31,7 +31,7 @@ f1()
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int a_main = 0; int a_main = 123123;
f1(); f1();
f3(); f3();
return(0); return(0);

48
util.c

@ -298,17 +298,53 @@ get_function_around_pc(struct mi_process proc, u64 pc)
return(0); return(0);
} }
static struct mi_variable *
get_variable(struct mi_process proc, char *name, int length, u64 pc)
{
struct mi_debuginfo debug = proc.debug;
for (int c = 0; c < debug.cu_count; ++c) {
struct mi_compunit *unit = debug.compilation_units + c;
if (unit->low_pc <= pc && pc < unit->high_pc) {
for (int f = 0; f < unit->functions_count; ++f) {
struct mi_function *func = debug.functions + unit->functions_from + f;
if (func->low_pc <= pc && pc < func->high_pc) {
for (int v = 0; v < func->variables_count; ++v) {
struct mi_variable *variable = debug.variables + func->variables_from + v;
if (0 == strncmp(name, variable->name, length)) {
return(variable);
}
}
return(0);
}
}
break;
}
}
return(0);
}
static u64 static u64
get_cfa_at_pc(struct mi_process proc, u64 pc) get_cfa_at_pc(struct mi_process proc, u64 pc)
{ {
struct dwarf_fde *fde = eh_frame_find_fde(proc, pc); struct dwarf_fde fde = eh_frame_find_fde(proc, pc);
if (!fde) { if (!fde.length) {
DIE("could not find FDE for pc!\n"); DIE("could not find FDE for pc!\n");
} }
struct dwarf_regset regs = eh_frame_init_registers(proc, fde->cie); struct mi_registers regs = get_process_registers(proc);
regs = eh_frame_find_pc(proc, fde, regs, pc); struct dwarf_regset regset = eh_frame_init_registers(proc, regs, fde.cie);
u64 cfa = eh_frame_compute_cfa(proc, regs);
regset = eh_frame_find_pc(proc, fde, regs, regset, pc);
return(cfa); return(regset.cfa);
} }
Loading…
Cancel
Save