• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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