From 13df55e03f070f60c69e5ff936a2f21e8045bf1a Mon Sep 17 00:00:00 2001 From: aolo2 Date: Sun, 25 Jul 2021 22:34:04 +0300 Subject: [PATCH] Getting BASE type info, printing variable type and pretty value --- .gitignore | 1 + command.c | 81 ++++++++++++++++++++++++++++++++++++++++++-- common.h | 24 +++++++++++++ dwarf.c | 76 ++++++++++++++++++++++++++++++++++++++--- elf_dwarf.h | 22 ++++++++++++ main.c | 6 ++-- res/005-base-types.c | 13 +++++++ res/Makefile | 1 + 8 files changed, 214 insertions(+), 10 deletions(-) create mode 100644 res/005-base-types.c diff --git a/.gitignore b/.gitignore index bb4bd3a..0415e4d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ res/001-simple res/002-compilation-units res/003-recursion res/004-scoped-variables +res/005-base-types diff --git a/command.c b/command.c index 4c97f55..a1841fd 100644 --- a/command.c +++ b/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); 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); + struct mi_type type = proc.debug.types[variable->type]; if (cfa && 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); + u64 raw_value = ptrace(PTRACE_PEEKDATA, proc.pid, address, NULL); + + 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 { printf("Variable %.*s not found\n", name_length, name); } diff --git a/common.h b/common.h index 256ad43..667d21c 100644 --- a/common.h +++ b/common.h @@ -29,8 +29,19 @@ typedef int16_t s16; typedef int32_t s32; typedef int64_t s64; +typedef float f32; +typedef double f64; + #include "elf_dwarf.h" +enum mi_type_encoding { + MI_ADDRESS, + MI_BOOLEAN, + MI_FLOAT, + MI_SIGNED, + MI_UNSIGNED +}; + struct mi_buffer { u8 *data; u64 size; @@ -49,9 +60,20 @@ struct mi_sourcefile { 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 { char *name; s64 location; + int type; }; struct mi_function { @@ -89,10 +111,12 @@ struct mi_debuginfo { struct mi_compunit compilation_units[16]; struct mi_function functions[64]; struct mi_variable variables[64]; + struct mi_type types[64]; int cu_count; int func_count; int var_count; + int type_count; }; struct mi_process { diff --git a/dwarf.c b/dwarf.c index 04c3a5e..d549740 100644 --- a/dwarf.c +++ b/dwarf.c @@ -119,6 +119,7 @@ abbrev_entry_offset(u8 *file, u64 abbrev_offset, u32 requested_code) u32 has_children = file[abbrev_offset + offset++]; (void) has_children; + if (code == requested_code) { return(abbrev_offset); } @@ -654,7 +655,7 @@ TODO: The DW_OP_form_tls_address operation pops a value from the stack, translat } 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; @@ -691,7 +692,8 @@ read_actual_debug_data(u8 *file, u64 string_offset, u32 address_size, u64 base_d u32 offset; memcpy(&offset, file + data_offset, 4); increment = 4; - *value = file[base_data_offset + offset]; + //*value = file[base_data_offset + offset]; + *value = offset; break; } @@ -765,15 +767,21 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest, u32 code, tag; u64 schema_offset; 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_function *func = dest->functions + dest->func_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; for (;;) { + s64 record_offset = data_offset - debug_info_offset; + data_offset += decode_leb128(file + data_offset, &code); if (code == 0) { @@ -804,7 +812,7 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest, 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 (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; } else if (attribute == DW_AT_location) { 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); @@ -843,6 +894,23 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest, ++parent->variables_count; ++dest->var_count; ++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; + } } } diff --git a/elf_dwarf.h b/elf_dwarf.h index 0e295af..9562563 100644 --- a/elf_dwarf.h +++ b/elf_dwarf.h @@ -478,6 +478,28 @@ enum dwarf_expression_op { 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 { DW_CFA_advance_loc = 0x1, DW_CFA_offset = 0x2, diff --git a/main.c b/main.c index 4d476dd..8f6ffba 100644 --- a/main.c +++ b/main.c @@ -21,9 +21,11 @@ main(int argc, char *argv[]) char *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_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"); printf("Base address: %#lx\n", process.base_address); @@ -32,8 +34,6 @@ main(int argc, char *argv[]) printf("> "); fflush(stdout); - parse_debug_line(process.elf, &process.debug); - #if 0 command_start(process); command_step(process); diff --git a/res/005-base-types.c b/res/005-base-types.c new file mode 100644 index 0000000..33a6751 --- /dev/null +++ b/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; +} diff --git a/res/Makefile b/res/Makefile index e9026a0..3dd17a1 100644 --- a/res/Makefile +++ b/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 003-recursion 003-recursion.c gcc -g -o 004-scoped-variables 004-scoped-variables.c + gcc -g -o 005-base-types 005-base-types.c