1 /*
2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "dfx_instructions.h"
17
18 #include <algorithm>
19 #include <cstdio>
20 #include <cstdlib>
21
22 #include "dfx_define.h"
23 #include "dfx_errors.h"
24 #include "dfx_log.h"
25 #include "dfx_instr_statistic.h"
26 #include "dfx_regs_qut.h"
27 #include "dwarf_op.h"
28
29 namespace OHOS {
30 namespace HiviewDFX {
31 namespace {
32 #undef LOG_DOMAIN
33 #undef LOG_TAG
34 #define LOG_DOMAIN 0xD002D11
35 #define LOG_TAG "DfxInstructions"
36 }
37
Flush(DfxRegs & regs,std::shared_ptr<DfxMemory> memory,uintptr_t cfa,RegLoc loc,uintptr_t & val)38 bool DfxInstructions::Flush(DfxRegs& regs, std::shared_ptr<DfxMemory> memory, uintptr_t cfa, RegLoc loc, uintptr_t& val)
39 {
40 if (memory == nullptr) {
41 return false;
42 }
43 uintptr_t location;
44 switch (loc.type) {
45 case REG_LOC_VAL_OFFSET:
46 val = cfa + static_cast<uintptr_t>(loc.val);
47 break;
48 case REG_LOC_MEM_OFFSET:
49 location = cfa + static_cast<uintptr_t>(loc.val);
50 memory->ReadUptr(location, &val);
51 break;
52 case REG_LOC_REGISTER:
53 location = static_cast<uintptr_t>(loc.val);
54 if (location >= regs.RegsSize()) {
55 LOGE("%s", "Illegal register location");
56 return false;
57 }
58 val = regs[location];
59 break;
60 case REG_LOC_MEM_EXPRESSION: {
61 DwarfOp<uintptr_t> dwarfOp(memory);
62 location = dwarfOp.Eval(regs, cfa, loc.val);
63 memory->ReadUptr(location, &val);
64 break;
65 }
66 case REG_LOC_VAL_EXPRESSION: {
67 DwarfOp<uintptr_t> dwarfOp(memory);
68 val = dwarfOp.Eval(regs, cfa, loc.val);
69 break;
70 }
71 default:
72 LOGE("%s", "Failed to save register.");
73 return false;
74 }
75 return true;
76 }
77
Apply(std::shared_ptr<DfxMemory> memory,DfxRegs & regs,RegLocState & rsState,uint16_t & errCode)78 bool DfxInstructions::Apply(std::shared_ptr<DfxMemory> memory, DfxRegs& regs, RegLocState& rsState, uint16_t& errCode)
79 {
80 uintptr_t cfa = 0;
81 RegLoc cfaLoc;
82 if (rsState.cfaReg != 0) {
83 cfa = regs[rsState.cfaReg] + static_cast<uint32_t>(rsState.cfaRegOffset);
84 } else if (rsState.cfaExprPtr != 0) {
85 cfaLoc.type = REG_LOC_VAL_EXPRESSION;
86 cfaLoc.val = static_cast<intptr_t>(rsState.cfaExprPtr);
87 if (!Flush(regs, memory, 0, cfaLoc, cfa)) {
88 LOGE("%s", "Failed to update cfa.");
89 return false;
90 }
91 } else {
92 LOGE("%s", "no cfa info exist?");
93 INSTR_STATISTIC(UnsupportedDefCfa, rsState.cfaReg, UNW_ERROR_NOT_SUPPORT);
94 return false;
95 }
96 LOGU("Update cfa : %" PRIx64 "", (uint64_t)cfa);
97
98 for (size_t i = 0; i < rsState.locs.size(); i++) {
99 if (rsState.locs[i].type != REG_LOC_UNUSED) {
100 size_t reg = DfxRegsQut::GetQutRegs()[i];
101 if (Flush(regs, memory, cfa, rsState.locs[i], regs[reg])) {
102 LOGU("Update reg[%zu] : %" PRIx64 "", reg, (uint64_t)regs[reg]);
103 }
104 }
105 }
106
107 regs.SetSp(cfa);
108
109 if (rsState.returnAddressUndefined) {
110 regs.SetPc(0);
111 errCode = UNW_ERROR_RETURN_ADDRESS_UNDEFINED;
112 return false;
113 } else {
114 if (rsState.returnAddressRegister >= REG_EH && rsState.returnAddressRegister < REG_LAST) {
115 LOGU("returnAddressRegister: %d", (int)rsState.returnAddressRegister);
116 regs.SetPc(regs[rsState.returnAddressRegister]);
117 } else {
118 LOGE("returnAddressRegister: %d error", (int)rsState.returnAddressRegister);
119 errCode = UNW_ERROR_ILLEGAL_VALUE;
120 return false;
121 }
122 }
123 if (rsState.returnAddressSame) {
124 errCode = UNW_ERROR_RETURN_ADDRESS_SAME;
125 return false;
126 }
127
128 return true;
129 }
130 } // namespace HiviewDFX
131 } // namespace OHOS
132