Browse Source

Getting BASE type info, printing variable type and pretty value

master
aolo2 3 years ago
parent
commit
13df55e03f
  1. 1
      .gitignore
  2. 81
      command.c
  3. 24
      common.h
  4. 76
      dwarf.c
  5. 22
      elf_dwarf.h
  6. 6
      main.c
  7. 13
      res/005-base-types.c
  8. 1
      res/Makefile

1
.gitignore vendored

@ -4,3 +4,4 @@ res/001-simple
res/002-compilation-units res/002-compilation-units
res/003-recursion res/003-recursion
res/004-scoped-variables res/004-scoped-variables
res/005-base-types

81
command.c

@ -147,13 +147,88 @@ command_print(struct mi_process proc, char *name, int name_length)
struct mi_registers regs = get_process_registers(proc); struct mi_registers regs = get_process_registers(proc);
u64 pc = regs.rip - proc.base_address; u64 pc = regs.rip - proc.base_address;
u64 cfa = get_cfa_at_pc(proc, pc); u64 cfa = get_cfa_at_pc(proc, pc);
struct mi_variable *variable = get_variable(proc, name, name_length, pc); struct mi_variable *variable = get_variable(proc, name, name_length, pc);
struct mi_type type = proc.debug.types[variable->type];
if (cfa && variable) { if (cfa && variable) {
u64 address = cfa + variable->location; u64 address = cfa + variable->location;
long value = ptrace(PTRACE_PEEKDATA, proc.pid, address, NULL); u64 raw_value = ptrace(PTRACE_PEEKDATA, proc.pid, address, NULL);
int val4 = value & 0x00000000FFFFFFFF;
printf("%.*s = %d\n", name_length, name, val4); u8 raw_value1;
u16 raw_value2;
u32 raw_value4;
if (type.size == 1) {
raw_value1 = (raw_value & 0x00000000000000ffUL);
} else if (type.size == 2) {
raw_value2 = (raw_value & 0x000000000000ffffUL);
} else if (type.size == 4) {
raw_value4 = (raw_value & 0x00000000ffffffffUL);
}
switch (type.encoding) {
case MI_ADDRESS: {
printf("(address) %.*s = %#lx\n", name_length, name, raw_value);
break;
}
case MI_BOOLEAN: {
if (raw_value) {
printf("(boolean) %.*s = true\n", name_length, name);
} else {
printf("(boolean) %.*s = false\n", name_length, name);
}
break;
}
case MI_FLOAT: {
if (type.size == 4) {
f32 float_val;
memcpy(&float_val, &raw_value4, 4);
printf("(float) %.*s = %f\n", name_length, name, float_val);
} else if (type.size == 8) {
f64 float_val;
memcpy(&float_val, &raw_value, 8);
printf("(double) %.*s = %f\n", name_length, name, float_val);
}
break;
}
case MI_SIGNED: {
if (type.size == 1) {
s8 signed_value1;
memcpy(&signed_value1, &raw_value1, 1);
printf("(s8) %.*s = %d\n", name_length, name, signed_value1);
} else if (type.size == 2) {
s16 signed_value2;
memcpy(&signed_value2, &raw_value2, 2);
printf("(s16) %.*s = %d\n", name_length, name, signed_value2);
} else if (type.size == 4) {
s32 signed_value4;
memcpy(&signed_value4, &raw_value4, 4);
printf("(s32) %.*s = %d\n", name_length, name, signed_value4);
} else if (type.size == 8) {
s64 signed_value8;
memcpy(&signed_value8, &raw_value, 8);
printf("(s64) %.*s = %ld\n", name_length, name, signed_value8);
}
break;
}
case MI_UNSIGNED: {
if (type.size == 1) {
printf("(u8) %.*s = %u\n", name_length, name, raw_value1);
} else if (type.size == 2) {
printf("(u16) %.*s = %u\n", name_length, name, raw_value2);
} else if (type.size == 4) {
printf("(u32) %.*s = %u\n", name_length, name, raw_value4);
} else if (type.size == 8) {
printf("(u64) %.*s = %lu\n", name_length, name, raw_value);
}
break;
}
}
} else { } else {
printf("Variable %.*s not found\n", name_length, name); printf("Variable %.*s not found\n", name_length, name);
} }

24
common.h

@ -29,8 +29,19 @@ typedef int16_t s16;
typedef int32_t s32; typedef int32_t s32;
typedef int64_t s64; typedef int64_t s64;
typedef float f32;
typedef double f64;
#include "elf_dwarf.h" #include "elf_dwarf.h"
enum mi_type_encoding {
MI_ADDRESS,
MI_BOOLEAN,
MI_FLOAT,
MI_SIGNED,
MI_UNSIGNED
};
struct mi_buffer { struct mi_buffer {
u8 *data; u8 *data;
u64 size; u64 size;
@ -49,9 +60,20 @@ struct mi_sourcefile {
struct mi_buffer file; struct mi_buffer file;
}; };
struct mi_type {
char *name;
int size;
enum mi_type_encoding encoding;
// used during parsing so that variables (which only have offsets) could find their
// corresponding parsed type record
s64 _offset;
};
struct mi_variable { struct mi_variable {
char *name; char *name;
s64 location; s64 location;
int type;
}; };
struct mi_function { struct mi_function {
@ -89,10 +111,12 @@ struct mi_debuginfo {
struct mi_compunit compilation_units[16]; struct mi_compunit compilation_units[16];
struct mi_function functions[64]; struct mi_function functions[64];
struct mi_variable variables[64]; struct mi_variable variables[64];
struct mi_type types[64];
int cu_count; int cu_count;
int func_count; int func_count;
int var_count; int var_count;
int type_count;
}; };
struct mi_process { struct mi_process {

76
dwarf.c

@ -119,6 +119,7 @@ abbrev_entry_offset(u8 *file, u64 abbrev_offset, u32 requested_code)
u32 has_children = file[abbrev_offset + offset++]; u32 has_children = file[abbrev_offset + offset++];
(void) has_children; (void) has_children;
if (code == requested_code) { if (code == requested_code) {
return(abbrev_offset); return(abbrev_offset);
} }
@ -654,7 +655,7 @@ TODO: The DW_OP_form_tls_address operation pops a value from the stack, translat
} }
static u32 static u32
read_actual_debug_data(u8 *file, u64 string_offset, u32 address_size, u64 base_data_offset, u32 form, u64 data_offset, u64 *value) read_actual_debug_data(u8 *file, u64 string_offset, u32 address_size, u32 form, u64 data_offset, u64 *value)
{ {
u32 increment = 0; u32 increment = 0;
@ -691,7 +692,8 @@ read_actual_debug_data(u8 *file, u64 string_offset, u32 address_size, u64 base_d
u32 offset; u32 offset;
memcpy(&offset, file + data_offset, 4); memcpy(&offset, file + data_offset, 4);
increment = 4; increment = 4;
*value = file[base_data_offset + offset]; //*value = file[base_data_offset + offset];
*value = offset;
break; break;
} }
@ -765,15 +767,21 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest,
u32 code, tag; u32 code, tag;
u64 schema_offset; u64 schema_offset;
u32 depth = 0; u32 depth = 0;
u64 base_data_offset = data_offset - header_size; //u64 base_data_offset = data_offset - header_size;
int vars_from = dest->var_count;
int types_from = dest->type_count;
struct mi_compunit *comp_unit = dest->compilation_units + dest->cu_count; struct mi_compunit *comp_unit = dest->compilation_units + dest->cu_count;
struct mi_function *func = dest->functions + dest->func_count; struct mi_function *func = dest->functions + dest->func_count;
struct mi_variable *variable = dest->variables + dest->var_count; struct mi_variable *variable = dest->variables + dest->var_count;
struct mi_type *type = dest->types + dest->type_count;
comp_unit->functions_from = dest->func_count; comp_unit->functions_from = dest->func_count;
for (;;) { for (;;) {
s64 record_offset = data_offset - debug_info_offset;
data_offset += decode_leb128(file + data_offset, &code); data_offset += decode_leb128(file + data_offset, &code);
if (code == 0) { if (code == 0) {
@ -804,7 +812,7 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest,
u64 value; u64 value;
data_offset += read_actual_debug_data(file, debug_str_offset, di_header.address_size, base_data_offset, form, data_offset, &value); data_offset += read_actual_debug_data(file, debug_str_offset, di_header.address_size, form, data_offset, &value);
if (tag == DW_TAG_compile_unit) { if (tag == DW_TAG_compile_unit) {
if (attribute == DW_AT_low_pc) { if (attribute == DW_AT_low_pc) {
@ -827,6 +835,49 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest,
variable->name = (char *) value; variable->name = (char *) value;
} else if (attribute == DW_AT_location) { } else if (attribute == DW_AT_location) {
variable->location = value; variable->location = value;
} else if (attribute == DW_AT_type) {
variable->type = value;
}
} else if (tag == DW_TAG_base_type) {
type->_offset = record_offset;
if (attribute == DW_AT_name) {
type->name = (char *) value;
} else if (attribute == DW_AT_byte_size) {
type->size = value;
} else if (attribute == DW_AT_encoding) {
enum dwarf_type_encoding encoding = value;
switch (encoding) {
case DW_ATE_address: {
type->encoding = MI_ADDRESS;
break;
}
case DW_ATE_boolean: {
type->encoding = MI_BOOLEAN;
break;
}
case DW_ATE_float: {
type->encoding = MI_FLOAT;
break;
}
case DW_ATE_signed_char:
case DW_ATE_signed: {
type->encoding = MI_SIGNED;
break;
}
case DW_ATE_unsigned_char:
case DW_ATE_unsigned: {
type->encoding = MI_UNSIGNED;
break;
}
default: {
DIE("unexpected type encoding!\n");
}
}
} }
} }
} while (attribute != 0 || form != 0); } while (attribute != 0 || form != 0);
@ -843,6 +894,23 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest,
++parent->variables_count; ++parent->variables_count;
++dest->var_count; ++dest->var_count;
++variable; ++variable;
} else if (tag == DW_TAG_base_type) {
++dest->type_count;
++type;
}
}
// Resolve types
for (int v = vars_from; v < dest->var_count; ++v) {
struct mi_variable *variable = dest->variables + v;
for (int t = types_from; t < dest->type_count; ++t) {
struct mi_type *type = dest->types + t;
if (type->_offset == variable->type) {
variable->type = t;
break;
}
} }
} }

22
elf_dwarf.h

@ -478,6 +478,28 @@ enum dwarf_expression_op {
DW_OP_hi_user = 0xff DW_OP_hi_user = 0xff
}; };
enum dwarf_type_encoding {
DW_ATE_address = 0x01,
DW_ATE_boolean = 0x02,
DW_ATE_complex_float = 0x03,
DW_ATE_float = 0x04,
DW_ATE_signed = 0x05,
DW_ATE_signed_char = 0x06,
DW_ATE_unsigned = 0x07,
DW_ATE_unsigned_char = 0x08,
DW_ATE_imaginary_float = 0x09,
DW_ATE_packed_decimal = 0x0a,
DW_ATE_numeric_string = 0x0b,
DW_ATE_edited = 0x0c,
DW_ATE_signed_fixed = 0x0d,
DW_ATE_unsigned_fixed = 0x0e,
DW_ATE_decimal_float = 0x0f,
DW_ATE_UTF = 0x10,
DW_ATE_lo_user = 0x80,
DW_ATE_hi_user = 0xff,
};
enum dwarf_cfa_op_base { enum dwarf_cfa_op_base {
DW_CFA_advance_loc = 0x1, DW_CFA_advance_loc = 0x1,
DW_CFA_offset = 0x2, DW_CFA_offset = 0x2,

6
main.c

@ -21,9 +21,11 @@ main(int argc, char *argv[])
char *command = malloc(max_command_length + 1); char *command = malloc(max_command_length + 1);
char *last_command = malloc(max_command_length + 1); char *last_command = malloc(max_command_length + 1);
process.base_address = 0x555555554000UL; // get_executable_base_address(file, proc.pid);
parse_debug_info(process.elf, &process.debug); parse_debug_info(process.elf, &process.debug);
parse_debug_line(process.elf, &process.debug);
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");
printf("Base address: %#lx\n", process.base_address); printf("Base address: %#lx\n", process.base_address);
@ -32,8 +34,6 @@ main(int argc, char *argv[])
printf("> "); printf("> ");
fflush(stdout); fflush(stdout);
parse_debug_line(process.elf, &process.debug);
#if 0 #if 0
command_start(process); command_start(process);
command_step(process); command_step(process);

13
res/005-base-types.c

@ -0,0 +1,13 @@
int
main(int argc, char **argv)
{
int var_int = -123;
unsigned int var_unsigned = 1;
long var_long = -999;
unsigned long var_unsigned_long = 3;
char var_char = '4';
unsigned char var_unsigned_char = '5';
float var_float = 3.14f;
double var_double = 3.14 * 2.0;
void *var_void = (void *) 0xdeadbeef;
}

1
res/Makefile

@ -3,3 +3,4 @@ all:
gcc -g -o 002-compilation-units 002-compilation-units.c 002-compilation-units-impl.c gcc -g -o 002-compilation-units 002-compilation-units.c 002-compilation-units-impl.c
gcc -g -o 003-recursion 003-recursion.c gcc -g -o 003-recursion 003-recursion.c
gcc -g -o 004-scoped-variables 004-scoped-variables.c gcc -g -o 004-scoped-variables 004-scoped-variables.c
gcc -g -o 005-base-types 005-base-types.c

Loading…
Cancel
Save