static void read_mod_fund_type(U2_T Form, ObjectInfo ** Type) { U1_T * Buf; size_t BufSize; size_t BufPos; dio_ChkBlock(Form, &Buf, &BufSize); *Type = find_object_info(sDebugSection->addr + dio_GetPos() - 1); (*Type)->mTag = TAG_lo_user; (*Type)->mCompUnit = sCompUnit; (*Type)->mEncoding = Buf[BufSize - 1]; BufPos = BufSize - 1; while (BufPos > 0) { U2_T Tag = 0; ObjectInfo * Mod = NULL; switch (Buf[--BufPos]) { case MOD_volatile: case MOD_const: continue; case MOD_pointer_to: Tag = TAG_pointer_type; break; case MOD_reference_to: Tag = TAG_reference_type; break; } Mod = find_object_info(sDebugSection->addr + dio_GetPos() - BufSize + BufPos); Mod->mTag = Tag; Mod->mCompUnit = sCompUnit; Mod->mType = *Type; *Type = Mod; } }
static void read_mod_user_def_type(U2_T Form, ObjectInfo ** Type) { U1_T * Buf; size_t BufSize; size_t BufPos; int i; U4_T Ref = 0; dio_ChkBlock(Form, &Buf, &BufSize); for (i = 0; i < 4; i++) { Ref |= (U4_T)Buf[BufSize - 4 + (sDebugSection->file->big_endian ? 3 - i : i)] << (i * 8); } *Type = find_object_info(sDebugSection->addr + Ref); BufPos = BufSize - 4; while (BufPos > 0) { U2_T Tag = 0; ObjectInfo * Mod = NULL; switch (Buf[--BufPos]) { case MOD_volatile: case MOD_const: continue; case MOD_pointer_to: Tag = TAG_pointer_type; break; case MOD_reference_to: Tag = TAG_reference_type; break; } Mod = find_object_info(sDebugSection->addr + dio_GetPos() - BufSize + BufPos); Mod->mTag = Tag; Mod->mCompUnit = sCompUnit; Mod->mType = *Type; *Type = Mod; } }
static void load_debug_sections(void) { Trap trap; unsigned idx; ELF_File * File = sCache->mFile; memset(&trap, 0, sizeof(trap)); sSymbolTableLen = sCache->mSymbolTableLen; sObjectList = NULL; sObjectListTail = NULL; sCompUnitsMax = 0; for (idx = 1; idx < File->section_cnt; idx++) { ELF_Section * sec = File->sections + idx; if (sec->size == 0) continue; if (sec->name == NULL) continue; if (strcmp(sec->name, ".debug") == 0 || strcmp(sec->name, ".debug_info") == 0) { sDebugSection = sec; sParentObject = NULL; sPrevSibling = NULL; dio_EnterDebugSection(NULL, sec, 0); if (set_trap(&trap)) { while (dio_GetPos() < sec->size) { dio_ReadUnit(&sUnitDesc, entry_callback); sCompUnit->mDesc = sUnitDesc; } clear_trap(&trap); } dio_ExitSection(); sParentObject = NULL; sPrevSibling = NULL; sCompUnit = NULL; sDebugSection = NULL; if (trap.error) break; } else if (strcmp(sec->name, ".debug_ranges") == 0) { sCache->mDebugRanges = sec; } else if (strcmp(sec->name, ".debug_aranges") == 0) { sCache->mDebugARanges = sec; } else if (strcmp(sec->name, ".debug_line") == 0) { sCache->mDebugLine = sec; } else if (strcmp(sec->name, ".debug_loc") == 0) { sCache->mDebugLoc = sec; } } if (sObjectList == NULL) { loc_free(sCache->mObjectHash); sCache->mObjectHash = NULL; } sCache->mObjectList = sObjectList; sSymbolTableLen = 0; sObjectList = NULL; sObjectListTail = NULL; sCompUnitsMax = 0; if (trap.error) str_exception(trap.error, trap.msg); }
void load_line_numbers(DWARFCache * Cache, CompUnit * Unit) { Trap trap; if (Unit->mFiles != NULL && Unit->mDirs != NULL) return; if (elf_load(Cache->mDebugLine)) exception(errno); dio_EnterDataSection(&Unit->mDesc, Cache->mDebugLine->data, Unit->mLineInfoOffs, Cache->mDebugLine->size); if (set_trap(&trap)) { U8_T header_pos = 0; U1_T opcode_base = 0; U1_T opcode_size[256]; U8_T header_size = 0; U1_T min_instruction_length = 0; U1_T is_stmt_default = 0; I1_T line_base = 0; U1_T line_range = 0; U8_T unit_size = 0; int dwarf64 = 0; LineNumbersState state; /* Read header */ unit_size = dio_ReadU4(); if (unit_size == 0xffffffffu) { unit_size = dio_ReadU8(); unit_size += 12; dwarf64 = 1; } else { unit_size += 4; } dio_ReadU2(); /* line info version */ header_size = dwarf64 ? dio_ReadU8() : (U8_T)dio_ReadU4(); header_pos = dio_GetPos(); min_instruction_length = dio_ReadU1(); is_stmt_default = dio_ReadU1() != 0; line_base = (I1_T)dio_ReadU1(); line_range = dio_ReadU1(); opcode_base = dio_ReadU1(); memset(opcode_size, 0, sizeof(opcode_size)); dio_Read(opcode_size + 1, opcode_base - 1); /* Read directory names */ for (;;) { char * Name = dio_ReadString(); if (Name == NULL) break; add_dir(Unit, Name); } /* Read source sFileLocks info */ for (;;) { U4_T dir = 0; FileInfo File; memset(&File, 0, sizeof(File)); File.mName = dio_ReadString(); if (File.mName == NULL) break; dir = dio_ReadULEB128(); if (dir > 0 && dir <= Unit->mDirsCnt) File.mDir = Unit->mDirs[dir - 1]; File.mModTime = dio_ReadULEB128(); File.mSize = dio_ReadULEB128(); add_file(Unit, &File); } /* Run the program */ if (header_pos + header_size != dio_GetPos()) str_exception(ERR_INV_DWARF, "Invalid line info header"); memset(&state, 0, sizeof(state)); state.mFile = 1; state.mLine = 1; if (is_stmt_default) state.mFlags |= LINE_IsStmt; while (dio_GetPos() < Unit->mLineInfoOffs + unit_size) { U1_T opcode = dio_ReadU1(); if (opcode >= opcode_base) { state.mLine += (unsigned)((int)((opcode - opcode_base) % line_range) + line_base); state.mAddress += (opcode - opcode_base) / line_range * min_instruction_length; add_state(Unit, &state); state.mFlags &= ~(LINE_BasicBlock | LINE_PrologueEnd | LINE_EpilogueBegin); } else if (opcode == 0) { U4_T op_size = dio_ReadULEB128(); U8_T op_pos = dio_GetPos(); switch (dio_ReadU1()) { case DW_LNE_define_file: { U4_T dir = 0; FileInfo File; memset(&File, 0, sizeof(File)); File.mName = dio_ReadString(); dir = dio_ReadULEB128(); if (dir > 0 && dir <= Unit->mDirsCnt) File.mDir = Unit->mDirs[dir - 1]; File.mModTime = dio_ReadULEB128(); File.mSize = dio_ReadULEB128(); add_file(Unit, &File); break; } case DW_LNE_end_sequence: state.mFlags |= LINE_EndSequence; add_state(Unit, &state); memset(&state, 0, sizeof(state)); state.mFile = 1; state.mLine = 1; if (is_stmt_default) state.mFlags |= LINE_IsStmt; else state.mFlags &= ~LINE_IsStmt; break; case DW_LNE_set_address: state.mAddress = (ContextAddress)dio_ReadAddress(); break; default: dio_Skip(op_size - 1); break; } if (dio_GetPos() != op_pos + op_size) str_exception(ERR_INV_DWARF, "Invalid line info op size"); } else { switch (opcode) { case DW_LNS_copy: add_state(Unit, &state); state.mFlags &= ~(LINE_BasicBlock | LINE_PrologueEnd | LINE_EpilogueBegin); break; case DW_LNS_advance_pc: state.mAddress += (ContextAddress)(dio_ReadU8LEB128() * min_instruction_length); break; case DW_LNS_advance_line: state.mLine += dio_ReadSLEB128(); break; case DW_LNS_set_file: state.mFile = dio_ReadULEB128(); break; case DW_LNS_set_column: state.mColumn = dio_ReadULEB128(); break; case DW_LNS_negate_stmt: state.mFlags ^= LINE_IsStmt; break; case DW_LNS_set_basic_block: state.mFlags |= LINE_BasicBlock; break; case DW_LNS_const_add_pc: state.mAddress += (255 - opcode_base) / line_range * min_instruction_length; break; case DW_LNS_fixed_advance_pc: state.mAddress += dio_ReadU2(); break; case DW_LNS_set_prologue_end: state.mFlags |= LINE_PrologueEnd; break; case DW_LNS_set_epilogue_begin: state.mFlags |= LINE_EpilogueBegin; break; case DW_LNS_set_isa: state.mISA = (U1_T)dio_ReadULEB128(); break; default: str_exception(ERR_INV_DWARF, "Invalid line info op code"); break; } } } dio_ExitSection(); clear_trap(&trap); } else { dio_ExitSection(); free_unit_cache(Unit); str_exception(trap.error, trap.msg); } }
static void read_object_attributes(U2_T Tag, U2_T Attr, U2_T Form) { static ObjectInfo * Info; static U8_T Sibling; switch (Attr) { case 0: if (Form) { Info = find_object_info(sDebugSection->addr + dio_gEntryPos); Info->mTag = Tag; Info->mCompUnit = sCompUnit; Info->mParent = sParentObject; /* TODO: Default AT_lower_bound value is language dependand */ Sibling = 0; } else { if (Tag == TAG_enumerator && Info->mType == NULL) Info->mType = sParentObject; if (sPrevSibling != NULL) sPrevSibling->mSibling = Info; else if (sParentObject != NULL) sParentObject->mChildren = Info; else sCompUnit->mChildren = Info; sPrevSibling = Info; if (Sibling != 0) { U8_T SiblingPos = Sibling; ObjectInfo * Parent = sParentObject; ObjectInfo * PrevSibling = sPrevSibling; sParentObject = Info; sPrevSibling = NULL; while (dio_GetPos() < SiblingPos) dio_ReadEntry(entry_callback); sParentObject = Parent; sPrevSibling = PrevSibling; } } break; case AT_sibling: dio_ChkRef(Form); Sibling = dio_gFormRef - sDebugSection->addr; break; case AT_type: dio_ChkRef(Form); Info->mType = find_object_info(dio_gFormRef); break; case AT_fund_type: dio_ChkData(Form); Info->mType = find_object_info(sDebugSection->addr + dio_GetPos() - dio_gFormDataSize); Info->mType->mTag = TAG_lo_user; Info->mCompUnit = sCompUnit; Info->mType->mEncoding = (U2_T)dio_gFormData; break; case AT_user_def_type: dio_ChkRef(Form); Info->mType = find_object_info(dio_gFormRef); break; case AT_mod_fund_type: read_mod_fund_type(Form, &Info->mType); break; case AT_mod_u_d_type: read_mod_user_def_type(Form, &Info->mType); break; case AT_encoding: dio_ChkData(Form); Info->mEncoding = (U2_T)dio_gFormData; break; case AT_low_pc: dio_ChkAddr(Form); Info->mLowPC = (ContextAddress)dio_gFormRef; break; case AT_high_pc: dio_ChkAddr(Form); Info->mHighPC = (ContextAddress)dio_gFormRef; break; case AT_name: dio_ChkString(Form); Info->mName = dio_gFormDataAddr; break; } }
static void exec_stack_frame_instruction(U8_T func_addr) { RegisterRules * reg; U1_T op = dio_ReadU1(); U4_T n; switch (op) { case CFA_nop: break; case CFA_set_loc: rules.location = read_frame_data_pointer(rules.addr_encoding, &rules.loc_section, func_addr); break; case CFA_advance_loc1: rules.location += dio_ReadU1() * rules.code_alignment; break; case CFA_advance_loc2: rules.location += dio_ReadU2() * rules.code_alignment; break; case CFA_advance_loc4: rules.location += dio_ReadU4() * rules.code_alignment; break; case CFA_offset_extended: reg = get_reg(&frame_regs, dio_ReadULEB128()); reg->rule = RULE_OFFSET; reg->offset = dio_ReadULEB128() * rules.data_alignment; break; case CFA_restore_extended: n = dio_ReadULEB128(); reg = get_reg(&frame_regs, n); *reg = *get_reg(&cie_regs, n); break; case CFA_undefined: reg = get_reg(&frame_regs, dio_ReadULEB128()); memset(reg, 0, sizeof(*reg)); break; case CFA_same_value: reg = get_reg(&frame_regs, dio_ReadULEB128()); reg->rule = RULE_SAME_VALUE; break; case CFA_register: reg = get_reg(&frame_regs, dio_ReadULEB128()); reg->rule = RULE_REGISTER; reg->offset = dio_ReadULEB128(); break; case CFA_remember_state: copy_register_rules(get_regs_stack_item(regs_stack_pos++), &frame_regs); break; case 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 CFA_def_cfa: frame_regs.cfa_rule = RULE_OFFSET; frame_regs.cfa_register = dio_ReadULEB128(); frame_regs.cfa_offset = dio_ReadULEB128(); break; case CFA_def_cfa_register: frame_regs.cfa_rule = RULE_OFFSET; frame_regs.cfa_register = dio_ReadULEB128(); break; case CFA_def_cfa_offset: frame_regs.cfa_rule = RULE_OFFSET; frame_regs.cfa_offset = dio_ReadULEB128(); break; case CFA_def_cfa_expression: frame_regs.cfa_rule = RULE_EXPRESSION; frame_regs.cfa_offset = dio_ReadULEB128(); frame_regs.cfa_expression = dio_GetPos(); dio_Skip(frame_regs.cfa_offset); break; case 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 CFA_offset_extended_sf: reg = get_reg(&frame_regs, dio_ReadULEB128()); reg->rule = RULE_OFFSET; reg->offset = dio_ReadSLEB128() * rules.data_alignment; break; case CFA_def_cfa_sf: frame_regs.cfa_rule = RULE_OFFSET; frame_regs.cfa_register = dio_ReadULEB128(); frame_regs.cfa_offset = dio_ReadSLEB128() * rules.data_alignment; break; case CFA_def_cfa_offset_sf: frame_regs.cfa_rule = RULE_OFFSET; frame_regs.cfa_offset = dio_ReadSLEB128() * rules.data_alignment; break; case CFA_val_offset: reg = get_reg(&frame_regs, dio_ReadULEB128()); reg->rule = RULE_VAL_OFFSET; reg->offset = dio_ReadULEB128() * rules.data_alignment; break; case 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 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 CFA_CFA_GNU_window_save: /* SPARC-specific code */ for (n = 8; n < 16; n++) { reg = get_reg(&frame_regs, n); reg->rule = RULE_REGISTER; reg->offset = n + 16; } for (n = 16; n < 32; n++) { reg = get_reg(&frame_regs, n); reg->rule = RULE_OFFSET; reg->offset = (n - 16) * (rules.reg_id_scope.machine == EM_SPARCV9 ? 8 : 4); } break; case 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 CFA_GNU_negative_offset_ext: /* 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 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(§ion); ContextAddress rt_addr = elf_map_to_run_time_address( rules.ctx, rules.section->file, section, (ContextAddress)lt_addr); if (errno) str_exception(errno, "Cannot get object run-time address"); add_command(SFT_CMD_NUMBER)->args.num = rt_addr; } break; case OP_deref: { LocationExpressionCommand * cmd = add_command(SFT_CMD_RD_MEM); cmd->args.mem.size = rules.address_size; cmd->args.mem.big_endian = rules.reg_id_scope.big_endian; } break; case OP_deref_size: { LocationExpressionCommand * cmd = add_command(SFT_CMD_RD_MEM); cmd->args.mem.size = dio_ReadU1(); cmd->args.mem.big_endian = rules.reg_id_scope.big_endian; } break; case OP_const1u: add_command(SFT_CMD_NUMBER)->args.num = dio_ReadU1(); break; case OP_const1s: add_command(SFT_CMD_NUMBER)->args.num = (I1_T)dio_ReadU1(); break; case OP_const2u: add_command(SFT_CMD_NUMBER)->args.num = dio_ReadU2(); break; case OP_const2s: add_command(SFT_CMD_NUMBER)->args.num = (I2_T)dio_ReadU2(); break; case OP_const4u: add_command(SFT_CMD_NUMBER)->args.num = dio_ReadU4(); break; case OP_const4s: add_command(SFT_CMD_NUMBER)->args.num = (I4_T)dio_ReadU4(); break; case OP_const8u: add_command(SFT_CMD_NUMBER)->args.num = dio_ReadU8(); break; case OP_const8s: add_command(SFT_CMD_NUMBER)->args.num = (I8_T)dio_ReadU8(); break; case OP_constu: add_command(SFT_CMD_NUMBER)->args.num = dio_ReadU8LEB128(); break; case OP_consts: add_command(SFT_CMD_NUMBER)->args.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)->args.num = dio_ReadU8LEB128(); add_command(SFT_CMD_ADD); break; case OP_ge: add_command(SFT_CMD_GE); break; case OP_gt: add_command(SFT_CMD_GT); break; case OP_le: add_command(SFT_CMD_LE); break; case OP_lt: add_command(SFT_CMD_LT); break; case OP_shl: add_command(SFT_CMD_SHL); 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)->args.num = op - OP_lit0; break; case OP_reg0: case OP_reg1: case OP_reg2: case OP_reg3: case OP_reg4: case OP_reg5: case OP_reg6: case OP_reg7: case OP_reg8: case OP_reg9: case OP_reg10: case OP_reg11: case OP_reg12: case OP_reg13: case OP_reg14: case OP_reg15: case OP_reg16: case OP_reg17: case OP_reg18: case OP_reg19: case OP_reg20: case OP_reg21: case OP_reg22: case OP_reg23: case OP_reg24: case OP_reg25: case OP_reg26: case OP_reg27: case OP_reg28: case OP_reg29: case OP_reg30: case OP_reg31: { RegisterDefinition * def = get_reg_by_id(rules.ctx, op - OP_reg0, &rules.reg_id_scope); if (def == NULL) str_exception(errno, "Cannot read DWARF frame info"); add_command(SFT_CMD_RD_REG)->args.reg = def; } break; case OP_regx: { unsigned n = (unsigned)dio_ReadULEB128(); RegisterDefinition * def = get_reg_by_id(rules.ctx, n, &rules.reg_id_scope); if (def == NULL) str_exception(errno, "Cannot read DWARF frame info"); add_command(SFT_CMD_RD_REG)->args.reg = def; } 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_RD_REG)->args.reg = def; if (offs != 0) { add_command(SFT_CMD_NUMBER)->args.num = offs; add_command(SFT_CMD_ADD); } } break; case OP_bregx: { unsigned n = (unsigned)dio_ReadULEB128(); I8_T offs = dio_ReadS8LEB128(); RegisterDefinition * def = get_reg_by_id(rules.ctx, n, &rules.reg_id_scope); if (def == NULL) str_exception(errno, "Cannot read DWARF frame info"); add_command(SFT_CMD_RD_REG)->args.reg = def; if (offs != 0) { add_command(SFT_CMD_NUMBER)->args.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 U8_T read_frame_data_pointer(U1_T encoding, ELF_Section ** sec, U8_T func_addr) { U8_T v = 0; U8_T pos; unsigned idx; ELF_File * file; if (encoding == EH_PE_omit) return 0; pos = dio_GetPos(); /* Decode the base or adjust the offset */ switch ((encoding >> 4) & 0x7) { case 0: case EH_PB_funcrel: v = func_addr; break; case EH_PB_pcrel: if (sec != NULL) { v = pos + rules.section->addr; } break; case EH_PB_datarel: if (sec != NULL) { v = rules.section->addr; } break; case EH_PB_textrel: if (sec != NULL && rules.text_section != NULL) { v = rules.text_section->addr; } break; case EH_PB_aligned: if ((pos % rules.address_size) != 0) dio_SetPos(pos + (rules.address_size - (pos % rules.address_size))); break; default: str_exception(ERR_INV_DWARF, "Unknown encoding of .eh_frame section pointers"); break; } /* Decode the value */ 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_ReadAddressX(sec, 2); break; case EH_PE_udata4: v += dio_ReadAddressX(sec, 4); break; case EH_PE_udata8: v += dio_ReadAddressX(sec, 8); break; case EH_PE_sleb128: v += dio_ReadS8LEB128(); break; case EH_PE_sdata2: v += (I2_T)dio_ReadAddressX(sec, 2); break; case EH_PE_sdata4: v += (I4_T)dio_ReadAddressX(sec, 4); break; case EH_PE_sdata8: v += (I8_T)dio_ReadAddressX(sec, 8); break; default: str_exception(ERR_INV_DWARF, "Unknown encoding of .eh_frame section pointers"); break; } if (encoding & EH_PE_indirect) { size_t size = rules.address_size; U8_T res = 0; file = rules.section->file; 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 create_search_index(DWARFCache * cache, FrameInfoIndex * index) { ELF_Section * section = index->mSection; 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 { str_fmt_exception(ERR_INV_DWARF, "Invalid length 0x%" PRIX64 " in FDE at 0x%" PRIX64, fde_length, fde_pos); } } 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 (index->mFrameInfoRangesCnt >= index->mFrameInfoRangesMax) { index->mFrameInfoRangesMax += 512; if (index->mFrameInfoRanges == NULL) index->mFrameInfoRangesMax += (unsigned)(section->size / 32); index->mFrameInfoRanges = (FrameInfoRange *)loc_realloc(index->mFrameInfoRanges, index->mFrameInfoRangesMax * sizeof(FrameInfoRange)); } range = index->mFrameInfoRanges + index->mFrameInfoRangesCnt++; memset(range, 0, sizeof(FrameInfoRange)); range->mAddr = (ContextAddress)read_frame_data_pointer(rules.addr_encoding, &sec, 0); range->mSize = (ContextAddress)read_frame_data_pointer(rules.addr_encoding, NULL, 0); if (sec != NULL) { range->mSection = sec->index; index->mRelocatable = 1; } range->mOffset = fde_pos; } dio_SetPos(fde_end); } dio_ExitSection(); qsort(index->mFrameInfoRanges, index->mFrameInfoRangesCnt, sizeof(FrameInfoRange), cmp_frame_info_ranges); }
static void read_frame_fde(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, rules.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; 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, &rules.loc_section, 0); Range = read_frame_data_pointer(rules.addr_encoding, NULL, 0); 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(Addr); assert(location0 <= IP); if (rules.location > IP) break; location0 = rules.location; } dwarf_stack_trace_addr = location0; dwarf_stack_trace_size = rules.location - location0; if (rules.reg_id_scope.machine == EM_ARM && IP + 4 == Addr + Range) { /* GCC generates invalid frame info for ARM function epilogue */ /* Ignore frame info, fall-back to stack crawl logic */ dio_ExitSection(); return; } generate_commands(); if (dwarf_stack_trace_regs_cnt == 0) { /* GHS generates dummy frame info with all registers marked undefined */ /* Ignore frame info, fall-back to stack crawl logic */ dwarf_stack_trace_fp->cmds_cnt = 0; dwarf_stack_trace_addr = 0; dwarf_stack_trace_size = 0; dio_ExitSection(); return; } } } dio_ExitSection(); }
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) { str_fmt_exception(ERR_INV_DWARF, "Invalid CIE pointer 0x%" PRIX64 " in FDE at 0x%" PRIX64, pos, fde_pos); } 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_fmt_exception(ERR_INV_DWARF, "Unsupported version of Call Frame Information: %d", rules.version); } 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': { Trap trap; U8_T addr_pos; rules.prh_encoding = dio_ReadU1(); addr_pos = dio_GetPos(); if (set_trap(&trap)) { read_frame_data_pointer(rules.prh_encoding, NULL, 0); clear_trap(&trap); } else { dio_SetPos(addr_pos + rules.address_size); } } break; case 'R': rules.addr_encoding = dio_ReadU1(); break; } } dio_SetPos(aug_pos + aug_length); } clear_frame_registers(&cie_regs); clear_frame_registers(&frame_regs); regs_stack_pos = 0; while (dio_GetPos() < cie_end) { exec_stack_frame_instruction(0); } copy_register_rules(&cie_regs, &frame_regs); dio_SetPos(saved_pos); }
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; } } }