From 2053673cbe1070e3ccf7c51beda8766d2c6aef16 Mon Sep 17 00:00:00 2001 From: "A.Olokhtonov" Date: Thu, 22 Jul 2021 00:03:26 +0300 Subject: [PATCH] Draft of DWARF expression evaluation --- .gitignore | 1 + command.c | 19 +- common.h | 17 ++ dwarf.c | 554 ++++++++++++++++++++++++++++++++++++- elf_dwarf.h | 164 +++++++++++ main.c | 8 +- res/004-scoped-variables.c | 11 + res/Makefile | 1 + util.c | 34 +++ 9 files changed, 794 insertions(+), 15 deletions(-) create mode 100644 res/004-scoped-variables.c diff --git a/.gitignore b/.gitignore index a92e670..bb4bd3a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ build/ res/001-simple res/002-compilation-units res/003-recursion +res/004-scoped-variables diff --git a/command.c b/command.c index e142c9a..270ac14 100644 --- a/command.c +++ b/command.c @@ -22,7 +22,7 @@ command_step(struct mi_process proc) struct mi_sourcepoint *next_sp; do { - // TODO: step until source line changes (for active file) + // TODO: step until source line changes !for active file! ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0); waitpid(proc.pid, 0, 0); regs = get_process_registers(proc); @@ -40,6 +40,9 @@ command_start(struct mi_process proc) u64 main_address = proc.base_address + proc.main_address; long saved_instruction = place_breakpoint_at(proc, main_address); run_until_breakpoint_and_restore(proc, main_address, saved_instruction); + + // TODO: restart if already running/paused + // TODO: process state: not running / running / paused } static void @@ -52,7 +55,7 @@ command_next(struct mi_process proc) struct mi_sourcepoint *next_sp; do { - // TODO: step until source line changes (for active file) + // TODO: step until source line changes !for active file! ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0); waitpid(proc.pid, 0, 0); @@ -97,6 +100,13 @@ command_next(struct mi_process proc) print_sourcepoint(proc, comp_unit, next_sp); } +static void +command_print(struct mi_process proc, char *identifier, int len) +{ + u64 location = lookup_identifier_address(proc, identifier, len); + printf("%#lx\n", location); +} + static void command_list(struct mi_process proc) { @@ -113,8 +123,7 @@ command_cont(struct mi_process proc) } static void -command_stop(struct mi_process proc) +command_kill(struct mi_process proc) { - kill(proc.pid, SIGINT); - // TODO + kill(proc.pid, SIGKILL); } \ No newline at end of file diff --git a/common.h b/common.h index e34dcf1..44bc14d 100644 --- a/common.h +++ b/common.h @@ -56,6 +56,19 @@ struct mi_sourcefile { struct mi_buffer file; }; +struct mi_variable { + char *name; + s64 location; +}; + +struct mi_block { + u64 low_pc; + u64 high_pc; + + struct mi_variable variables[4]; // TODO + int var_count; +}; + struct mi_compunit { u64 low_pc; u64 high_pc; @@ -70,6 +83,9 @@ struct mi_compunit { int source_dirs_count; char *comp_dir; + + struct mi_block blocks[4]; // TODO + int block_count; }; struct mi_debuginfo { @@ -108,3 +124,4 @@ struct mi_registers { #define NT_PRSTATUS 1 #define DIE(string) do { fprintf(stderr, string); exit(1); } while (0) +#define ABS(v) ((v) < 0 ? -(v) : (v)) \ No newline at end of file diff --git a/dwarf.c b/dwarf.c index ed708da..7a22996 100644 --- a/dwarf.c +++ b/dwarf.c @@ -146,6 +146,514 @@ abbrev_entry_offset(u8 *file, u64 abbrev_offset, u32 requested_code) return(0); } +static s64 +compute_dwarf_expression_value(u8 *at, u32 length) +{ + s64 result = 0; + s64 stack[128] = { 0 }; + u32 stack_head = 0; + u8 *original_at = at; + + enum dwarf_expression_op op; + u32 increment; + + while (at - original_at < length) { + op = *at++; + + increment = 0; + + switch (op) { + case DW_OP_addr: { + u64 address; + memcpy(&address, at, 8); + stack[stack_head++] = address; + increment = 8; + break; + } + + case DW_OP_deref: { + u64 address = stack[--stack_head]; + s64 value; + memcpy(&value, (void *) address, 8); // TODO: surely not this... + stack[stack_head++] = value; + break; + } + + case DW_OP_const1u: { + u8 const_value = *at; + stack[stack_head++] = const_value; + increment = 1; + break; + } + + case DW_OP_const1s: { + s8 const_value = *((s8 *) at); + stack[stack_head++] = const_value; + increment = 1; + break; + } + + case DW_OP_const2u: { + u16 const_value; + memcpy(&const_value, at, 2); + stack[stack_head++] = const_value; + increment = 2; + break; + } + + case DW_OP_const2s: { + s16 const_value; + memcpy(&const_value, at, 2); + stack[stack_head++] = const_value; + increment = 2; + break; + } + + case DW_OP_const4u: { + u32 const_value; + memcpy(&const_value, at, 4); + stack[stack_head++] = const_value; + increment = 4; + break; + } + + case DW_OP_const4s: { + s32 const_value; + memcpy(&const_value, at, 4); + stack[stack_head++] = const_value; + increment = 4; + break; + } + + case DW_OP_const8u: { + u64 const_value; + memcpy(&const_value, at, 8); + stack[stack_head++] = const_value; + increment = 8; + break; + } + + case DW_OP_const8s: { + s64 const_value; + memcpy(&const_value, at, 8); + stack[stack_head++] = const_value; + increment = 8; + break; + } + + case DW_OP_constu: { + u32 const_value; + increment = decode_leb128(at, &const_value); + stack[stack_head++] = const_value; + break; + } + + case DW_OP_consts: { + s32 const_value; + increment = decode_leb128s(at, &const_value); + stack[stack_head++] = const_value; + break; + } + + case DW_OP_dup: { + s64 top = stack[stack_head - 1]; + stack[stack_head++] = top; + break; + } + + case DW_OP_drop: { + --stack_head; + break; + } + + case DW_OP_over: { + s64 value = stack[stack_head - 2]; + stack[stack_head++] = value; + break; + } + + case DW_OP_pick: { + u8 stack_index = *at; + increment = 1; + // NOTE: 0 means top of stack + s64 value = stack[stack_head - 1 - stack_index]; + stack[stack_head++] = value; + break; + } + + case DW_OP_swap: { + s64 top = stack[stack_head - 1]; + s64 second_from_top = stack[stack_head - 2]; + stack[stack_head - 2] = top; + stack[stack_head - 1] = second_from_top; + break; + } + + case DW_OP_rot: { + s64 top = stack[stack_head - 1]; + s64 second = stack[stack_head - 2]; + s64 third = stack[stack_head - 3]; + stack[stack_head - 1] = second; + stack[stack_head - 2] = third; + stack[stack_head - 3] = top; + break; + } + + case DW_OP_xderef: { + /* +TODO: The top two stack elements are popped, and a data item is retrieved through an implementation-defined address calculation and pushed as the new stack top. The size of the data retrieved from the dereferenced address is the size of an address on the target machine. + */ + stack_head -= 2; + s64 value = 0xdeadbeef; + stack[stack_head++] = value; + break; + } + + case DW_OP_abs: { + stack[stack_head - 1] = ABS(stack[stack_head - 1]); + break; + } + + case DW_OP_and: { + s64 a = stack[--stack_head]; + s64 b = stack[--stack_head]; + s64 result = b & a; + stack[stack_head++] = result; + break; + } + + case DW_OP_div: { + s64 a = stack[--stack_head]; + s64 b = stack[--stack_head]; + s64 result = b / a; + stack[stack_head++] = result; + break; + } + + case DW_OP_minus: { + s64 a = stack[--stack_head]; + s64 b = stack[--stack_head]; + s64 result = b - a; + stack[stack_head++] = result; + break; + } + + case DW_OP_mod: { + s64 a = stack[--stack_head]; + s64 b = stack[--stack_head]; + s64 result = b % a; + stack[stack_head++] = result; + break; + } + + case DW_OP_mul: { + s64 a = stack[--stack_head]; + s64 b = stack[--stack_head]; + s64 result = b * a; + stack[stack_head++] = result; + break; + } + + case DW_OP_neg: { + stack[stack_head - 1] = -stack[stack_head - 1]; + break; + } + + case DW_OP_not: { + stack[stack_head - 1] = ~stack[stack_head - 1]; + break; + } + + case DW_OP_or: { + s64 a = stack[--stack_head]; + s64 b = stack[--stack_head]; + s64 result = b | a; + stack[stack_head++] = result; + break; + } + + case DW_OP_plus: { + s64 a = stack[--stack_head]; + s64 b = stack[--stack_head]; + s64 result = b + a; + stack[stack_head++] = result; + break; + } + + case DW_OP_plus_uconst: { + u32 const_value; + increment = decode_leb128(at, &const_value); + s64 a = stack[--stack_head]; + s64 result = a + const_value; + stack[stack_head++] = result; + break; + } + + case DW_OP_shl: { + s64 a = stack[--stack_head]; + s64 b = stack[--stack_head]; + s64 result = b << a; + stack[stack_head++] = result; + break; + } + + case DW_OP_shr: { + s64 a = stack[--stack_head]; + s64 b = stack[--stack_head]; + s64 result = b >> a; + stack[stack_head++] = result; + break; + } + + case DW_OP_shra: { + s64 a = stack[--stack_head]; + s64 b = stack[--stack_head]; + s64 result; + + if (b > 0) { + result = b >> a; + } else { + result = ~(~b >> a); + } + + stack[stack_head++] = result; + + break; + } + + case DW_OP_xor: { + s64 a = stack[--stack_head]; + s64 b = stack[--stack_head]; + s64 result = b ^ a; + stack[stack_head++] = result; + break; + break; + } + + case DW_OP_skip: { + s16 const_value; + memcpy(&const_value, at, 2); + increment = 2; + increment += const_value; + break; + } + + case DW_OP_bra: { + s16 const_value; + memcpy(&const_value, at, 2); + increment = 2; + s64 top = stack[--stack_head]; + if (top) { + increment += const_value; + } + break; + } + + case DW_OP_eq: { + s64 a = stack[--stack_head]; + s64 b = stack[--stack_head]; + stack[stack_head++] = (b == a ? 1 : 0); + break; + } + + case DW_OP_ge: { + s64 a = stack[--stack_head]; + s64 b = stack[--stack_head]; + stack[stack_head++] = (b >= a ? 1 : 0); + break; + } + + case DW_OP_gt: { + s64 a = stack[--stack_head]; + s64 b = stack[--stack_head]; + stack[stack_head++] = (b > a ? 1 : 0); + break; + } + + case DW_OP_le: { + s64 a = stack[--stack_head]; + s64 b = stack[--stack_head]; + stack[stack_head++] = (b <= a ? 1 : 0); + break; + } + + case DW_OP_lt: { + s64 a = stack[--stack_head]; + s64 b = stack[--stack_head]; + stack[stack_head++] = (b < a ? 1 : 0); + break; + } + + case DW_OP_ne: { + s64 a = stack[--stack_head]; + s64 b = stack[--stack_head]; + stack[stack_head++] = (b != a ? 1 : 0); + break; + } + + case DW_OP_lit0 ... DW_OP_lit31: { + u32 value = op - DW_OP_lit0; + stack[stack_head++] = value; + break; + } + + case DW_OP_reg0 ... DW_OP_reg31: { + break; + } + + case DW_OP_breg0 ... DW_OP_breg31: { + s32 offset; + increment = decode_leb128s(at, &offset); + break; + } + + case DW_OP_regx: { + u32 reg; + increment = decode_leb128(at, ®); + break; + } + + case DW_OP_fbreg: { + s32 offset; + increment = decode_leb128s(at, &offset); + stack[stack_head++] = offset; + break; + } + + case DW_OP_bregx: { + u32 reg; + s32 offset; + + increment = decode_leb128(at, ®); + increment += decode_leb128s(at, &offset); + + break; + } + + case DW_OP_piece: { + u32 size; + increment = decode_leb128(at, &size); + break; + } + + case DW_OP_deref_size: { + u8 size = *at; + increment = 1; + u64 address = stack[--stack_head]; + s64 value; + memcpy(&value, (void *) address, size); // TODO: surely not this.. + stack[stack_head++] = value; + break; + } + + case DW_OP_xderef_size: { + u8 size = *at; + increment = 1; + /* +TODO: The top two stack elements are popped, and a data item is retrieved through an implementation-defined address calculation and pushed as the new stack top. The size of the data retrieved from the dereferenced address is the size of an address on the target machine. + */ + stack_head -= 2; + s64 value = 0xdeadbeef; + stack[stack_head++] = value; + break; + } + + case DW_OP_nop: { + break; + } + + case DW_OP_push_object_address: { + /* +TODO: The DW_OP_push_object_address operation pushes the address of the object currently being evaluated as part of evaluation of a user presented expression. This object may correspond to an independent variable described by its own debugging information entry or it may be a component of an array, structure, or class whose address has been dynamically determined by an earlier step during user expression evaluation. +*/ + s64 value = 0xdeadbeef; + stack[stack_head++] = value; + break; + } + + case DW_OP_call2: { + u16 offset; + memcpy(&offset, at, 2); + increment = 2; + DIE("i can't call2\n"); + break; + } + + case DW_OP_call4: { + u32 offset; + memcpy(&offset, at, 4); + increment = 4; + DIE("i can't call4\n"); + break; + } + + case DW_OP_call_ref: { + u32 offset; // u64 on 64-bit dwarf ! + memcpy(&offset, at, 4); + increment = 4; + DIE("i can't call_ref\n"); + break; + } + + case DW_OP_form_tls_address: { + /* +TODO: The DW_OP_form_tls_address operation pops a value from the stack, translates it into an address in the current thread's thread-local storage block, and pushes the address. If the DWARF expression containing the DW_OP_form_tls_address operation belongs to the main executable's DWARF info, the operation uses the main executable's thread-local storage block; if the expression belongs to a shared library's DWARF info, then it uses that shared library's thread-local storage block. +*/ + s64 top = stack[--stack_head]; + s64 value = 0xdeadbeef; + stack[stack_head++] = value; + break; + } + + case DW_OP_call_frame_cfa: { + s64 address = 0xdeadbeef; // TODO: get CFA address + stack[stack_head++] = address; + break; + } + + case DW_OP_bit_piece: { + u32 size; + u32 offset; + + increment = decode_leb128(at, &size); + increment += decode_leb128(at, &offset); + + break; + } + + case DW_OP_implicit_value: { + u32 size; + increment = decode_leb128(at, &size); + increment += size; + break; + } + + case DW_OP_stack_value: { + break; + } + + case DW_OP_lo_user: { + break; + } + + case DW_OP_hi_user: { + break; + } + + + default: { + printf("unknown dwarf op %d\n", op); + } + } + + at += increment; + } + + result = stack[stack_head - 1]; + + return(result); +} + 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) { @@ -189,10 +697,12 @@ read_actual_debug_data(u8 *file, u64 string_offset, u32 address_size, u64 base_d } case DW_FORM_exprloc: { - // TODO: return value to caller - u32 length; increment = decode_leb128(file + data_offset, &length); + + s64 expression_value = compute_dwarf_expression_value(file + data_offset + increment, length); + *value = expression_value; + increment += length; break; @@ -262,11 +772,26 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest, struct mi_function *func = dest->functions + dest->func_count; struct mi_compunit *comp_unit = dest->compilation_units + dest->cu_count; + struct mi_block *block = comp_unit->blocks; + struct mi_variable *variable = block->variables; + + enum dwarf_die_tag parent = 0; + + // TODO: make this not bad for (;;) { data_offset += decode_leb128(file + data_offset, &code); if (code == 0) { + // NOTE: finalize parent + if (parent == DW_TAG_lexical_block) { + block->high_pc = block->low_pc + block->high_pc; + ++block; + ++comp_unit->block_count; + variable = block->variables; + __builtin_trap(); + } + if (depth > 1) { --depth; continue; @@ -283,6 +808,7 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest, u32 has_children = file[schema_offset++]; if (has_children) { + parent = tag; ++depth; } @@ -312,16 +838,27 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest, } else if (attribute == DW_AT_high_pc) { func->high_pc = value; } + } else if (tag == DW_TAG_lexical_block) { + if (attribute == DW_AT_low_pc) { + block->low_pc = value; + } else if (attribute == DW_AT_high_pc) { + block->high_pc = value; + } + } else if (tag == DW_TAG_variable) { + if (attribute == DW_AT_name) { + variable->name = (char *) value; + } else if (attribute == DW_AT_location) { + variable->location = value; + } } } while (attribute != 0 || form != 0); - if (tag == DW_TAG_compile_unit) { - comp_unit->high_pc = comp_unit->low_pc + comp_unit->high_pc; - ++comp_unit; - ++dest->cu_count; + if (parent == DW_TAG_variable) { + ++variable; + ++block->var_count; } - if (tag == DW_TAG_subprogram) { + if (parent == DW_TAG_subprogram) { func->high_pc = func->low_pc + func->high_pc; func->comp_unit = dest->cu_count; ++func; @@ -329,6 +866,9 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest, } } + comp_unit->high_pc = comp_unit->low_pc + comp_unit->high_pc; + ++dest->cu_count; + return(di_header.length + 4); } diff --git a/elf_dwarf.h b/elf_dwarf.h index ba2e391..76eae8e 100644 --- a/elf_dwarf.h +++ b/elf_dwarf.h @@ -314,6 +314,170 @@ enum dwarf_lnp_opcode_extended { DW_LNE_set_discriminator = 0x04, }; +enum dwarf_expression_op { + DW_OP_addr = 0x03, + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, + DW_OP_const1s = 0x09, + DW_OP_const2u = 0x0a, + DW_OP_const2s = 0x0b, + DW_OP_const4u = 0x0c, + DW_OP_const4s = 0x0d, + DW_OP_const8u = 0x0e, + DW_OP_const8s = 0x0f, + DW_OP_constu = 0x10, + DW_OP_consts = 0x11, + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1a, + DW_OP_div = 0x1b, + DW_OP_minus = 0x1c, + DW_OP_mod = 0x1d, + DW_OP_mul = 0x1e, + DW_OP_neg = 0x1f, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_skip = 0x2f, + DW_OP_bra = 0x28, + DW_OP_eq = 0x29, + DW_OP_ge = 0x2a, + DW_OP_gt = 0x2b, + DW_OP_le = 0x2c, + DW_OP_lt = 0x2d, + DW_OP_ne = 0x2e, + + DW_OP_lit0 = 0x30, + DW_OP_lit1 = 0x31, + DW_OP_lit2 = 0x32, + DW_OP_lit3 = 0x33, + DW_OP_lit4 = 0x34, + DW_OP_lit5 = 0x35, + DW_OP_lit6 = 0x36, + DW_OP_lit7 = 0x37, + DW_OP_lit8 = 0x38, + DW_OP_lit9 = 0x39, + DW_OP_lit10 = 0x3a, + DW_OP_lit11 = 0x3b, + DW_OP_lit12 = 0x3c, + DW_OP_lit13 = 0x3d, + DW_OP_lit14 = 0x3e, + DW_OP_lit15 = 0x3f, + DW_OP_lit16 = 0x40, + DW_OP_lit17 = 0x41, + DW_OP_lit18 = 0x42, + DW_OP_lit19 = 0x43, + DW_OP_lit20 = 0x44, + DW_OP_lit21 = 0x45, + DW_OP_lit22 = 0x46, + DW_OP_lit23 = 0x47, + DW_OP_lit24 = 0x48, + DW_OP_lit25 = 0x49, + DW_OP_lit26 = 0x4a, + DW_OP_lit27 = 0x4b, + DW_OP_lit28 = 0x4c, + DW_OP_lit29 = 0x4d, + DW_OP_lit30 = 0x4e, + DW_OP_lit31 = 0x4f, + + DW_OP_reg0 = 0x50, + DW_OP_reg1 = 0x51, + DW_OP_reg2 = 0x52, + DW_OP_reg3 = 0x53, + DW_OP_reg4 = 0x54, + DW_OP_reg5 = 0x55, + DW_OP_reg6 = 0x56, + DW_OP_reg7 = 0x57, + DW_OP_reg8 = 0x58, + DW_OP_reg9 = 0x59, + DW_OP_reg10 = 0x5a, + DW_OP_reg11 = 0x5b, + DW_OP_reg12 = 0x5c, + DW_OP_reg13 = 0x5d, + DW_OP_reg14 = 0x5e, + DW_OP_reg15 = 0x5f, + DW_OP_reg16 = 0x60, + DW_OP_reg17 = 0x61, + DW_OP_reg18 = 0x62, + DW_OP_reg19 = 0x63, + DW_OP_reg20 = 0x64, + DW_OP_reg21 = 0x65, + DW_OP_reg22 = 0x66, + DW_OP_reg23 = 0x67, + DW_OP_reg24 = 0x68, + DW_OP_reg25 = 0x69, + DW_OP_reg26 = 0x6a, + DW_OP_reg27 = 0x6b, + DW_OP_reg28 = 0x6c, + DW_OP_reg29 = 0x6d, + DW_OP_reg30 = 0x6e, + DW_OP_reg31 = 0x6f, + + DW_OP_breg0 = 0x70, + DW_OP_breg1 = 0x71, + DW_OP_breg2 = 0x72, + DW_OP_breg3 = 0x73, + DW_OP_breg4 = 0x74, + DW_OP_breg5 = 0x75, + DW_OP_breg6 = 0x76, + DW_OP_breg7 = 0x77, + DW_OP_breg8 = 0x78, + DW_OP_breg9 = 0x79, + DW_OP_breg10 = 0x7a, + DW_OP_breg11 = 0x7b, + DW_OP_breg12 = 0x7c, + DW_OP_breg13 = 0x7d, + DW_OP_breg14 = 0x7e, + DW_OP_breg15 = 0x7f, + DW_OP_breg16 = 0x80, + DW_OP_breg17 = 0x81, + DW_OP_breg18 = 0x82, + DW_OP_breg19 = 0x83, + DW_OP_breg20 = 0x84, + DW_OP_breg21 = 0x85, + DW_OP_breg22 = 0x86, + DW_OP_breg23 = 0x87, + DW_OP_breg24 = 0x88, + DW_OP_breg25 = 0x89, + DW_OP_breg26 = 0x8a, + DW_OP_breg27 = 0x8b, + DW_OP_breg28 = 0x8c, + DW_OP_breg29 = 0x8d, + DW_OP_breg30 = 0x8e, + DW_OP_breg31 = 0x8f, + + DW_OP_regx = 0x90, + DW_OP_fbreg = 0x91, + DW_OP_bregx = 0x92, + DW_OP_piece = 0x93, + DW_OP_deref_size = 0x94, + DW_OP_xderef_size = 0x95, + DW_OP_nop = 0x96, + DW_OP_push_object_address = 0x97, + DW_OP_call2 = 0x98, + DW_OP_call4 = 0x99, + DW_OP_call_ref = 0x9a, + DW_OP_form_tls_address = 0x9b, + DW_OP_call_frame_cfa = 0x9c, + DW_OP_bit_piece = 0x9d, + DW_OP_implicit_value = 0x9e, + DW_OP_stack_value = 0x9f, + + DW_OP_lo_user = 0xe0, + DW_OP_hi_user = 0xff +}; + #pragma pack(1) struct elf_header_x64 { char magic[4]; diff --git a/main.c b/main.c index f5cbeb5..e06ea7e 100644 --- a/main.c +++ b/main.c @@ -49,6 +49,8 @@ main(int argc, char *argv[]) command_step(process); } else if (0 == strncmp(command, "start\n", command_length)) { command_start(process); + } else if (0 == strncmp(command, "print ", 6)) { + command_print(process, command + 6, command_length - 7); } else if (0 == strncmp(command, "next\n", command_length)) { command_next(process); } else if (0 == strncmp(command, "line\n", command_length)) { @@ -56,11 +58,11 @@ main(int argc, char *argv[]) } else if (0 == strncmp(command, "cont\n", command_length)) { command_cont(process); wait = 1; - } else if (0 == strncmp(command, "stop\n", command_length)) { - command_stop(process); + } else if (0 == strncmp(command, "kill\n", command_length)) { + command_kill(process); wait = 1; } else { - printf("Unknown command: %*s", command_length, command); + printf("Unknown command: %.*s", command_length, command); } if (wait) { diff --git a/res/004-scoped-variables.c b/res/004-scoped-variables.c new file mode 100644 index 0000000..f9d9505 --- /dev/null +++ b/res/004-scoped-variables.c @@ -0,0 +1,11 @@ +int +main(int argc, char **argv) +{ + int outer = 1; + if (outer > 0) { + char *inner = "INNER"; + int outer = -1; + outer += 10; + } + return(0); +} diff --git a/res/Makefile b/res/Makefile index fe1d447..e9026a0 100644 --- a/res/Makefile +++ b/res/Makefile @@ -2,3 +2,4 @@ all: gcc -g -o 001-simple 001-simple.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 004-scoped-variables 004-scoped-variables.c diff --git a/util.c b/util.c index ea79392..d257e62 100644 --- a/util.c +++ b/util.c @@ -121,6 +121,7 @@ pc_to_sourcepoint(struct mi_process proc, u64 pc, int *comp_unit) return(unit.sp_table + i - 1); } } + break; } } @@ -271,4 +272,37 @@ print_current_instruction(struct mi_process proc) printf("PC = %#018lx: %x %x %x %x [%x] %x %x %x %x %x %x %x\n", regs.rip, nb[0], nb[1], nb[2], nb[3], nb[4], nb[5], nb[6], nb[7], nb[8], nb[9], nb[10], nb[11]); +} + +static u64 +lookup_identifier_address(struct mi_process proc, char *ident, int len) +{ + struct mi_registers regs = get_process_registers(proc); + u64 pc_local = regs.rip - proc.base_address; + + for (int c = 0; c < proc.debug.cu_count; ++c) { + struct mi_compunit unit = proc.debug.compilation_units[c]; + + if (unit.low_pc <= pc_local && pc_local < unit.high_pc) { + for (int b = 0; b < unit.block_count; ++b) { + struct mi_block block = unit.blocks[b]; + + if (block.low_pc <= pc_local && pc_local < block.high_pc) { + for (int v = 0; v < block.var_count; ++v) { + struct mi_variable variable = block.variables[v]; + + if (0 == strncmp(variable.name, ident, len)) { + return(variable.location); + } + } + break; + + } + } + break; + + } + } + + return(0); } \ No newline at end of file