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