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;
    }
}
Beispiel #6
0
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;
        }
    }
}
Beispiel #7
0
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 (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");
        }
    }
}
Beispiel #8
0
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;
}
Beispiel #9
0
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);
}
Beispiel #10
0
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();
}
Beispiel #11
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) {
        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);
}
Beispiel #12
0
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;
            }
        }
    }