Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'agent/tcf/services/dwarfframe.c')
-rw-r--r--agent/tcf/services/dwarfframe.c1019
1 files changed, 1019 insertions, 0 deletions
diff --git a/agent/tcf/services/dwarfframe.c b/agent/tcf/services/dwarfframe.c
new file mode 100644
index 00000000..843393df
--- /dev/null
+++ b/agent/tcf/services/dwarfframe.c
@@ -0,0 +1,1019 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module implements handling of .debug_frame and .eh_frame sections.
+ *
+ * Functions in this module use exceptions to report errors, see exceptions.h
+ */
+
+#include <config.h>
+
+#if ENABLE_ELF && ENABLE_DebugContext
+
+#include <assert.h>
+#include <stdio.h>
+#include <framework/exceptions.h>
+#include <framework/myalloc.h>
+#include <framework/trace.h>
+#include <services/dwarf.h>
+#include <services/dwarfio.h>
+#include <services/dwarfframe.h>
+
+#define EH_PE_omit 0xff
+
+#define EH_PE_absptr 0x00
+#define EH_PE_uleb128 0x01
+#define EH_PE_udata2 0x02
+#define EH_PE_udata4 0x03
+#define EH_PE_udata8 0x04
+#define EH_PE_sleb128 0x09
+#define EH_PE_sdata2 0x0a
+#define EH_PE_sdata4 0x0b
+#define EH_PE_sdata8 0x0c
+
+#define EH_PB_pcrel 0x01
+#define EH_PB_textrel 0x02
+#define EH_PB_datarel 0x03
+#define EH_PB_funcrel 0x04
+#define EH_PB_aligned 0x05
+
+#define EH_PE_indirect 0x80
+
+#define RULE_OFFSET 1
+#define RULE_SAME_VALUE 2
+#define RULE_REGISTER 3
+#define RULE_EXPRESSION 4
+#define RULE_VAL_OFFSET 5
+#define RULE_VAL_EXPRESSION 6
+
+typedef struct RegisterRules {
+ int rule;
+ I4_T offset;
+ U8_T expression;
+} RegisterRules;
+
+typedef struct StackFrameRegisters {
+ RegisterRules * regs;
+ int regs_cnt;
+ int regs_max;
+} StackFrameRegisters;
+
+typedef struct StackFrameRules {
+ Context * ctx;
+ ELF_Section * section;
+ RegisterIdScope reg_id_scope;
+ int eh_frame;
+ U1_T version;
+ U1_T address_size;
+ U1_T segment_size;
+ U4_T code_alignment;
+ I4_T data_alignment;
+ U8_T cie_pos;
+ char * cie_aug;
+ U8_T cie_eh_data;
+ ELF_Section * cie_eh_data_section;
+ U4_T fde_aug_length;
+ U1_T * fde_aug_data;
+ U1_T lsda_encoding;
+ U1_T prh_encoding;
+ U1_T addr_encoding;
+ U8_T location;
+ int return_address_register;
+ int cfa_rule;
+ I4_T cfa_offset;
+ U4_T cfa_register;
+ U8_T cfa_expression;
+} StackFrameRules;
+
+static StackFrameRegisters frame_regs;
+static StackFrameRegisters cie_regs;
+static StackFrameRegisters * regs_stack = NULL;
+static int regs_stack_max = 0;
+static int regs_stack_pos = 0;
+
+static StackFrameRules rules;
+
+U8_T dwarf_stack_trace_addr = 0;
+U8_T dwarf_stack_trace_size = 0;
+
+StackTracingCommandSequence * dwarf_stack_trace_fp = NULL;
+
+int dwarf_stack_trace_regs_cnt = 0;
+StackTracingCommandSequence ** dwarf_stack_trace_regs = NULL;
+
+static int trace_regs_max = 0;
+static int trace_cmds_max = 0;
+static int trace_cmds_cnt = 0;
+static StackTracingCommand * trace_cmds = NULL;
+
+static RegisterRules * get_reg(StackFrameRegisters * regs, int reg) {
+ while (reg >= regs->regs_max) {
+ regs->regs_max = regs->regs_max == 0 ? 32 : regs->regs_max * 2;
+ regs->regs = (RegisterRules *)loc_realloc(regs->regs, sizeof(RegisterRules) * regs->regs_max);
+ }
+ while (regs->regs_cnt <= reg) {
+ int n = regs->regs_cnt++;
+ memset(regs->regs + n, 0, sizeof(RegisterRules));
+ /* Architecture specific implied rules */
+ switch (rules.reg_id_scope.machine) {
+ case EM_386:
+ switch (n) {
+ case 4: /* SP */
+ regs->regs[n].rule = RULE_VAL_OFFSET;
+ break;
+ case 3: /* BX */
+ case 5: /* BP */
+ case 6: /* SI */
+ case 7: /* DI */
+ regs->regs[n].rule = RULE_SAME_VALUE;
+ break;
+ }
+ break;
+ case EM_X86_64:
+ switch (n) {
+ case 3: /* BX */
+ case 6: /* BP */
+ case 12: /* R12 */
+ case 13: /* R13 */
+ case 14: /* R14 */
+ case 15: /* R15 */
+ regs->regs[n].rule = RULE_SAME_VALUE;
+ break;
+ case 7: /* SP */
+ regs->regs[n].rule = RULE_VAL_OFFSET;
+ break;
+ }
+ break;
+ case EM_PPC:
+ if (n == 1) {
+ regs->regs[n].rule = RULE_VAL_OFFSET;
+ }
+ else if ((n >= 14 && n <= 31) || (n >= 46 && n <= 63)) {
+ regs->regs[n].rule = RULE_SAME_VALUE;
+ }
+ else if (n == rules.return_address_register) {
+ regs->regs[n].rule = RULE_REGISTER;
+ regs->regs[n].offset = 108;
+ }
+ break;
+ case EM_ARM:
+ if (n >= 4 && n <= 11) { /* Local variables */
+ regs->regs[n].rule = RULE_SAME_VALUE;
+ }
+ else if (n == 13) { /* Stack pointer */
+ regs->regs[n].rule = RULE_VAL_OFFSET;
+ }
+ break;
+ }
+ }
+ return regs->regs + reg;
+}
+
+static void copy_register_rules(StackFrameRegisters * dst, StackFrameRegisters * src) {
+ int n;
+ dst->regs_cnt = 0;
+ for (n = 0; n < src->regs_cnt; n++) {
+ *get_reg(dst, n) = *get_reg(src, n);
+ }
+}
+
+static StackFrameRegisters * get_regs_stack_item(int n) {
+ while (n >= regs_stack_max) {
+ int max = regs_stack_max;
+ regs_stack_max = regs_stack_max == 0 ? 8 : regs_stack_max * 2;
+ regs_stack = (StackFrameRegisters *)loc_realloc(regs_stack, sizeof(StackFrameRegisters) * regs_stack_max);
+ memset(regs_stack + max, 0, sizeof(StackFrameRegisters) * (regs_stack_max - max));
+ }
+ return regs_stack + n;
+}
+
+static U8_T read_frame_data_pointer(U1_T encoding, ELF_Section ** sec) {
+ U8_T v = 0;
+ if (encoding != EH_PE_omit) {
+ U8_T pos = dio_GetPos();
+ switch (encoding & 0xf) {
+ case EH_PE_absptr:
+ v = dio_ReadAddress(sec);
+ break;
+ case EH_PE_uleb128:
+ v = dio_ReadU8LEB128();
+ break;
+ case EH_PE_udata2:
+ v = dio_ReadU2();
+ break;
+ case EH_PE_udata4:
+ v = dio_ReadU4();
+ break;
+ case EH_PE_udata8:
+ v = dio_ReadU8();
+ break;
+ case EH_PE_sleb128:
+ v = dio_ReadS8LEB128();
+ break;
+ case EH_PE_sdata2:
+ v = (I2_T)dio_ReadU2();
+ break;
+ case EH_PE_sdata4:
+ v = (I4_T)dio_ReadU4();
+ break;
+ case EH_PE_sdata8:
+ v = (I8_T)dio_ReadU8();
+ break;
+ default:
+ str_exception(ERR_INV_DWARF, "Unknown encoding of .eh_frame section pointers");
+ break;
+ }
+ if (v != 0 && sec != NULL) {
+ switch ((encoding >> 4) & 0x7) {
+ case 0:
+ break;
+ case EH_PB_pcrel:
+ *sec = rules.section;
+ v += rules.section->addr + pos;
+ break;
+ case EH_PB_datarel:
+ *sec = rules.section;
+ v += rules.section->addr;
+ break;
+ case EH_PB_textrel:
+ case EH_PB_funcrel:
+ case EH_PB_aligned:
+ default:
+ str_exception(ERR_INV_DWARF, "Unknown encoding of .eh_frame section pointers");
+ break;
+ }
+ if (encoding & EH_PE_indirect) {
+ unsigned idx;
+ ELF_File * file = rules.section->file;
+ size_t size = rules.address_size;
+ U8_T res = 0;
+ for (idx = 1; idx < file->section_cnt; idx++) {
+ ELF_Section * sec = file->sections + idx;
+ if ((sec->flags & SHF_ALLOC) == 0) continue;
+ if (sec->addr <= v && sec->addr + sec->size >= v + size) {
+ U1_T * p;
+ size_t i;
+ if (sec->data == NULL && elf_load(sec) < 0) exception(errno);
+ p = (U1_T *)sec->data + (uintptr_t)(v - sec->addr);
+ for (i = 0; i < size; i++) {
+ res = (res << 8) | p[file->big_endian ? i : size - i - 1];
+ }
+ break;
+ }
+ }
+ v = res;
+ }
+ }
+ }
+ return v;
+}
+
+static void exec_stack_frame_instruction(void) {
+ RegisterRules * reg;
+ U4_T n;
+ U1_T op = dio_ReadU1();
+ switch (op) {
+ case 0x00: /* DW_CFA_nop */
+ break;
+ case 0x01: /* DW_CFA_set_loc */
+ rules.location = read_frame_data_pointer(rules.addr_encoding, 0);
+ break;
+ case 0x02: /* DW_CFA_advance_loc1 */
+ rules.location += dio_ReadU1() * rules.code_alignment;
+ break;
+ case 0x03: /* DW_CFA_advance_loc2 */
+ rules.location += dio_ReadU2() * rules.code_alignment;
+ break;
+ case 0x04: /* DW_CFA_advance_loc4 */
+ rules.location += dio_ReadU4() * rules.code_alignment;
+ break;
+ case 0x05: /* DW_CFA_offset_extended */
+ reg = get_reg(&frame_regs, dio_ReadULEB128());
+ reg->rule = RULE_OFFSET;
+ reg->offset = dio_ReadULEB128() * rules.data_alignment;
+ break;
+ case 0x06: /* DW_CFA_restore_extended */
+ n = dio_ReadULEB128();
+ reg = get_reg(&frame_regs, n);
+ *reg = *get_reg(&cie_regs, n);
+ break;
+ case 0x07: /* DW_CFA_undefined */
+ reg = get_reg(&frame_regs, dio_ReadULEB128());
+ memset(reg, 0, sizeof(*reg));
+ break;
+ case 0x08: /* DW_CFA_same_value */
+ reg = get_reg(&frame_regs, dio_ReadULEB128());
+ reg->rule = RULE_SAME_VALUE;
+ break;
+ case 0x09: /* DW_CFA_register */
+ reg = get_reg(&frame_regs, dio_ReadULEB128());
+ reg->rule = RULE_REGISTER;
+ reg->offset = dio_ReadULEB128();
+ break;
+ case 0x0a: /* DW_CFA_remember_state */
+ copy_register_rules(get_regs_stack_item(regs_stack_pos++), &frame_regs);
+ break;
+ case 0x0b: /* DW_CFA_restore_state */
+ if (regs_stack_pos <= 0) {
+ str_exception(ERR_INV_DWARF, "Invalid DW_CFA_restore_state instruction");
+ }
+ copy_register_rules(&frame_regs, get_regs_stack_item(--regs_stack_pos));
+ break;
+ case 0x0c: /* DW_CFA_def_cfa */
+ rules.cfa_rule = RULE_OFFSET;
+ rules.cfa_register = dio_ReadULEB128();
+ rules.cfa_offset = dio_ReadULEB128();
+ break;
+ case 0x0d: /* DW_CFA_def_cfa_register */
+ rules.cfa_rule = RULE_OFFSET;
+ rules.cfa_register = dio_ReadULEB128();
+ break;
+ case 0x0e: /* DW_CFA_def_cfa_offset */
+ rules.cfa_rule = RULE_OFFSET;
+ rules.cfa_offset = dio_ReadULEB128();
+ break;
+ case 0x0f: /* DW_CFA_def_cfa_expression */
+ rules.cfa_rule = RULE_EXPRESSION;
+ rules.cfa_offset = dio_ReadULEB128();
+ rules.cfa_expression = dio_GetPos();
+ dio_Skip(rules.cfa_offset);
+ break;
+ case 0x10: /* DW_CFA_expression */
+ reg = get_reg(&frame_regs, dio_ReadULEB128());
+ reg->rule = RULE_EXPRESSION;
+ reg->offset = dio_ReadULEB128();
+ reg->expression = dio_GetPos();
+ dio_Skip(reg->offset);
+ break;
+ case 0x11: /* DW_CFA_offset_extended_sf */
+ reg = get_reg(&frame_regs, dio_ReadULEB128());
+ reg->rule = RULE_OFFSET;
+ reg->offset = dio_ReadSLEB128() * rules.data_alignment;
+ break;
+ case 0x12: /* DW_CFA_def_cfa_sf */
+ rules.cfa_rule = RULE_OFFSET;
+ rules.cfa_register = dio_ReadULEB128();
+ rules.cfa_offset = dio_ReadSLEB128() * rules.data_alignment;
+ break;
+ case 0x13: /* DW_CFA_def_cfa_offset_sf */
+ rules.cfa_rule = RULE_OFFSET;
+ rules.cfa_offset = dio_ReadSLEB128() * rules.data_alignment;
+ break;
+ case 0x14: /* DW_CFA_val_offset */
+ reg = get_reg(&frame_regs, dio_ReadULEB128());
+ reg->rule = RULE_VAL_OFFSET;
+ reg->offset = dio_ReadULEB128() * rules.data_alignment;
+ break;
+ case 0x15: /* DW_CFA_val_offset_sf */
+ reg = get_reg(&frame_regs, dio_ReadULEB128());
+ reg->rule = RULE_VAL_OFFSET;
+ reg->offset = dio_ReadSLEB128() * rules.data_alignment;
+ break;
+ case 0x16: /* DW_CFA_val_expression */
+ reg = get_reg(&frame_regs, dio_ReadULEB128());
+ reg->rule = RULE_VAL_EXPRESSION;
+ reg->offset = dio_ReadULEB128();
+ reg->expression = dio_GetPos();
+ dio_Skip(reg->offset);
+ break;
+ case 0x2e: /* DW_CFA_GNU_args_size */
+ /* This instruction specifies the total size of the arguments
+ * which have been pushed onto the stack. Not used by the debugger. */
+ dio_ReadULEB128();
+ break;
+ case 0x2f: /* DW_CFA_GNU_negative_offset_extended */
+ /* This instruction is identical to DW_CFA_offset_extended_sf
+ * except that the operand is subtracted to produce the offset. */
+ reg = get_reg(&frame_regs, dio_ReadULEB128());
+ reg->rule = RULE_OFFSET;
+ reg->offset = -dio_ReadSLEB128() * rules.data_alignment;
+ break;
+ default:
+ switch (op >> 6) {
+ case 0:
+ str_exception(ERR_INV_DWARF, "Unsupported instruction in Call Frame Information");
+ break;
+ case 1: /* DW_CFA_advance_loc */
+ rules.location += (op & 0x3f) * rules.code_alignment;
+ break;
+ case 2: /* DW_CFA_offset */
+ reg = get_reg(&frame_regs, op & 0x3f);
+ reg->rule = RULE_OFFSET;
+ reg->offset = dio_ReadULEB128() * rules.data_alignment;
+ break;
+ case 3: /* DW_CFA_restore */
+ n = op & 0x3f;
+ reg = get_reg(&frame_regs, n);
+ *reg = *get_reg(&cie_regs, n);
+ break;
+ }
+ }
+}
+
+static StackTracingCommand * add_command(int op) {
+ StackTracingCommand * cmd = NULL;
+ if (trace_cmds_cnt >= trace_cmds_max) {
+ trace_cmds_max += 16;
+ trace_cmds = (StackTracingCommand *)loc_realloc(trace_cmds, trace_cmds_max * sizeof(StackTracingCommand));
+ }
+ cmd = trace_cmds + trace_cmds_cnt++;
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->cmd = op;
+ return cmd;
+}
+
+static void add_command_sequence(StackTracingCommandSequence ** ptr, RegisterDefinition * reg) {
+ StackTracingCommandSequence * seq = *ptr;
+ if (seq == NULL || seq->cmds_max < trace_cmds_cnt) {
+ *ptr = seq = (StackTracingCommandSequence *)loc_realloc(seq, sizeof(StackTracingCommandSequence) + (trace_cmds_cnt - 1) * sizeof(StackTracingCommand));
+ seq->cmds_max = trace_cmds_cnt;
+ }
+ seq->reg = reg;
+ seq->cmds_cnt = trace_cmds_cnt;
+ memcpy(seq->cmds, trace_cmds, trace_cmds_cnt * sizeof(StackTracingCommand));
+}
+
+static void add_dwarf_expression_commands(U8_T cmds_offs, U4_T cmds_size) {
+ dio_EnterSection(NULL, rules.section, cmds_offs);
+ while (dio_GetPos() < cmds_offs + cmds_size) {
+ U1_T op = dio_ReadU1();
+
+ switch (op) {
+ case OP_addr:
+ {
+ ELF_Section * section = NULL;
+ U8_T lt_addr = dio_ReadAddress(&section);
+ ContextAddress rt_addr = elf_map_to_run_time_address(
+ rules.ctx, rules.section->file, section, (ContextAddress)lt_addr);
+ if (rt_addr == 0) str_exception(ERR_INV_DWARF, "object has no RT address");
+ add_command(SFT_CMD_NUMBER)->num = rt_addr;
+ }
+ break;
+ case OP_deref:
+ {
+ StackTracingCommand * cmd = add_command(SFT_CMD_DEREF);
+ cmd->size = rules.address_size;
+ cmd->big_endian = rules.section->file->big_endian;
+ }
+ break;
+ case OP_deref_size:
+ {
+ StackTracingCommand * cmd = add_command(SFT_CMD_DEREF);
+ cmd->size = dio_ReadU1();
+ cmd->big_endian = rules.section->file->big_endian;
+ }
+ break;
+ case OP_const1u:
+ add_command(SFT_CMD_NUMBER)->num = dio_ReadU1();
+ break;
+ case OP_const1s:
+ add_command(SFT_CMD_NUMBER)->num = (I1_T)dio_ReadU1();
+ break;
+ case OP_const2u:
+ add_command(SFT_CMD_NUMBER)->num = dio_ReadU2();
+ break;
+ case OP_const2s:
+ add_command(SFT_CMD_NUMBER)->num = (I2_T)dio_ReadU2();
+ break;
+ case OP_const4u:
+ add_command(SFT_CMD_NUMBER)->num = dio_ReadU4();
+ break;
+ case OP_const4s:
+ add_command(SFT_CMD_NUMBER)->num = (I4_T)dio_ReadU4();
+ break;
+ case OP_const8u:
+ add_command(SFT_CMD_NUMBER)->num = dio_ReadU8();
+ break;
+ case OP_const8s:
+ add_command(SFT_CMD_NUMBER)->num = (I8_T)dio_ReadU8();
+ break;
+ case OP_constu:
+ add_command(SFT_CMD_NUMBER)->num = dio_ReadU8LEB128();
+ break;
+ case OP_consts:
+ add_command(SFT_CMD_NUMBER)->num = dio_ReadS8LEB128();
+ break;
+ case OP_and:
+ add_command(SFT_CMD_AND);
+ break;
+ case OP_minus:
+ add_command(SFT_CMD_SUB);
+ break;
+ case OP_or:
+ add_command(SFT_CMD_OR);
+ break;
+ case OP_plus:
+ add_command(SFT_CMD_ADD);
+ break;
+ case OP_plus_uconst:
+ add_command(SFT_CMD_NUMBER)->num = dio_ReadU8LEB128();
+ add_command(SFT_CMD_ADD);
+ break;
+ case OP_lit0:
+ case OP_lit1:
+ case OP_lit2:
+ case OP_lit3:
+ case OP_lit4:
+ case OP_lit5:
+ case OP_lit6:
+ case OP_lit7:
+ case OP_lit8:
+ case OP_lit9:
+ case OP_lit10:
+ case OP_lit11:
+ case OP_lit12:
+ case OP_lit13:
+ case OP_lit14:
+ case OP_lit15:
+ case OP_lit16:
+ case OP_lit17:
+ case OP_lit18:
+ case OP_lit19:
+ case OP_lit20:
+ case OP_lit21:
+ case OP_lit22:
+ case OP_lit23:
+ case OP_lit24:
+ case OP_lit25:
+ case OP_lit26:
+ case OP_lit27:
+ case OP_lit28:
+ case OP_lit29:
+ case OP_lit30:
+ case OP_lit31:
+ add_command(SFT_CMD_NUMBER)->num = op - OP_lit0;
+ break;
+ case OP_breg0:
+ case OP_breg1:
+ case OP_breg2:
+ case OP_breg3:
+ case OP_breg4:
+ case OP_breg5:
+ case OP_breg6:
+ case OP_breg7:
+ case OP_breg8:
+ case OP_breg9:
+ case OP_breg10:
+ case OP_breg11:
+ case OP_breg12:
+ case OP_breg13:
+ case OP_breg14:
+ case OP_breg15:
+ case OP_breg16:
+ case OP_breg17:
+ case OP_breg18:
+ case OP_breg19:
+ case OP_breg20:
+ case OP_breg21:
+ case OP_breg22:
+ case OP_breg23:
+ case OP_breg24:
+ case OP_breg25:
+ case OP_breg26:
+ case OP_breg27:
+ case OP_breg28:
+ case OP_breg29:
+ case OP_breg30:
+ case OP_breg31:
+ {
+ I8_T offs = dio_ReadS8LEB128();
+ RegisterDefinition * def = get_reg_by_id(rules.ctx, op - OP_breg0, &rules.reg_id_scope);
+ if (def == NULL) str_exception(errno, "Cannot read DWARF frame info");
+ add_command(SFT_CMD_REGISTER)->reg = def;
+ if (offs != 0) {
+ add_command(SFT_CMD_NUMBER)->num = offs;
+ add_command(SFT_CMD_ADD);
+ }
+ }
+ break;
+ case OP_nop:
+ break;
+ default:
+ trace(LOG_ALWAYS, "Unsupported DWARF expression op 0x%02x", op);
+ str_exception(ERR_UNSUPPORTED, "Unsupported DWARF expression op");
+ }
+ }
+}
+
+static void generate_register_commands(RegisterRules * reg, RegisterDefinition * dst_reg_def, RegisterDefinition * src_reg_def) {
+ if (dst_reg_def == NULL) return;
+ trace_cmds_cnt = 0;
+ switch (reg->rule) {
+ case RULE_VAL_OFFSET:
+ case RULE_OFFSET:
+ add_command(SFT_CMD_FP);
+ if (reg->offset != 0) {
+ add_command(SFT_CMD_NUMBER)->num = reg->offset;
+ add_command(SFT_CMD_ADD);
+ }
+ if (reg->rule == RULE_OFFSET) {
+ StackTracingCommand * cmd = add_command(SFT_CMD_DEREF);
+ cmd->size = dst_reg_def->size;
+ if (cmd->size > rules.address_size) cmd->size = rules.address_size;
+ cmd->big_endian = rules.section->file->big_endian;
+ }
+ break;
+ case RULE_SAME_VALUE:
+ if (src_reg_def == NULL) return;
+ add_command(SFT_CMD_REGISTER)->reg = src_reg_def;
+ break;
+ case RULE_REGISTER:
+ {
+ RegisterDefinition * src_sef = get_reg_by_id(rules.ctx, reg->offset, &rules.reg_id_scope);
+ if (src_sef != NULL) add_command(SFT_CMD_REGISTER)->reg = src_sef;
+ }
+ break;
+ case RULE_EXPRESSION:
+ case RULE_VAL_EXPRESSION:
+ add_command(SFT_CMD_FP);
+ add_dwarf_expression_commands(reg->expression, reg->offset);
+ if (reg->rule == RULE_EXPRESSION) {
+ StackTracingCommand * cmd = add_command(SFT_CMD_DEREF);
+ cmd->size = dst_reg_def->size;
+ if (cmd->size > rules.address_size) cmd->size = rules.address_size;
+ cmd->big_endian = rules.section->file->big_endian;
+ }
+ break;
+ default:
+ str_exception(ERR_INV_DWARF, "Invalid .debug_frame");
+ break;
+ }
+ if (dwarf_stack_trace_regs_cnt >= trace_regs_max) {
+ int i;
+ trace_regs_max += 16;
+ dwarf_stack_trace_regs = (StackTracingCommandSequence **)loc_realloc(dwarf_stack_trace_regs, trace_regs_max * sizeof(StackTracingCommandSequence *));
+ for (i = dwarf_stack_trace_regs_cnt; i < trace_regs_max; i++) dwarf_stack_trace_regs[i] = NULL;
+ }
+ if (trace_cmds_cnt == 0) return;
+ add_command_sequence(dwarf_stack_trace_regs + dwarf_stack_trace_regs_cnt++, dst_reg_def);
+}
+
+static void generate_commands(void) {
+ int i;
+ RegisterRules * reg;
+ RegisterDefinition * reg_def;
+
+ reg = get_reg(&frame_regs, rules.return_address_register);
+ if (reg->rule != 0) {
+ reg_def = get_reg_by_id(rules.ctx, rules.return_address_register, &rules.reg_id_scope);
+ generate_register_commands(reg, get_PC_definition(rules.ctx), reg_def);
+ }
+ for (i = 0; i < frame_regs.regs_cnt; i++) {
+ if (i == rules.return_address_register) continue;
+ reg = get_reg(&frame_regs, i);
+ if (reg->rule == 0) continue;
+ reg_def = get_reg_by_id(rules.ctx, i, &rules.reg_id_scope);
+ generate_register_commands(reg, reg_def, reg_def);
+ }
+
+ trace_cmds_cnt = 0;
+ switch (rules.cfa_rule) {
+ case RULE_OFFSET:
+ reg_def = get_reg_by_id(rules.ctx, rules.cfa_register, &rules.reg_id_scope);
+ if (reg_def != NULL) {
+ add_command(SFT_CMD_REGISTER)->reg = reg_def;
+ if (rules.cfa_offset != 0) {
+ add_command(SFT_CMD_NUMBER)->num = rules.cfa_offset;
+ add_command(SFT_CMD_ADD);
+ }
+ }
+ break;
+ case RULE_EXPRESSION:
+ add_dwarf_expression_commands(rules.cfa_expression, rules.cfa_offset);
+ break;
+ default:
+ str_exception(ERR_INV_DWARF, "Invalid .debug_frame");
+ break;
+ }
+ add_command_sequence(&dwarf_stack_trace_fp, NULL);
+}
+
+static int generate_plt_section_commands(U8_T offs) {
+ RegisterRules * reg = NULL;
+
+ cie_regs.regs_cnt = 0;
+ frame_regs.regs_cnt = 0;
+ switch (rules.reg_id_scope.machine) {
+ case EM_386:
+ rules.cfa_rule = RULE_OFFSET;
+ rules.cfa_register = 4; /* esp */
+ if (offs == 0) {
+ rules.cfa_offset = 8;
+ }
+ else if (offs < 16) {
+ rules.cfa_offset = 12;
+ }
+ else if ((offs - 16) % 16 < 11) {
+ rules.cfa_offset = 4;
+ }
+ else {
+ rules.cfa_offset = 8;
+ }
+ rules.return_address_register = 8; /* eip */
+ reg = get_reg(&frame_regs, rules.return_address_register);
+ reg->rule = RULE_OFFSET;
+ reg->offset = -4;
+ generate_commands();
+ return 1;
+ case EM_X86_64:
+ rules.cfa_rule = RULE_OFFSET;
+ rules.cfa_register = 7; /* rsp */
+ if (offs == 0) {
+ rules.cfa_offset = 16;
+ }
+ else if (offs < 16) {
+ rules.cfa_offset = 24;
+ }
+ else if ((offs - 16) % 16 < 11) {
+ rules.cfa_offset = 8;
+ }
+ else {
+ rules.cfa_offset = 16;
+ }
+ rules.return_address_register = 16; /* rip */
+ reg = get_reg(&frame_regs, rules.return_address_register);
+ reg->rule = RULE_OFFSET;
+ reg->offset = -8;
+ generate_commands();
+ return 1;
+ case EM_PPC:
+ rules.return_address_register = 108; /* LR */
+ rules.cfa_rule = RULE_OFFSET;
+ rules.cfa_register = 1; /* R1 */
+ rules.cfa_offset = 0;
+ generate_commands();
+ return 1;
+ }
+ return 0;
+}
+
+static void read_frame_cie(U8_T fde_pos, U8_T pos) {
+ int cie_dwarf64 = 0;
+ U8_T saved_pos = dio_GetPos();
+ U8_T cie_length = 0;
+ U8_T cie_end = 0;
+
+ rules.cie_pos = pos;
+ if (pos >= rules.section->size) {
+ char msg[256];
+ snprintf(msg, sizeof(msg),
+ "Invalid CIE pointer 0x%" PRIX64
+ " in FDE at 0x%" PRIX64, pos, fde_pos);
+ str_exception(ERR_INV_DWARF, msg);
+ }
+ dio_SetPos(pos);
+ cie_length = dio_ReadU4();
+ if (cie_length == ~(U4_T)0) {
+ cie_length = dio_ReadU8();
+ cie_dwarf64 = 1;
+ }
+ cie_end = dio_GetPos() + cie_length;
+ dio_Skip(cie_dwarf64 ? 8 : 4);
+ rules.version = dio_ReadU1();
+ if (rules.version != 1 && rules.version != 3 && rules.version != 4) {
+ str_exception(ERR_INV_DWARF, "Unsupported version of Call Frame Information");
+ }
+ rules.cie_aug = dio_ReadString();
+ if (rules.cie_aug != NULL && strcmp(rules.cie_aug, "eh") == 0) {
+ rules.cie_eh_data = dio_ReadAddress(&rules.cie_eh_data_section);
+ }
+ if (rules.version >= 4) {
+ rules.address_size = dio_ReadU1();
+ rules.segment_size = dio_ReadU1();
+ }
+ else {
+ rules.address_size = rules.section->file->elf64 ? 8 : 4;
+ rules.segment_size = 0;
+ }
+ if (rules.segment_size != 0) {
+ str_exception(ERR_INV_DWARF, "Unsupported Call Frame Information: segment size != 0");
+ }
+ rules.code_alignment = dio_ReadULEB128();
+ rules.data_alignment = dio_ReadSLEB128();
+ rules.return_address_register = dio_ReadULEB128();
+ rules.lsda_encoding = 0;
+ rules.prh_encoding = 0;
+ rules.addr_encoding = 0;
+ if (rules.cie_aug != NULL && rules.cie_aug[0] == 'z') {
+ U4_T aug_length = dio_ReadULEB128();
+ U8_T aug_pos = dio_GetPos();
+ char * p = rules.cie_aug + 1;
+ while (*p) {
+ switch (*p++) {
+ case 'L':
+ rules.lsda_encoding = dio_ReadU1();
+ break;
+ case 'P':
+ rules.prh_encoding = dio_ReadU1();
+ read_frame_data_pointer(rules.prh_encoding, 0);
+ break;
+ case 'R':
+ rules.addr_encoding = dio_ReadU1();
+ break;
+ }
+ }
+ dio_SetPos(aug_pos + aug_length);
+ }
+ cie_regs.regs_cnt = 0;
+ frame_regs.regs_cnt = 0;
+ regs_stack_pos = 0;
+ while (dio_GetPos() < cie_end) {
+ exec_stack_frame_instruction();
+ }
+ copy_register_rules(&cie_regs, &frame_regs);
+ dio_SetPos(saved_pos);
+}
+
+static void read_frame_fde(ELF_Section * section, U8_T IP, U8_T fde_pos) {
+ int fde_dwarf64 = 0;
+ U8_T fde_length = 0;
+ U8_T fde_end = 0;
+ U8_T ref_pos = 0;
+ U8_T cie_ref = 0;
+ int fde_flag = 0;
+
+ dio_EnterSection(NULL, section, fde_pos);
+ fde_length = dio_ReadU4();
+ assert(fde_length > 0);
+ if (fde_length == ~(U4_T)0) {
+ fde_length = dio_ReadU8();
+ fde_dwarf64 = 1;
+ }
+ ref_pos = dio_GetPos();
+ fde_end = ref_pos + fde_length;
+ cie_ref = fde_dwarf64 ? dio_ReadU8() : dio_ReadU4();
+ if (rules.eh_frame) fde_flag = cie_ref != 0;
+ else if (fde_dwarf64) fde_flag = cie_ref != ~(U8_T)0;
+ else fde_flag = cie_ref != ~(U4_T)0;
+ assert(fde_flag);
+ if (fde_flag) {
+ U8_T Addr, Range;
+ ELF_Section * sec = NULL;
+ if (rules.eh_frame) cie_ref = ref_pos - cie_ref;
+ if (cie_ref != rules.cie_pos) read_frame_cie(fde_pos, cie_ref);
+ Addr = read_frame_data_pointer(rules.addr_encoding, &sec);
+ Range = read_frame_data_pointer(rules.addr_encoding, NULL);
+ assert(Addr <= IP && Addr + Range > IP);
+ if (Addr <= IP && Addr + Range > IP) {
+ U8_T location0 = Addr;
+ if (rules.cie_aug != NULL && rules.cie_aug[0] == 'z') {
+ rules.fde_aug_length = dio_ReadULEB128();
+ rules.fde_aug_data = dio_GetDataPtr();
+ dio_Skip(rules.fde_aug_length);
+ }
+ copy_register_rules(&frame_regs, &cie_regs);
+ rules.location = Addr;
+ regs_stack_pos = 0;
+ for (;;) {
+ if (dio_GetPos() >= fde_end) {
+ rules.location = Addr + Range;
+ break;
+ }
+ exec_stack_frame_instruction();
+ assert(location0 <= IP);
+ if (rules.location > IP) break;
+ location0 = rules.location;
+ }
+ dwarf_stack_trace_addr = location0;
+ dwarf_stack_trace_size = rules.location - location0;
+ generate_commands();
+ }
+ }
+ dio_ExitSection();
+}
+
+static int cmp_frame_info_ranges(const void * x, const void * y) {
+ FrameInfoRange * rx = (FrameInfoRange *)x;
+ FrameInfoRange * ry = (FrameInfoRange *)y;
+ if (rx->mAddr < ry->mAddr) return -1;
+ if (rx->mAddr > ry->mAddr) return +1;
+ return 0;
+}
+
+static void create_search_index(DWARFCache * cache, ELF_Section * section) {
+ dio_EnterSection(NULL, section, 0);
+ while (dio_GetPos() < section->size) {
+ int fde_dwarf64 = 0;
+ U8_T fde_length = 0;
+ U8_T fde_pos = 0;
+ U8_T fde_end = 0;
+ U8_T ref_pos = 0;
+ U8_T cie_ref = 0;
+ int fde_flag = 0;
+
+ fde_pos = dio_GetPos();
+ fde_length = dio_ReadU4();
+ if (fde_length == 0) continue;
+ if (fde_length == ~(U4_T)0) {
+ fde_length = dio_ReadU8();
+ fde_dwarf64 = 1;
+ }
+ ref_pos = dio_GetPos();
+ fde_end = ref_pos + fde_length;
+ if (fde_end > rules.section->size) {
+ U4_T alignment = section->alignment;
+ if (alignment > 1 && fde_pos % alignment != 0) {
+ /* Workaround for sections with invalid alignment */
+ dio_SetPos(fde_pos + alignment - fde_pos % alignment);
+ continue;
+ }
+ else {
+ char msg[256];
+ snprintf(msg, sizeof(msg),
+ "Invalid length 0x%" PRIX64
+ " in FDE at 0x%" PRIX64, fde_length, fde_pos);
+ str_exception(ERR_INV_DWARF, msg);
+ }
+ }
+ cie_ref = fde_dwarf64 ? dio_ReadU8() : dio_ReadU4();
+ if (rules.eh_frame) fde_flag = cie_ref != 0;
+ else if (fde_dwarf64) fde_flag = cie_ref != ~(U8_T)0;
+ else fde_flag = cie_ref != ~(U4_T)0;
+ if (fde_flag) {
+ ELF_Section * sec = NULL;
+ FrameInfoRange * range = NULL;
+ if (rules.eh_frame) cie_ref = ref_pos - cie_ref;
+ if (cie_ref != rules.cie_pos) read_frame_cie(fde_pos, cie_ref);
+ if (cache->mFrameInfoRangesCnt >= cache->mFrameInfoRangesMax) {
+ cache->mFrameInfoRangesMax += 512;
+ if (cache->mFrameInfoRanges == NULL) cache->mFrameInfoRangesMax += (unsigned)(section->size / 32);
+ cache->mFrameInfoRanges = (FrameInfoRange *)loc_realloc(cache->mFrameInfoRanges,
+ cache->mFrameInfoRangesMax * sizeof(FrameInfoRange));
+ }
+ range = cache->mFrameInfoRanges + cache->mFrameInfoRangesCnt++;
+ range->mAddr = (ContextAddress)read_frame_data_pointer(rules.addr_encoding, &sec);
+ range->mSize = (ContextAddress)read_frame_data_pointer(rules.addr_encoding, NULL);
+ range->mOffset = fde_pos;
+ }
+ dio_SetPos(fde_end);
+ }
+ dio_ExitSection();
+ qsort(cache->mFrameInfoRanges, cache->mFrameInfoRangesCnt, sizeof(FrameInfoRange), cmp_frame_info_ranges);
+}
+
+void get_dwarf_stack_frame_info(Context * ctx, ELF_File * file, ELF_Section * sec, U8_T IP) {
+ DWARFCache * cache = get_dwarf_cache(file);
+ ELF_Section * section = cache->mDebugFrame;
+ unsigned l, h;
+
+ dwarf_stack_trace_regs_cnt = 0;
+ if (dwarf_stack_trace_fp == NULL) {
+ dwarf_stack_trace_fp = (StackTracingCommandSequence *)loc_alloc_zero(sizeof(StackTracingCommandSequence));
+ dwarf_stack_trace_fp->cmds_max = 1;
+ }
+ dwarf_stack_trace_fp->cmds_cnt = 0;
+ dwarf_stack_trace_addr = 0;
+ dwarf_stack_trace_size = 0;
+
+ if (section == NULL) section = cache->mEHFrame;
+ if (section == NULL) return;
+
+ memset(&rules, 0, sizeof(StackFrameRules));
+ rules.ctx = ctx;
+ rules.section = section;
+ rules.eh_frame = section == cache->mEHFrame;
+ rules.reg_id_scope.big_endian = file->big_endian;
+ rules.reg_id_scope.machine = file->machine;
+ rules.reg_id_scope.os_abi = file->os_abi;
+ rules.reg_id_scope.id_type = rules.eh_frame ? REGNUM_EH_FRAME : REGNUM_DWARF;
+ rules.cie_pos = ~(U8_T)0;
+
+ if (cache->mFrameInfoRanges == NULL) create_search_index(cache, section);
+ l = 0;
+ h = cache->mFrameInfoRangesCnt;
+ while (l < h) {
+ unsigned k = (l + h) / 2;
+ FrameInfoRange * range = cache->mFrameInfoRanges + k;
+ assert(cache->mFrameInfoRanges[l].mAddr <= cache->mFrameInfoRanges[h - 1].mAddr);
+ if (range->mAddr > IP) {
+ h = k;
+ }
+ else if (range->mAddr + range->mSize <= IP) {
+ l = k + 1;
+ }
+ else {
+ read_frame_fde(section, IP, range->mOffset);
+ return;
+ }
+ }
+ if (sec != NULL && sec->name != NULL && strcmp(sec->name, ".plt") == 0) {
+ assert(IP >= sec->addr);
+ assert(IP < sec->addr + sec->size);
+ if (generate_plt_section_commands(IP - sec->addr)) return;
+ }
+}
+
+#endif /* ENABLE_ELF && ENABLE_DebugContext */

Back to the top