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