1800b99b8Sopenharmony_ci/*
2800b99b8Sopenharmony_ci * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License.
5800b99b8Sopenharmony_ci * You may obtain a copy of the License at
6800b99b8Sopenharmony_ci *
7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8800b99b8Sopenharmony_ci *
9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and
13800b99b8Sopenharmony_ci * limitations under the License.
14800b99b8Sopenharmony_ci */
15800b99b8Sopenharmony_ci
16800b99b8Sopenharmony_ci#include "dfx_instructions.h"
17800b99b8Sopenharmony_ci
18800b99b8Sopenharmony_ci#include <algorithm>
19800b99b8Sopenharmony_ci#include <cstdio>
20800b99b8Sopenharmony_ci#include <cstdlib>
21800b99b8Sopenharmony_ci
22800b99b8Sopenharmony_ci#include "dfx_define.h"
23800b99b8Sopenharmony_ci#include "dfx_errors.h"
24800b99b8Sopenharmony_ci#include "dfx_log.h"
25800b99b8Sopenharmony_ci#include "dfx_instr_statistic.h"
26800b99b8Sopenharmony_ci#include "dfx_regs_qut.h"
27800b99b8Sopenharmony_ci#include "dwarf_op.h"
28800b99b8Sopenharmony_ci
29800b99b8Sopenharmony_cinamespace OHOS {
30800b99b8Sopenharmony_cinamespace HiviewDFX {
31800b99b8Sopenharmony_cinamespace {
32800b99b8Sopenharmony_ci#undef LOG_DOMAIN
33800b99b8Sopenharmony_ci#undef LOG_TAG
34800b99b8Sopenharmony_ci#define LOG_DOMAIN 0xD002D11
35800b99b8Sopenharmony_ci#define LOG_TAG "DfxInstructions"
36800b99b8Sopenharmony_ci}
37800b99b8Sopenharmony_ci
38800b99b8Sopenharmony_cibool DfxInstructions::Flush(DfxRegs& regs, std::shared_ptr<DfxMemory> memory, uintptr_t cfa, RegLoc loc, uintptr_t& val)
39800b99b8Sopenharmony_ci{
40800b99b8Sopenharmony_ci    if (memory == nullptr) {
41800b99b8Sopenharmony_ci        return false;
42800b99b8Sopenharmony_ci    }
43800b99b8Sopenharmony_ci    uintptr_t location;
44800b99b8Sopenharmony_ci    switch (loc.type) {
45800b99b8Sopenharmony_ci        case REG_LOC_VAL_OFFSET:
46800b99b8Sopenharmony_ci            val = cfa + static_cast<uintptr_t>(loc.val);
47800b99b8Sopenharmony_ci            break;
48800b99b8Sopenharmony_ci        case REG_LOC_MEM_OFFSET:
49800b99b8Sopenharmony_ci            location = cfa + static_cast<uintptr_t>(loc.val);
50800b99b8Sopenharmony_ci            memory->ReadUptr(location, &val);
51800b99b8Sopenharmony_ci            break;
52800b99b8Sopenharmony_ci        case REG_LOC_REGISTER:
53800b99b8Sopenharmony_ci            location = static_cast<uintptr_t>(loc.val);
54800b99b8Sopenharmony_ci            if (location >= regs.RegsSize()) {
55800b99b8Sopenharmony_ci                DFXLOGE("Illegal register location");
56800b99b8Sopenharmony_ci                return false;
57800b99b8Sopenharmony_ci            }
58800b99b8Sopenharmony_ci            val = regs[location];
59800b99b8Sopenharmony_ci            break;
60800b99b8Sopenharmony_ci        case REG_LOC_MEM_EXPRESSION: {
61800b99b8Sopenharmony_ci            DwarfOp<uintptr_t> dwarfOp(memory);
62800b99b8Sopenharmony_ci            location = dwarfOp.Eval(regs, cfa, loc.val);
63800b99b8Sopenharmony_ci            memory->ReadUptr(location, &val);
64800b99b8Sopenharmony_ci            break;
65800b99b8Sopenharmony_ci        }
66800b99b8Sopenharmony_ci        case REG_LOC_VAL_EXPRESSION: {
67800b99b8Sopenharmony_ci            DwarfOp<uintptr_t> dwarfOp(memory);
68800b99b8Sopenharmony_ci            val = dwarfOp.Eval(regs, cfa, loc.val);
69800b99b8Sopenharmony_ci            break;
70800b99b8Sopenharmony_ci        }
71800b99b8Sopenharmony_ci        default:
72800b99b8Sopenharmony_ci            DFXLOGE("Failed to save register.");
73800b99b8Sopenharmony_ci            return false;
74800b99b8Sopenharmony_ci    }
75800b99b8Sopenharmony_ci    return true;
76800b99b8Sopenharmony_ci}
77800b99b8Sopenharmony_ci
78800b99b8Sopenharmony_cibool DfxInstructions::Apply(std::shared_ptr<DfxMemory> memory, DfxRegs& regs, RegLocState& rsState, uint16_t& errCode)
79800b99b8Sopenharmony_ci{
80800b99b8Sopenharmony_ci    uintptr_t cfa = 0;
81800b99b8Sopenharmony_ci    RegLoc cfaLoc;
82800b99b8Sopenharmony_ci    if (rsState.cfaReg != 0) {
83800b99b8Sopenharmony_ci        cfa = regs[rsState.cfaReg] + static_cast<uint32_t>(rsState.cfaRegOffset);
84800b99b8Sopenharmony_ci    } else if (rsState.cfaExprPtr != 0) {
85800b99b8Sopenharmony_ci        cfaLoc.type = REG_LOC_VAL_EXPRESSION;
86800b99b8Sopenharmony_ci        cfaLoc.val = static_cast<intptr_t>(rsState.cfaExprPtr);
87800b99b8Sopenharmony_ci        if (!Flush(regs, memory, 0, cfaLoc, cfa)) {
88800b99b8Sopenharmony_ci            DFXLOGE("Failed to update cfa.");
89800b99b8Sopenharmony_ci            return false;
90800b99b8Sopenharmony_ci        }
91800b99b8Sopenharmony_ci    } else {
92800b99b8Sopenharmony_ci        DFXLOGE("no cfa info exist?");
93800b99b8Sopenharmony_ci        INSTR_STATISTIC(UnsupportedDefCfa, rsState.cfaReg, UNW_ERROR_NOT_SUPPORT);
94800b99b8Sopenharmony_ci        return false;
95800b99b8Sopenharmony_ci    }
96800b99b8Sopenharmony_ci    DFXLOGU("Update cfa : %{public}" PRIx64 "", (uint64_t)cfa);
97800b99b8Sopenharmony_ci
98800b99b8Sopenharmony_ci    for (size_t i = 0; i < rsState.locs.size(); i++) {
99800b99b8Sopenharmony_ci        if (rsState.locs[i].type != REG_LOC_UNUSED) {
100800b99b8Sopenharmony_ci            size_t reg = DfxRegsQut::GetQutRegs()[i];
101800b99b8Sopenharmony_ci            if (Flush(regs, memory, cfa, rsState.locs[i], regs[reg])) {
102800b99b8Sopenharmony_ci                DFXLOGU("Update reg[%{public}zu] : %{public}" PRIx64 "", reg, (uint64_t)regs[reg]);
103800b99b8Sopenharmony_ci            }
104800b99b8Sopenharmony_ci        }
105800b99b8Sopenharmony_ci    }
106800b99b8Sopenharmony_ci
107800b99b8Sopenharmony_ci    regs.SetSp(cfa);
108800b99b8Sopenharmony_ci
109800b99b8Sopenharmony_ci    if (rsState.returnAddressUndefined) {
110800b99b8Sopenharmony_ci        regs.SetPc(0);
111800b99b8Sopenharmony_ci        errCode = UNW_ERROR_RETURN_ADDRESS_UNDEFINED;
112800b99b8Sopenharmony_ci        return false;
113800b99b8Sopenharmony_ci    } else {
114800b99b8Sopenharmony_ci        if (rsState.returnAddressRegister >= REG_EH && rsState.returnAddressRegister < REG_LAST) {
115800b99b8Sopenharmony_ci            DFXLOGU("returnAddressRegister: %{public}d", (int)rsState.returnAddressRegister);
116800b99b8Sopenharmony_ci            regs.SetPc(regs[rsState.returnAddressRegister]);
117800b99b8Sopenharmony_ci        } else {
118800b99b8Sopenharmony_ci            DFXLOGE("returnAddressRegister: %{public}d error", (int)rsState.returnAddressRegister);
119800b99b8Sopenharmony_ci            errCode = UNW_ERROR_ILLEGAL_VALUE;
120800b99b8Sopenharmony_ci            return false;
121800b99b8Sopenharmony_ci        }
122800b99b8Sopenharmony_ci    }
123800b99b8Sopenharmony_ci    if (rsState.returnAddressSame) {
124800b99b8Sopenharmony_ci        errCode = UNW_ERROR_RETURN_ADDRESS_SAME;
125800b99b8Sopenharmony_ci        return false;
126800b99b8Sopenharmony_ci    }
127800b99b8Sopenharmony_ci
128800b99b8Sopenharmony_ci    return true;
129800b99b8Sopenharmony_ci}
130800b99b8Sopenharmony_ci} // namespace HiviewDFX
131800b99b8Sopenharmony_ci} // namespace OHOS
132