1 /*
2 * Copyright (c) 2024-2025 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 #include "dump_utils.h"
16
17 #include <vector>
18 #include <pthread.h>
19 #include "sys/ptrace.h"
20
21 #include "dfx_util.h"
22 #include "dfx_log.h"
23 #include "dfx_kernel_stack.h"
24 #include "dfx_frame_formatter.h"
25 #ifndef is_ohos_lite
26 #include "bundle_mgr_interface.h"
27 #include "bundle_mgr_proxy.h"
28 #include "if_system_ability_manager.h"
29 #include "iservice_registry.h"
30 #include "system_ability_definition.h"
31 #endif
32 namespace OHOS {
33 namespace HiviewDFX {
34 namespace {
35 // defined in alltypes.h
36 #define DFX_MUTEX_TYPE u.i[0]
37 #define DFX_MUTEX_OWNER u.vi[1]
38 typedef struct {
39 union {
40 int i[sizeof(long) == 8 ? 10 : 6];
41 volatile int vi[sizeof(long) == 8 ? 10 : 6];
42 volatile void *volatile p[sizeof(long) == 8 ? 5 : 6];
43 } u;
44 } DfxMutex;
45 }
ParseLockInfo(Unwinder & unwinder,int32_t vmPid,int32_t tid)46 bool DumpUtils::ParseLockInfo(Unwinder& unwinder, int32_t vmPid, int32_t tid)
47 {
48 #ifdef __aarch64__
49 std::vector<char> buffer(sizeof(pthread_mutex_t), 0);
50 if (unwinder.GetLockInfo(vmPid, buffer.data(), sizeof(pthread_mutex_t))) {
51 auto mutexInfo = reinterpret_cast<DfxMutex*>(buffer.data());
52 // only PTHREAD_MUTEX_ERRORCHECK(2) type lock contains lock holder thread-id
53 // the normal type only store EBUSY in owner section
54 int type = mutexInfo->DFX_MUTEX_TYPE;
55 uint32_t owner = static_cast<uint32_t>(mutexInfo->DFX_MUTEX_OWNER) & 0x3fffffff;
56 DFXLOGI("Thread(%{public}d) is waiting a lock with type %{public}d held by %{public}u", tid, type, owner);
57 return true;
58 }
59 return false;
60 #else
61 // not impl yet
62 return false;
63 #endif
64 }
65
IsLastValidFrame(const DfxFrame & frame)66 bool DumpUtils::IsLastValidFrame(const DfxFrame& frame)
67 {
68 static uintptr_t libcStartPc = 0;
69 static uintptr_t libffrtStartEntry = 0;
70 if (((libcStartPc != 0) && (frame.pc == libcStartPc)) ||
71 ((libffrtStartEntry != 0) && (frame.pc == libffrtStartEntry))) {
72 return true;
73 }
74
75 if (frame.mapName.find("ld-musl-aarch64.so.1") != std::string::npos &&
76 frame.funcName.find("start") != std::string::npos) {
77 libcStartPc = frame.pc;
78 return true;
79 }
80
81 if (frame.mapName.find("libffrt") != std::string::npos &&
82 frame.funcName.find("CoStartEntry") != std::string::npos) {
83 libffrtStartEntry = frame.pc;
84 return true;
85 }
86 return false;
87 }
88
GetThreadKernelStack(DfxThread & thread)89 void DumpUtils::GetThreadKernelStack(DfxThread& thread)
90 {
91 std::string threadKernelStack;
92 pid_t tid = thread.GetThreadInfo().nsTid;
93 DfxThreadStack threadStack;
94 if (DfxGetKernelStack(tid, threadKernelStack) == 0 && FormatThreadKernelStack(threadKernelStack, threadStack)) {
95 DFXLOGW("Failed to get tid(%{public}d) user stack, try kernel", tid);
96 if (IsBetaVersion()) {
97 DFXLOGI("%{public}s", threadKernelStack.c_str());
98 }
99 thread.SetParseSymbolNecessity(false);
100 thread.SetFrames(threadStack.frames);
101 }
102 }
103
ReadStringByPtrace(pid_t tid,uintptr_t startAddr,size_t maxLen)104 std::string DumpUtils::ReadStringByPtrace(pid_t tid, uintptr_t startAddr, size_t maxLen)
105 {
106 constexpr size_t maxReadLen = 1024 * 1024 * 1; // 1M
107 if (maxLen == 0 || maxLen > maxReadLen) {
108 DFXLOGE("maxLen(%{public}zu) is invalid value.", maxLen);
109 return "";
110 }
111 size_t bufLen = (maxLen + sizeof(long) - 1) / sizeof(long);
112 std::vector<long> buffer(bufLen, 0);
113 for (size_t i = 0; i < bufLen; i++) {
114 long ret = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(startAddr + sizeof(long) * i), nullptr);
115 if (ret == -1) {
116 DFXLOGE("read target mem by ptrace failed, errno(%{public}s).", strerror(errno));
117 break;
118 }
119 buffer[i] = ret;
120 if (ret == 0) {
121 break;
122 }
123 }
124 char* val = reinterpret_cast<char*>(buffer.data());
125 val[maxLen - 1] = '\0';
126 return std::string(val);
127 }
128
GetStackTrace(const std::vector<DfxFrame> & frames)129 std::string DumpUtils::GetStackTrace(const std::vector<DfxFrame>& frames)
130 {
131 std::string stackTrace;
132 for (const auto& frame : frames) {
133 stackTrace += DfxFrameFormatter::GetFrameStr(frame);
134 #if defined(__aarch64__)
135 if (IsLastValidFrame(frame)) {
136 break;
137 }
138 #endif
139 }
140 return stackTrace;
141 }
142
ReadTargetMemory(pid_t tid,uintptr_t addr,uintptr_t & value)143 bool DumpUtils::ReadTargetMemory(pid_t tid, uintptr_t addr, uintptr_t &value)
144 {
145 uintptr_t targetAddr = addr;
146 auto retAddr = reinterpret_cast<long*>(&value);
147 for (size_t i = 0; i < sizeof(uintptr_t) / sizeof(long); i++) {
148 *retAddr = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(targetAddr), nullptr);
149 if (*retAddr == -1) {
150 return false;
151 }
152 targetAddr += sizeof(long);
153 retAddr += 1;
154 }
155 return true;
156 }
157
158 #ifndef is_ohos_lite
GetBundleManager()159 sptr<AppExecFwk::IBundleMgr> GetBundleManager()
160 {
161 auto systemManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
162 if (!systemManager) {
163 DFXLOGE("Get system ability manager failed");
164 return nullptr;
165 }
166 auto remoteObject = systemManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
167 if (!remoteObject) {
168 DFXLOGE("Get system ability failed");
169 return nullptr;
170 }
171 sptr<AppExecFwk::IBundleMgr> bundleMgrProxy = iface_cast<AppExecFwk::IBundleMgr>(remoteObject);
172 return bundleMgrProxy;
173 }
174 #endif
175
GetSelfBundleName()176 std::string DumpUtils::GetSelfBundleName()
177 {
178 #ifndef is_ohos_lite
179 static std::string bundleName;
180 if (!bundleName.empty()) {
181 return bundleName;
182 }
183 auto bundleInstance = GetBundleManager();
184 if (bundleInstance == nullptr) {
185 DFXLOGE("bundleInstance is nullptr");
186 return "";
187 }
188 AppExecFwk::BundleInfo bundleInfo;
189 auto ret = bundleInstance->GetBundleInfoForSelf(0, bundleInfo);
190 if (ret != ERR_OK) {
191 DFXLOGE("GetBundleInfoForSelf failed! ret = %{public}d", ret);
192 return "";
193 }
194 bundleName = bundleInfo.name;
195 return bundleName;
196 #endif
197 return "";
198 }
199
InfoCrashUnwindResult(const ProcessDumpRequest & request,bool isUnwindSucc)200 void DumpUtils::InfoCrashUnwindResult(const ProcessDumpRequest& request, bool isUnwindSucc)
201 {
202 if (!isUnwindSucc) {
203 return;
204 }
205 if (ptrace(PTRACE_POKEDATA, request.nsPid, reinterpret_cast<void*>(request.unwindResultAddr),
206 CRASH_UNWIND_SUCCESS_FLAG) < 0) {
207 DFXLOGE("pok unwind success flag to nsPid %{public}d fail %{public}s", request.nsPid, strerror(errno));
208 }
209 }
210 } // namespace HiviewDFX
211 } // namespace OHOS
212