• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 // for libunwind.h empty struct has size 0 in c, size 1 in c++
17 #include "register.h"
18 #if !is_mingw
19 #include <sys/utsname.h>
20 #endif
21 #if HAVE_LIBUNWIND
22 #include <libunwind.h>
23 #endif
24 #include "debug_logger.h"
25 
26 
27 namespace OHOS {
28 namespace Developtools {
29 namespace HiPerf {
30 static ArchType g_deviceArchType = ArchType::ARCH_UNKNOWN;
31 // order is IP , SP for ut
32 static const std::map<size_t, const std::string> PERF_REG_NAME_MAP = {
33 #if defined(target_cpu_x86_64)
34     {PERF_REG_X86_IP, "PERF_REG_X86_IP"},
35     {PERF_REG_X86_SP, "PERF_REG_X86_SP"},
36 #elif defined(target_cpu_arm)
37     {PERF_REG_ARM_PC, "PERF_REG_ARM_PC"},
38     {PERF_REG_ARM_SP, "PERF_REG_ARM_SP"},
39 #elif defined(target_cpu_arm64)
40     {PERF_REG_ARM64_PC, "PERF_REG_ARM64_PC"},
41     {PERF_REG_ARM64_SP, "PERF_REG_ARM64_SP"},
42 #endif
43 };
44 
45 // these copy from kerne uapi perf_regs.h
GetSupportedRegMask(ArchType arch)46 uint64_t GetSupportedRegMask(ArchType arch)
47 {
48     uint64_t result = 0;
49     switch (arch) {
50         case ArchType::ARCH_X86:
51             result = ((1ULL << PERF_REG_X86_32_MAX) - 1);
52             break;
53         case ArchType::ARCH_X86_64:
54             result = ((1ULL << PERF_REG_X86_64_MAX) - 1);
55             result &= ~((1ULL << PERF_REG_X86_DS) | (1ULL << PERF_REG_X86_ES) |
56                         (1ULL << PERF_REG_X86_FS) | (1ULL << PERF_REG_X86_GS));
57             break;
58         case ArchType::ARCH_ARM:
59             result = ((1ULL << PERF_REG_ARM_MAX) - 1);
60             break;
61         case ArchType::ARCH_ARM64:
62             result = ((1ULL << PERF_REG_ARM64_MAX) - 1);
63             break;
64         default:
65             result = std::numeric_limits<uint64_t>::max();
66             HLOGE("unsupport arch %d", arch);
67             break;
68     }
69     return result;
70 }
71 
72 #if HAVE_LIBUNWIND
73 const std::map<int, int> LibUnwindRegMap = {
74 #if defined(target_cpu_x86_64)
75     {UNW_X86_64_RAX, PERF_REG_X86_AX},  {UNW_X86_64_RDX, PERF_REG_X86_DX},
76     {UNW_X86_64_RCX, PERF_REG_X86_CX},  {UNW_X86_64_RBX, PERF_REG_X86_BX},
77     {UNW_X86_64_RSI, PERF_REG_X86_SI},  {UNW_X86_64_RDI, PERF_REG_X86_DI},
78     {UNW_X86_64_RBP, PERF_REG_X86_BP},  {UNW_X86_64_RSP, PERF_REG_X86_SP},
79     {UNW_X86_64_R8, PERF_REG_X86_R8},   {UNW_X86_64_R9, PERF_REG_X86_R9},
80     {UNW_X86_64_R10, PERF_REG_X86_R10}, {UNW_X86_64_R11, PERF_REG_X86_R11},
81     {UNW_X86_64_R12, PERF_REG_X86_R12}, {UNW_X86_64_R13, PERF_REG_X86_R13},
82     {UNW_X86_64_R14, PERF_REG_X86_R14}, {UNW_X86_64_R15, PERF_REG_X86_R15},
83     {UNW_X86_64_RIP, PERF_REG_X86_IP},
84 #elif defined(target_cpu_arm64)
85     {UNW_AARCH64_X0, PERF_REG_ARM64_X0},   {UNW_AARCH64_X1, PERF_REG_ARM64_X1},
86     {UNW_AARCH64_X2, PERF_REG_ARM64_X2},   {UNW_AARCH64_X3, PERF_REG_ARM64_X3},
87     {UNW_AARCH64_X4, PERF_REG_ARM64_X4},   {UNW_AARCH64_X5, PERF_REG_ARM64_X5},
88     {UNW_AARCH64_X6, PERF_REG_ARM64_X6},   {UNW_AARCH64_X7, PERF_REG_ARM64_X7},
89     {UNW_AARCH64_X8, PERF_REG_ARM64_X8},   {UNW_AARCH64_X9, PERF_REG_ARM64_X9},
90     {UNW_AARCH64_X10, PERF_REG_ARM64_X10}, {UNW_AARCH64_X11, PERF_REG_ARM64_X11},
91     {UNW_AARCH64_X12, PERF_REG_ARM64_X12}, {UNW_AARCH64_X13, PERF_REG_ARM64_X13},
92     {UNW_AARCH64_X14, PERF_REG_ARM64_X14}, {UNW_AARCH64_X15, PERF_REG_ARM64_X15},
93     {UNW_AARCH64_X16, PERF_REG_ARM64_X16}, {UNW_AARCH64_X17, PERF_REG_ARM64_X17},
94     {UNW_AARCH64_X18, PERF_REG_ARM64_X18}, {UNW_AARCH64_X19, PERF_REG_ARM64_X19},
95     {UNW_AARCH64_X20, PERF_REG_ARM64_X20}, {UNW_AARCH64_X21, PERF_REG_ARM64_X21},
96     {UNW_AARCH64_X22, PERF_REG_ARM64_X22}, {UNW_AARCH64_X23, PERF_REG_ARM64_X23},
97     {UNW_AARCH64_X24, PERF_REG_ARM64_X24}, {UNW_AARCH64_X25, PERF_REG_ARM64_X25},
98     {UNW_AARCH64_X26, PERF_REG_ARM64_X26}, {UNW_AARCH64_X27, PERF_REG_ARM64_X27},
99     {UNW_AARCH64_X28, PERF_REG_ARM64_X28}, {UNW_AARCH64_X29, PERF_REG_ARM64_X29},
100     {UNW_AARCH64_X30, PERF_REG_ARM64_LR},  {UNW_AARCH64_SP, PERF_REG_ARM64_SP},
101     {UNW_AARCH64_PC, PERF_REG_ARM64_PC},
102 #elif defined(target_cpu_arm)
103     {UNW_ARM_R0, PERF_REG_ARM_R0},  {UNW_ARM_R1, PERF_REG_ARM_R1},   {UNW_ARM_R2, PERF_REG_ARM_R2},
104     {UNW_ARM_R3, PERF_REG_ARM_R3},  {UNW_ARM_R4, PERF_REG_ARM_R4},   {UNW_ARM_R5, PERF_REG_ARM_R5},
105     {UNW_ARM_R6, PERF_REG_ARM_R6},  {UNW_ARM_R7, PERF_REG_ARM_R7},   {UNW_ARM_R8, PERF_REG_ARM_R8},
106     {UNW_ARM_R9, PERF_REG_ARM_R9},  {UNW_ARM_R10, PERF_REG_ARM_R10}, {UNW_ARM_R11, PERF_REG_ARM_FP},
107     {UNW_ARM_R12, PERF_REG_ARM_IP}, {UNW_ARM_R13, PERF_REG_ARM_SP},  {UNW_ARM_R14, PERF_REG_ARM_LR},
108     {UNW_ARM_R15, PERF_REG_ARM_PC},
109 #else
110 #error not support
111 #endif
112 };
113 
LibunwindRegIdToPerfReg(int libUnwindReg)114 int LibunwindRegIdToPerfReg(int libUnwindReg)
115 {
116     if (LibUnwindRegMap.count(libUnwindReg)) {
117         return LibUnwindRegMap.at(libUnwindReg);
118     } else {
119         HLOGE("unwind: invalid reg id %d", libUnwindReg);
120         return -EINVAL;
121     }
122 }
123 #endif
124 
UpdatePerfContext(uint64_t addr,perf_callchain_context & perfCallchainContext)125 const std::string UpdatePerfContext(uint64_t addr, perf_callchain_context &perfCallchainContext)
126 {
127     if (PERF_CONTEXT_NAME.count(addr) != 0) {
128         perfCallchainContext = static_cast<perf_callchain_context>(addr);
129         return StringPrintf("%s: %" PRIx64 "", PERF_CONTEXT_NAME.at(addr).c_str(), addr);
130     } else {
131         perfCallchainContext = PERF_CONTEXT_MAX;
132         return StringPrintf("unknow context: %" PRIx64 "", addr);
133     }
134 }
135 
GetArchName(ArchType arch)136 const std::string GetArchName(ArchType arch)
137 {
138     switch (arch) {
139         case ArchType::ARCH_X86:
140             return "X86_32";
141         case ArchType::ARCH_X86_64:
142             return "X86_64";
143         case ArchType::ARCH_ARM:
144             return "ARM";
145         case ArchType::ARCH_ARM64:
146             return "ARM64";
147         default:
148             return "Unsupport";
149     }
150 }
151 
RegisterGetIP(ArchType arch)152 size_t RegisterGetIP(ArchType arch)
153 {
154     switch (arch) {
155         case ArchType::ARCH_X86:
156         case ArchType::ARCH_X86_64:
157             return PERF_REG_X86_IP;
158         case ArchType::ARCH_ARM:
159             return PERF_REG_ARM_PC;
160         case ArchType::ARCH_ARM64:
161             return PERF_REG_ARM64_PC;
162         default:
163             return std::numeric_limits<size_t>::max();
164     }
165 }
166 
RegisterGetSP(ArchType arch)167 size_t RegisterGetSP(ArchType arch)
168 {
169     switch (arch) {
170         case ArchType::ARCH_X86:
171         case ArchType::ARCH_X86_64:
172             return PERF_REG_X86_SP;
173         case ArchType::ARCH_ARM:
174             return PERF_REG_ARM_SP;
175         case ArchType::ARCH_ARM64:
176             return PERF_REG_ARM64_SP;
177         default:
178             return std::numeric_limits<size_t>::max();
179     }
180 }
181 
RegisterGetName(size_t registerIndex)182 const std::string RegisterGetName(size_t registerIndex)
183 {
184     std::string name;
185     name.append("PerfReg[");
186     name.append(std::to_string(registerIndex));
187     if (PERF_REG_NAME_MAP.count(registerIndex) > 0) {
188         name.append(":");
189         name.append(PERF_REG_NAME_MAP.at(registerIndex));
190     }
191     name.append("]");
192     return name;
193 }
194 
RegisterGetValue(uint64_t & value,const u64 registers[],const size_t registerIndex,const size_t registerNumber)195 bool RegisterGetValue(uint64_t &value, const u64 registers[], const size_t registerIndex,
196                       const size_t registerNumber)
197 {
198     if (registerIndex >= registerNumber) {
199         HLOGE("registerIndex is %zu, max is %zu", registerIndex, registerNumber);
200         return false;
201     }
202     value = registers[registerIndex];
203     return true;
204 }
205 
GetArchTypeFromUname(const std::string & machine)206 ArchType GetArchTypeFromUname(const std::string &machine)
207 {
208     if (StringStartsWith(machine, "arm")) {
209         if (machine == "armv8l") {
210             // 32 bit elf run in 64 bit cpu
211             return ArchType::ARCH_ARM64;
212         }
213         return ArchType::ARCH_ARM;
214     } else if (machine == "aarch64") {
215         return ArchType::ARCH_ARM64;
216     } else if (machine == "x86_64") {
217         return ArchType::ARCH_X86_64;
218     } else if (machine == "x86" || machine == "i686") {
219         return ArchType::ARCH_X86;
220     } else {
221         HLOGE("unsupport machine %s", machine.c_str());
222         return ArchType::ARCH_UNKNOWN;
223     }
224 }
225 
GetArchTypeFromABI(bool abi32)226 ArchType GetArchTypeFromABI(bool abi32)
227 {
228     if (g_deviceArchType == ArchType::ARCH_UNKNOWN) {
229         g_deviceArchType = GetDeviceArch();
230     }
231     if (abi32) {
232         if (g_deviceArchType == ArchType::ARCH_ARM64) {
233             return ArchType::ARCH_ARM;
234         } else if (g_deviceArchType == ArchType::ARCH_X86_64) {
235             return ArchType::ARCH_X86;
236         }
237     }
238     return g_deviceArchType;
239 }
240 
SetDeviceArch(ArchType arch)241 ArchType SetDeviceArch(ArchType arch)
242 {
243     HLOGD("g_deviceArchType change to  %s", GetArchName(arch).c_str());
244     g_deviceArchType = arch;
245     return g_deviceArchType;
246 }
247 
GetDeviceArch()248 ArchType GetDeviceArch()
249 {
250 #if defined(is_mingw) && is_mingw
251     return g_deviceArchType;
252 #else
253     if (g_deviceArchType != ArchType::ARCH_UNKNOWN) {
254         return g_deviceArchType;
255     } else {
256         utsname systemName;
257         if ((uname(&systemName)) != 0) {
258             // fallback
259             g_deviceArchType = BUILD_ARCH_TYPE;
260         } else {
261             g_deviceArchType = GetArchTypeFromUname(systemName.machine);
262             HLOGD("machine arch is %s : %s", systemName.machine,
263                   GetArchName(g_deviceArchType).c_str());
264             if (g_deviceArchType == ArchType::ARCH_UNKNOWN) {
265                 g_deviceArchType = BUILD_ARCH_TYPE;
266             }
267         }
268     }
269     return g_deviceArchType;
270 #endif
271 }
272 
UpdateRegForABI(ArchType arch,u64 * regs)273 void UpdateRegForABI(ArchType arch, u64 *regs)
274 {
275     if (g_deviceArchType == ArchType::ARCH_ARM64 and arch == ArchType::ARCH_ARM) {
276         // arm in arm64
277         regs[PERF_REG_ARM_PC] = regs[PERF_REG_ARM64_PC];
278     }
279 }
280 } // namespace HiPerf
281 } // namespace Developtools
282 } // namespace OHOS
283