• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
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 "runtime_stack_range.h"
17 
18 #include <csignal>
19 #include <cstring>
20 #include <map>
21 #include <sys/types.h>
22 #include "c/executor_task.h"
23 #include "get_thread_id.h"
24 #include "utilities.h"
25 
26 namespace {
27 constexpr int BASE_MAX = 16;
28 
29 struct StandardLibrary {
StandardLibrary__anonc3ddc7af0111::StandardLibrary30     StandardLibrary(uint64_t begin, uint64_t end, const std::string& name)
31         : soBegin_(begin), soEnd_(end), name_(name)
32     {}
33     uint64_t soBegin_;
34     uint64_t soEnd_;
35     std::string name_;
36 };
37 
38 static std::map<std::string, StandardLibrary> g_stdLib;
39 static std::map<std::string, StandardLibrary> g_targetLib;
40 static uintptr_t g_stackMainStart = 0;
41 static uintptr_t g_stackMainEnd = 0;
42 }  // namespace
43 
GetMainStackRange(uintptr_t & stackBottom,uintptr_t & stackTop)44 static bool GetMainStackRange(uintptr_t& stackBottom, uintptr_t& stackTop)
45 {
46     stackBottom = g_stackMainStart;
47     stackTop = g_stackMainEnd;
48     return (stackBottom != 0 && stackTop != 0);
49 }
50 
GetSubStackRange(uintptr_t & stackBottom,uintptr_t & stackTop)51 static bool GetSubStackRange(uintptr_t& stackBottom, uintptr_t& stackTop)
52 {
53     bool ret = false;
54     pthread_attr_t tattr;
55     void* base = nullptr;
56     size_t size = 0;
57     if (pthread_getattr_np(pthread_self(), &tattr) != 0) {
58         return ret;
59     }
60     if (pthread_attr_getstack(&tattr, &base, &size) == 0) {
61         stackBottom = reinterpret_cast<uintptr_t>(base);
62         stackTop = reinterpret_cast<uintptr_t>(base) + size;
63         ret = true;
64     }
65     pthread_attr_destroy(&tattr);
66     return ret;
67 }
68 
GetSigAltStackRange(uintptr_t & stackBottom,uintptr_t & stackTop)69 static bool GetSigAltStackRange(uintptr_t& stackBottom, uintptr_t& stackTop)
70 {
71     bool ret = false;
72     stack_t altStack;
73     if (sigaltstack(nullptr, &altStack) != -1) {
74         if ((static_cast<uint32_t>(altStack.ss_flags) & SS_ONSTACK) != 0) {
75             stackBottom = reinterpret_cast<uintptr_t>(altStack.ss_sp);
76             stackTop = reinterpret_cast<uintptr_t>(altStack.ss_sp) + altStack.ss_size;
77             ret = true;
78         }
79     }
80     return ret;
81 }
82 
GetCoroutineStackRange(uintptr_t & stackBottom,uintptr_t & stackTop)83 static bool GetCoroutineStackRange(uintptr_t& stackBottom, uintptr_t& stackTop)
84 {
85     bool ret = false;
86     void* stackAddr = nullptr;
87     size_t coroutineStackSize = 0;
88     if (ffrt_get_current_coroutine_stack(&stackAddr, &coroutineStackSize)) {
89         stackBottom = reinterpret_cast<uintptr_t>(stackAddr);
90         stackTop = stackBottom + coroutineStackSize;
91         ret = true;
92     }
93     return ret;
94 }
95 
IsLegalSoName(const char * fileName)96 bool IsLegalSoName(const char *fileName)
97 {
98     if (fileName == nullptr) {
99         return false;
100     }
101     size_t fileNameLength = strlen(fileName);
102     if (fileNameLength == 0) {
103         return false;
104     }
105     if (fileName[0] == '[' || fileName[strlen(fileName) - 1] == ']' ||
106         std::strncmp(fileName, "/dev/", sizeof("/dev/") - 1) == 0 ||
107         std::strncmp(fileName, "/memfd:", sizeof("/memfd:") - 1) == 0 ||
108         std::strncmp(fileName, "//anon", sizeof("//anon") - 1) == 0) {
109         return false;
110     }
111     return true;
112 }
113 
GetStandardLibraryRange(std::string & line,bool targeted=false)114 static void GetStandardLibraryRange(std::string& line, bool targeted = false)
115 {
116     line.resize(strlen(line.c_str()));
117     std::vector<std::string> mapTokens = OHOS::Developtools::NativeDaemon::StringSplit(line, " ");
118     const std::string& soRange = mapTokens.front();
119     std::string& soName = mapTokens.back();
120     if (IsLegalSoName(soName.c_str())) {
121         std::string::size_type concatPos = soRange.find('-');
122         uint64_t soStart = static_cast<uint64_t>(strtoll(soRange.c_str(), nullptr, BASE_MAX));
123         uint64_t soEnd = static_cast<uint64_t>(strtoll(soRange.c_str() + concatPos + 1, nullptr, BASE_MAX));
124         auto iter = g_stdLib.begin();
125         bool isExit = false;
126         if (targeted) {
127             std::tie(iter, isExit) = g_targetLib.try_emplace(soName, StandardLibrary(soStart, soEnd, soName));
128         } else {
129             std::tie(iter, isExit) = g_stdLib.try_emplace(soName, StandardLibrary(soStart, soEnd, soName));
130         }
131         if (!isExit) {
132             if (iter->second.soBegin_ > soStart) {
133                 iter->second.soBegin_ = soStart;
134             } else if (iter->second.soEnd_ < soEnd) {
135                 iter->second.soEnd_ = soEnd;
136             }
137         }
138     }
139 }
140 
ParseTargetedMaps(std::atomic<Range> & targetedRange,std::string targetedLib)141 bool ParseTargetedMaps(std::atomic<Range>& targetedRange, std::string targetedLib)
142 {
143     FILE* fp = fopen("/proc/self/maps", "r");
144     bool ret = false;
145     if (fp == nullptr) {
146         return ret;
147     }
148     char mapInfo[256] = {0}; // 256: map info size
149     int pos = 0;
150     uint64_t begin = 0;
151     uint64_t end = 0;
152     uint64_t offset = 0;
153     char perms[5] = {0}; // 5:rwxp
154     while (fgets(mapInfo, sizeof(mapInfo), fp) != nullptr) {
155         if (strstr(mapInfo, targetedLib.c_str()) != nullptr) {
156             std::string lineStr = mapInfo;
157             GetStandardLibraryRange(lineStr, true);
158             ret = true;
159         }
160     }
161     if (fclose(fp) != 0) {
162         printf("fclose failed.\n");
163     }
164     auto range = targetedRange.load();
165     for (const auto& [soName, stdLibrary]: g_targetLib) {
166         range.start = stdLibrary.soBegin_;
167         range.end = stdLibrary.soEnd_;
168     }
169     targetedRange.store(range);
170     return ret;
171 }
172 
GetRuntimeStackRange(const uintptr_t stackPtr,uintptr_t & stackBottom,uintptr_t & stackTop,bool isMainThread)173 bool GetRuntimeStackRange(const uintptr_t stackPtr, uintptr_t& stackBottom, uintptr_t& stackTop, bool isMainThread)
174 {
175     bool ret = false;
176     if (isMainThread) {
177         ret = GetMainStackRange(stackBottom, stackTop);
178     } else {
179         ret = GetSubStackRange(stackBottom, stackTop);
180         if (stackPtr < stackBottom || stackPtr >= stackTop) {
181             ret = GetSigAltStackRange(stackBottom, stackTop);
182         }
183     }
184     if (stackPtr < stackBottom || stackPtr >= stackTop) {
185         ret = GetCoroutineStackRange(stackBottom, stackTop);
186     }
187     return ret && (stackPtr >= stackBottom && stackPtr < stackTop);
188 }
189 
ParseSelfMaps(std::vector<std::pair<uint64_t,uint64_t>> & filterStaLibRange)190 bool ParseSelfMaps(std::vector<std::pair<uint64_t, uint64_t>>& filterStaLibRange)
191 {
192     FILE* fp = fopen("/proc/self/maps", "r");
193     bool ret = false;
194     if (fp == nullptr) {
195         return ret;
196     }
197     char mapInfo[256] = {0}; // 256: map info size
198     int pos = 0;
199     uint64_t begin = 0;
200     uint64_t end = 0;
201     uint64_t offset = 0;
202     char perms[5] = {0}; // 5:rwxp
203     while (fgets(mapInfo, sizeof(mapInfo), fp) != nullptr) {
204         if (strstr(mapInfo, "[stack]") != nullptr) {
205             if (sscanf_s(mapInfo, "%" SCNxPTR "-%" SCNxPTR " %4S %" SCNxPTR " %*X:%*X %*d%n", &begin, &end,
206                 &perms, sizeof(perms), &offset, &pos) != 4) { // 4:scan size
207                     continue;
208             }
209             g_stackMainStart = static_cast<uintptr_t>(begin);
210             g_stackMainEnd = static_cast<uintptr_t>(end);
211             ret = true;
212         } else if (strstr(mapInfo, "ld-musl") != nullptr || strstr(mapInfo, "libc++") != nullptr) {
213             std::string lineStr = mapInfo;
214             GetStandardLibraryRange(lineStr);
215         }
216     }
217     if (fclose(fp) != 0) {
218         printf("fclose failed.\n");
219     }
220     for (const auto& [soName, stdLibrary]: g_stdLib) {
221         filterStaLibRange.emplace_back(stdLibrary.soBegin_, stdLibrary.soEnd_);
222     }
223     return ret;
224 }
225 
ParseEvent(const std::string & filePath,std::vector<std::pair<uint64_t,uint64_t>> & filterStaLibRange,const NameData & curRawData)226 void ParseEvent(const std::string& filePath, std::vector<std::pair<uint64_t, uint64_t>>& filterStaLibRange,
227                 const NameData& curRawData)
228 {
229     if (curRawData.addr == nullptr) {
230         return;
231     }
232     uint64_t soStart = reinterpret_cast<uint64_t>(curRawData.addr);
233     uint64_t soEnd = soStart + static_cast<uint64_t>(curRawData.mallocSize);
234     auto [iter, success] = g_stdLib.try_emplace(filePath, StandardLibrary(soStart, soEnd, filePath));
235     if (!success) {
236         if (iter->second.soBegin_ > soStart) {
237             iter->second.soBegin_ = soStart;
238         } else if (iter->second.soEnd_ < soEnd) {
239             iter->second.soEnd_ = soEnd;
240         }
241         auto it = filterStaLibRange.rbegin();
242         for (; it != filterStaLibRange.rend(); ++it) {
243             if (it->first == iter->second.soBegin_) {
244                 break;
245             }
246         }
247         it->first = iter->second.soBegin_;
248         it->second = iter->second.soEnd_;
249     } else {
250         filterStaLibRange.emplace_back(iter->second.soBegin_, iter->second.soEnd_);
251     }
252 }
253