• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #include "runtime_stack_range.h"
17 
18 #include <cassert>
19 #include <csignal>
20 #include <cstdio>
21 #include <cstring>
22 #include <iostream>
23 #include <pthread.h>
24 #include <string>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include "get_thread_id.h"
28 
29 namespace {
30 constexpr int BASE_MIN = 2;
31 constexpr int BASE_CENTRE = 10;
32 constexpr int BASE_MAX = 16;
33 
34 struct StackScope {
35     const char* start;
36     const char* end;
37 };
38 static StackScope g_mainStack;
39 }  // namespace
40 
GetThreadRuntimeStackRange(const char ** start,const char ** end)41 static void GetThreadRuntimeStackRange(const char** start, const char** end)
42 {
43     *start = nullptr;
44     *end = nullptr;
45     pthread_t tid = pthread_self();
46     pthread_attr_t attr;
47     if (pthread_getattr_np(tid, &attr) == 0) {
48         char* stackAddr = nullptr;
49         size_t stackSize;
50         if (pthread_attr_getstack(&attr, reinterpret_cast<void**>(const_cast<char**>(start)), &stackSize) == 0) {
51             *end = *start + stackSize;
52         }
53         pthread_attr_destroy(&attr);
54     }
55 }
56 
CvtStrToInt(const char * str,int base)57 static long long CvtStrToInt(const char* str, int base)
58 {
59     long long result = 0;
60     if (base >= BASE_MIN && base <= BASE_CENTRE) {
61         while (*str) {
62             if (*str >= '0' && *str <= '0' + base - 1) {
63                 result = result * base + static_cast<long long>((*str) - '0');
64             } else {
65                 break;
66             }
67             ++str;
68         }
69     } else if (base > BASE_CENTRE && base <= BASE_MAX) {
70         while (*str) {
71             if (*str >= '0' && *str <= '0' + base - 1) {
72                 result = result * base + static_cast<long long>(*str) - '0';
73             } else if (*str >= 'a' && *str <= 'a' + base - 0x0a - 1) {
74                 result = result * base + static_cast<long long>(*str) - 'a' + 0x0a;
75             } else if (*str >= 'A' && *str <= 'A' + base - 0x0a - 1) {
76                 result = result * base + static_cast<long long>(*str) - 'A' + 0x0a;
77             } else {
78                 break;
79             }
80             ++str;
81         }
82     } else {
83         assert(0);
84         result = 0;
85     }
86     return result;
87 }
88 
IsEmptyString(const std::string & str)89 static int IsEmptyString(const std::string& str)
90 {
91     size_t idx = 0;
92     size_t size = str.size();
93     while (idx < size) {
94         if (!isspace(static_cast<unsigned char>(str[idx])) && str[idx] != 0) {
95             return 0;
96         }
97         ++idx;
98     }
99     return 1;
100 }
101 
GetAnUnlimitedLine(FILE * fp,std::string & buf)102 static void GetAnUnlimitedLine(FILE* fp, std::string& buf)
103 {
104     if (!fp) {
105         buf.resize(0);
106         return;
107     }
108     char* retLine = nullptr;
109     if (buf.size() == 0) {
110         buf.resize(INIT_LINE_SIZE);
111     }
112 
113     int offset = 0;
114     int length = 0;
115     do {
116         if (offset + length >= static_cast<int>(buf.size())) {
117             buf.resize(buf.size() + INC_LINE_SIZE);
118         }
119         retLine = fgets(&buf[0] + offset, buf.size() - offset, fp);
120         if (retLine == nullptr) {
121             break;
122         }
123         length = static_cast<int>(strlen(&buf[0] + offset));
124         if (offset + length - 1 >= 0 && buf[offset + length - 1] == '\n') {
125             break;
126         }
127         offset += length;
128     } while (1);
129 }
130 
GetMainThreadRuntimeStackRange()131 void GetMainThreadRuntimeStackRange()
132 {
133     std::string line;
134     FILE* fp = fopen("/proc/self/maps", "re");
135     if (fp == nullptr) {
136         return;
137     }
138     while (!feof(fp)) {
139         GetAnUnlimitedLine(fp, line);
140         if (IsEmptyString(line)) {
141             continue;
142         }
143         std::string::size_type pos = line.find("[stack]");
144         if (pos != static_cast<std::string::size_type>(-1)) {
145             std::string::size_type concatPos = line.find('-');
146             if (concatPos == static_cast<std::string::size_type>(-1)) {
147                 continue;
148             }
149             g_mainStack.start = reinterpret_cast<char*>(CvtStrToInt(line.c_str(), BASE_MAX));
150             g_mainStack.end = reinterpret_cast<char*>(CvtStrToInt(line.c_str() + concatPos + 1, BASE_MAX));
151 
152             break;
153         }
154     }
155     if (fclose(fp) != 0) {
156         printf("fclose failed.\n");
157     }
158 }
159 
IfContained(const char * start,const char * end,const char * ptr)160 static bool IfContained(const char* start, const char* end, const char* ptr)
161 {
162     bool ret = (ptr >= start && ptr < end);
163     return ret;
164 }
165 
GetRuntimeSigalAltStackRange(char ** start,char ** end)166 static void GetRuntimeSigalAltStackRange(char** start, char** end)
167 {
168     *start = nullptr;
169     *end = nullptr;
170 
171     stack_t altStack;
172 
173     if (sigaltstack(nullptr, &altStack) != -1) {
174         if ((altStack.ss_flags & SS_ONSTACK) != 0) {
175             *start = static_cast<char*>(altStack.ss_sp);
176             *end = static_cast<char*>(altStack.ss_sp) + altStack.ss_size;
177         }
178     }
179 }
180 
IfSubThread(pid_t pid,pid_t tid)181 static bool IfSubThread(pid_t pid, pid_t tid)
182 {
183     return pid != tid;
184 }
185 
GetRuntimeStackEnd(const char * stackptr,const char ** end,pid_t pid,pid_t tid)186 void GetRuntimeStackEnd(const char* stackptr, const char** end, pid_t pid, pid_t tid)
187 {
188     const char* start = nullptr;
189     *end = nullptr;
190     bool isSubThread = IfSubThread(pid, tid);
191     if (isSubThread) {
192         GetThreadRuntimeStackRange(&start, end);
193     } else {
194         start = g_mainStack.start;
195         *end = g_mainStack.end;
196     }
197     if (!IfContained(start, *end, stackptr)) {
198         char *sigStackStart = nullptr;
199         char *sigStackEnd = nullptr;
200         GetRuntimeSigalAltStackRange(&sigStackStart, &sigStackEnd);
201         if (IfContained(sigStackStart, sigStackEnd, stackptr)) {
202             *end = sigStackEnd;
203         } else if (!(!isSubThread && stackptr < *end)) {
204             *end = nullptr;
205         }
206     }
207 }
208