• 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__anonc0be73cd0111::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 uintptr_t g_stackMainStart = 0;
40 static uintptr_t g_stackMainEnd = 0;
41 }  // namespace
42 
GetMainStackRange(uintptr_t & stackBottom,uintptr_t & stackTop)43 static bool GetMainStackRange(uintptr_t& stackBottom, uintptr_t& stackTop)
44 {
45     stackBottom = g_stackMainStart;
46     stackTop = g_stackMainEnd;
47     return (stackBottom != 0 && stackTop != 0);
48 }
49 
GetSubStackRange(uintptr_t & stackBottom,uintptr_t & stackTop)50 static bool GetSubStackRange(uintptr_t& stackBottom, uintptr_t& stackTop)
51 {
52     bool ret = false;
53     pthread_attr_t tattr;
54     void* base = nullptr;
55     size_t size = 0;
56     if (pthread_getattr_np(pthread_self(), &tattr) != 0) {
57         return ret;
58     }
59     if (pthread_attr_getstack(&tattr, &base, &size) == 0) {
60         stackBottom = reinterpret_cast<uintptr_t>(base);
61         stackTop = reinterpret_cast<uintptr_t>(base) + size;
62         ret = true;
63     }
64     pthread_attr_destroy(&tattr);
65     return ret;
66 }
67 
GetSigAltStackRange(uintptr_t & stackBottom,uintptr_t & stackTop)68 static bool GetSigAltStackRange(uintptr_t& stackBottom, uintptr_t& stackTop)
69 {
70     bool ret = false;
71     stack_t altStack;
72     if (sigaltstack(nullptr, &altStack) != -1) {
73         if ((static_cast<uint32_t>(altStack.ss_flags) & SS_ONSTACK) != 0) {
74             stackBottom = reinterpret_cast<uintptr_t>(altStack.ss_sp);
75             stackTop = reinterpret_cast<uintptr_t>(altStack.ss_sp) + altStack.ss_size;
76             ret = true;
77         }
78     }
79     return ret;
80 }
81 
GetCoroutineStackRange(uintptr_t & stackBottom,uintptr_t & stackTop)82 static bool GetCoroutineStackRange(uintptr_t& stackBottom, uintptr_t& stackTop)
83 {
84     bool ret = false;
85     void* stackAddr = nullptr;
86     size_t coroutineStackSize = 0;
87     if (ffrt_get_current_coroutine_stack(&stackAddr, &coroutineStackSize)) {
88         stackBottom = reinterpret_cast<uintptr_t>(stackAddr);
89         stackTop = stackBottom + coroutineStackSize;
90         ret = true;
91     }
92     return ret;
93 }
94 
IsLegalSoName(const std::string & fileName)95 bool IsLegalSoName(const std::string &fileName)
96 {
97     if (fileName.front() == '[' || fileName.back() == ']' ||
98         std::strncmp(fileName.c_str(), "/dev/", sizeof("/dev/")) == 0 ||
99         std::strncmp(fileName.c_str(), "/memfd:", sizeof("/memfd:")) == 0 ||
100         std::strncmp(fileName.c_str(), "//anon", sizeof("//anon")) == 0) {
101         return false;
102     }
103     return true;
104 }
105 
GetStandardLibraryRange(std::string & line)106 static void GetStandardLibraryRange(std::string& line)
107 {
108     line.resize(strlen(line.c_str()));
109     std::vector<std::string> mapTokens = OHOS::Developtools::NativeDaemon::StringSplit(line, " ");
110     const std::string& soRange = mapTokens.front();
111     std::string& soName = mapTokens.back();
112     if (IsLegalSoName(soName)) {
113         std::string::size_type concatPos = soRange.find('-');
114         uint64_t soStart = static_cast<uint64_t>(strtoll(soRange.c_str(), nullptr, BASE_MAX));
115         uint64_t soEnd = static_cast<uint64_t>(strtoll(soRange.c_str() + concatPos + 1, nullptr, BASE_MAX));
116         auto [iter, isExit] = g_stdLib.try_emplace(soName, StandardLibrary(soStart, soEnd, soName));
117         if (!isExit) {
118             if (iter->second.soBegin_ > soStart) {
119                 iter->second.soBegin_ = soStart;
120             } else if (iter->second.soEnd_ < soEnd) {
121                 iter->second.soEnd_ = soEnd;
122             }
123         }
124     }
125 }
126 
GetRuntimeStackRange(const uintptr_t stackPtr,uintptr_t & stackBottom,uintptr_t & stackTop,bool isMainThread)127 bool GetRuntimeStackRange(const uintptr_t stackPtr, uintptr_t& stackBottom, uintptr_t& stackTop, bool isMainThread)
128 {
129     bool ret = false;
130     if (isMainThread) {
131         ret = GetMainStackRange(stackBottom, stackTop);
132     } else {
133         ret = GetSubStackRange(stackBottom, stackTop);
134         if (stackPtr < stackBottom || stackPtr >= stackTop) {
135             ret = GetSigAltStackRange(stackBottom, stackTop);
136         }
137     }
138     if (stackPtr < stackBottom || stackPtr >= stackTop) {
139         ret = GetCoroutineStackRange(stackBottom, stackTop);
140     }
141     return ret && (stackPtr >= stackBottom && stackPtr < stackTop);
142 }
143 
ParseSelfMaps(std::vector<std::pair<uint64_t,uint64_t>> & filterStaLibRange)144 bool ParseSelfMaps(std::vector<std::pair<uint64_t, uint64_t>>& filterStaLibRange)
145 {
146     FILE* fp = fopen("/proc/self/maps", "r");
147     bool ret = false;
148     if (fp == nullptr) {
149         return ret;
150     }
151     char mapInfo[256] = {0}; // 256: map info size
152     int pos = 0;
153     uint64_t begin = 0;
154     uint64_t end = 0;
155     uint64_t offset = 0;
156     char perms[5] = {0}; // 5:rwxp
157     while (fgets(mapInfo, sizeof(mapInfo), fp) != nullptr) {
158         if (strstr(mapInfo, "[stack]") != nullptr) {
159             if (sscanf_s(mapInfo, "%" SCNxPTR "-%" SCNxPTR " %4S %" SCNxPTR " %*X:%*X %*d%n", &begin, &end,
160                 &perms, sizeof(perms), &offset, &pos) != 4) { // 4:scan size
161                     continue;
162             }
163             g_stackMainStart = static_cast<uintptr_t>(begin);
164             g_stackMainEnd = static_cast<uintptr_t>(end);
165             ret = true;
166         } else if (strstr(mapInfo, "ld-musl") != nullptr || strstr(mapInfo, "libc++") != nullptr) {
167             std::string lineStr = mapInfo;
168             GetStandardLibraryRange(lineStr);
169         }
170     }
171     if (fclose(fp) != 0) {
172         printf("fclose failed.\n");
173     }
174     for (const auto& [soName, stdLibrary]: g_stdLib) {
175         filterStaLibRange.emplace_back(stdLibrary.soBegin_, stdLibrary.soEnd_);
176     }
177     return ret;
178 }
179 
ParseEvent(const std::string & filePath,std::vector<std::pair<uint64_t,uint64_t>> & filterStaLibRange,const NameData & curRawData)180 void ParseEvent(const std::string& filePath, std::vector<std::pair<uint64_t, uint64_t>>& filterStaLibRange,
181                 const NameData& curRawData)
182 {
183     if (curRawData.addr == nullptr) {
184         return;
185     }
186     uint64_t soStart = reinterpret_cast<uint64_t>(curRawData.addr);
187     uint64_t soEnd = soStart + static_cast<uint64_t>(curRawData.mallocSize);
188     auto [iter, success] = g_stdLib.try_emplace(filePath, StandardLibrary(soStart, soEnd, filePath));
189     if (!success) {
190         if (iter->second.soBegin_ > soStart) {
191             iter->second.soBegin_ = soStart;
192         } else if (iter->second.soEnd_ < soEnd) {
193             iter->second.soEnd_ = soEnd;
194         }
195         auto it = filterStaLibRange.rbegin();
196         for (; it != filterStaLibRange.rend(); ++it) {
197             if (it->first == iter->second.soBegin_) {
198                 break;
199             }
200         }
201         it->first = iter->second.soBegin_;
202         it->second = iter->second.soEnd_;
203     } else {
204         filterStaLibRange.emplace_back(iter->second.soBegin_, iter->second.soEnd_);
205     }
206 }
207