• 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 #include "debug_logger.h"
22 
23 
24 namespace OHOS {
25 namespace Developtools {
26 namespace HiPerf {
27 static ArchType g_deviceArchType = ArchType::ARCH_UNKNOWN;
28 // order is IP , SP for ut
29 static const std::map<size_t, const std::string> PERF_REG_NAME_MAP = {
30 #if defined(target_cpu_x86_64)
31     {PERF_REG_X86_IP, "PERF_REG_X86_IP"},
32     {PERF_REG_X86_SP, "PERF_REG_X86_SP"},
33 #elif defined(target_cpu_arm)
34     {PERF_REG_ARM_PC, "PERF_REG_ARM_PC"},
35     {PERF_REG_ARM_SP, "PERF_REG_ARM_SP"},
36 #elif defined(target_cpu_arm64)
37     {PERF_REG_ARM64_PC, "PERF_REG_ARM64_PC"},
38     {PERF_REG_ARM64_SP, "PERF_REG_ARM64_SP"},
39 #endif
40 };
41 
42 // these copy from kerne uapi perf_regs.h
GetSupportedRegMask(ArchType arch)43 uint64_t GetSupportedRegMask(ArchType arch)
44 {
45     uint64_t result = 0;
46     switch (arch) {
47         case ArchType::ARCH_X86:
48             result = ((1ULL << PERF_REG_X86_32_MAX) - 1);
49             break;
50         case ArchType::ARCH_X86_64:
51             result = ((1ULL << PERF_REG_X86_64_MAX) - 1);
52             result &= ~((1ULL << PERF_REG_X86_DS) | (1ULL << PERF_REG_X86_ES) |
53                         (1ULL << PERF_REG_X86_FS) | (1ULL << PERF_REG_X86_GS));
54             break;
55         case ArchType::ARCH_ARM:
56             result = ((1ULL << PERF_REG_ARM_MAX) - 1);
57             break;
58         case ArchType::ARCH_ARM64:
59             result = ((1ULL << PERF_REG_ARM64_MAX) - 1);
60             break;
61         default:
62             result = std::numeric_limits<uint64_t>::max();
63             HLOGE("unsupport arch %u", arch);
64             break;
65     }
66     return result;
67 }
68 
UpdatePerfContext(uint64_t addr,perf_callchain_context & perfCallchainContext)69 const std::string UpdatePerfContext(uint64_t addr, perf_callchain_context &perfCallchainContext)
70 {
71     if (PERF_CONTEXT_NAME.count(addr) != 0) {
72         perfCallchainContext = static_cast<perf_callchain_context>(addr);
73         return StringPrintf("%s: %" PRIx64 "", PERF_CONTEXT_NAME.at(addr).c_str(), addr);
74     } else {
75         perfCallchainContext = PERF_CONTEXT_MAX;
76         return StringPrintf("unknow context: %" PRIx64 "", addr);
77     }
78 }
79 
GetArchName(ArchType arch)80 const std::string GetArchName(ArchType arch)
81 {
82     switch (arch) {
83         case ArchType::ARCH_X86:
84             return "X86_32";
85         case ArchType::ARCH_X86_64:
86             return "X86_64";
87         case ArchType::ARCH_ARM:
88             return "ARM";
89         case ArchType::ARCH_ARM64:
90             return "ARM64";
91         default:
92             return "Unsupport";
93     }
94 }
95 
RegisterGetIP(ArchType arch)96 size_t RegisterGetIP(ArchType arch)
97 {
98     switch (arch) {
99         case ArchType::ARCH_X86:
100         case ArchType::ARCH_X86_64:
101             return PERF_REG_X86_IP;
102         case ArchType::ARCH_ARM:
103             return PERF_REG_ARM_PC;
104         case ArchType::ARCH_ARM64:
105             return PERF_REG_ARM64_PC;
106         default:
107             return std::numeric_limits<size_t>::max();
108     }
109 }
110 
RegisterGetSP(ArchType arch)111 size_t RegisterGetSP(ArchType arch)
112 {
113     switch (arch) {
114         case ArchType::ARCH_X86:
115         case ArchType::ARCH_X86_64:
116             return PERF_REG_X86_SP;
117         case ArchType::ARCH_ARM:
118             return PERF_REG_ARM_SP;
119         case ArchType::ARCH_ARM64:
120             return PERF_REG_ARM64_SP;
121         default:
122             return std::numeric_limits<size_t>::max();
123     }
124 }
125 
RegisterGetName(size_t registerIndex)126 const std::string RegisterGetName(size_t registerIndex)
127 {
128     std::string name;
129     name.append("PerfReg[");
130     name.append(std::to_string(registerIndex));
131     if (PERF_REG_NAME_MAP.count(registerIndex) > 0) {
132         name.append(":");
133         name.append(PERF_REG_NAME_MAP.at(registerIndex));
134     }
135     name.append("]");
136     return name;
137 }
138 
RegisterGetValue(uint64_t & value,const u64 registers[],const size_t registerIndex,const size_t registerNumber)139 bool RegisterGetValue(uint64_t &value, const u64 registers[], const size_t registerIndex,
140                       const size_t registerNumber)
141 {
142     if (registerIndex >= registerNumber) {
143         HLOGE("registerIndex is %zu, max is %zu", registerIndex, registerNumber);
144         return false;
145     }
146     value = registers[registerIndex];
147     return true;
148 }
149 
GetArchTypeFromUname(const std::string & machine)150 ArchType GetArchTypeFromUname(const std::string &machine)
151 {
152     if (StringStartsWith(machine, "arm")) {
153         if (machine == "armv8l") {
154             // 32 bit elf run in 64 bit cpu
155             return ArchType::ARCH_ARM64;
156         }
157         return ArchType::ARCH_ARM;
158     } else if (machine == "aarch64") {
159         return ArchType::ARCH_ARM64;
160     } else if (machine == "x86_64") {
161         return ArchType::ARCH_X86_64;
162     } else if (machine == "x86" || machine == "i686") {
163         return ArchType::ARCH_X86;
164     } else {
165         HLOGE("unsupport machine %s", machine.c_str());
166         return ArchType::ARCH_UNKNOWN;
167     }
168 }
169 
GetArchTypeFromABI(bool abi32)170 ArchType GetArchTypeFromABI(bool abi32)
171 {
172     if (g_deviceArchType == ArchType::ARCH_UNKNOWN) {
173         g_deviceArchType = GetDeviceArch();
174     }
175     if (abi32) {
176         if (g_deviceArchType == ArchType::ARCH_ARM64) {
177             return ArchType::ARCH_ARM;
178         } else if (g_deviceArchType == ArchType::ARCH_X86_64) {
179             return ArchType::ARCH_X86;
180         }
181     }
182     return g_deviceArchType;
183 }
184 
SetDeviceArch(ArchType arch)185 ArchType SetDeviceArch(ArchType arch)
186 {
187     HLOGD("g_deviceArchType change to  %s", GetArchName(arch).c_str());
188     g_deviceArchType = arch;
189     return g_deviceArchType;
190 }
191 
GetDeviceArch()192 ArchType GetDeviceArch()
193 {
194 #if defined(is_mingw) && is_mingw
195     return g_deviceArchType;
196 #else
197     if (g_deviceArchType != ArchType::ARCH_UNKNOWN) {
198         return g_deviceArchType;
199     } else {
200         utsname systemName;
201         if ((uname(&systemName)) != 0) {
202             // fallback
203             g_deviceArchType = BUILD_ARCH_TYPE;
204         } else {
205             g_deviceArchType = GetArchTypeFromUname(systemName.machine);
206             HLOGD("machine arch is %s : %s", systemName.machine,
207                   GetArchName(g_deviceArchType).c_str());
208             if (g_deviceArchType == ArchType::ARCH_UNKNOWN) {
209                 g_deviceArchType = BUILD_ARCH_TYPE;
210             }
211         }
212     }
213     return g_deviceArchType;
214 #endif
215 }
216 
UpdateRegForABI(ArchType arch,u64 * regs)217 void UpdateRegForABI(ArchType arch, u64 *regs)
218 {
219     if (g_deviceArchType == ArchType::ARCH_ARM64 && arch == ArchType::ARCH_ARM) {
220         // arm in arm64
221         regs[PERF_REG_ARM_PC] = regs[PERF_REG_ARM64_PC];
222     }
223 }
224 } // namespace HiPerf
225 } // namespace Developtools
226 } // namespace OHOS
227