106f6ba60Sopenharmony_ci/*
206f6ba60Sopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
306f6ba60Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
406f6ba60Sopenharmony_ci * you may not use this file except in compliance with the License.
506f6ba60Sopenharmony_ci * You may obtain a copy of the License at
606f6ba60Sopenharmony_ci *
706f6ba60Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
806f6ba60Sopenharmony_ci *
906f6ba60Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1006f6ba60Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1106f6ba60Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1206f6ba60Sopenharmony_ci * See the License for the specific language governing permissions and
1306f6ba60Sopenharmony_ci * limitations under the License.
1406f6ba60Sopenharmony_ci */
1506f6ba60Sopenharmony_ci
1606f6ba60Sopenharmony_ci#include "runtime_stack_range.h"
1706f6ba60Sopenharmony_ci
1806f6ba60Sopenharmony_ci#include <csignal>
1906f6ba60Sopenharmony_ci#include <cstring>
2006f6ba60Sopenharmony_ci#include <map>
2106f6ba60Sopenharmony_ci#include <sys/types.h>
2206f6ba60Sopenharmony_ci#include "get_thread_id.h"
2306f6ba60Sopenharmony_ci#include "utilities.h"
2406f6ba60Sopenharmony_ci
2506f6ba60Sopenharmony_cinamespace {
2606f6ba60Sopenharmony_ciconstexpr int BASE_MIN = 2;
2706f6ba60Sopenharmony_ciconstexpr int BASE_CENTRE = 10;
2806f6ba60Sopenharmony_ciconstexpr int BASE_MAX = 16;
2906f6ba60Sopenharmony_ci
3006f6ba60Sopenharmony_cistruct StackScope {
3106f6ba60Sopenharmony_ci    const char* start;
3206f6ba60Sopenharmony_ci    const char* end;
3306f6ba60Sopenharmony_ci};
3406f6ba60Sopenharmony_cistruct StandardLibrary {
3506f6ba60Sopenharmony_ci    StandardLibrary(uint64_t begin, uint64_t end, const std::string& name)
3606f6ba60Sopenharmony_ci        : soBegin_(begin), soEnd_(end), name_(name)
3706f6ba60Sopenharmony_ci    {}
3806f6ba60Sopenharmony_ci    uint64_t soBegin_;
3906f6ba60Sopenharmony_ci    uint64_t soEnd_;
4006f6ba60Sopenharmony_ci    std::string name_;
4106f6ba60Sopenharmony_ci};
4206f6ba60Sopenharmony_ci
4306f6ba60Sopenharmony_cistatic StackScope g_mainStack;
4406f6ba60Sopenharmony_cistatic std::map<std::string, StandardLibrary> g_stdLib;
4506f6ba60Sopenharmony_ci}  // namespace
4606f6ba60Sopenharmony_ci
4706f6ba60Sopenharmony_cistatic void GetThreadRuntimeStackRange(const char** start, const char** end)
4806f6ba60Sopenharmony_ci{
4906f6ba60Sopenharmony_ci    *start = nullptr;
5006f6ba60Sopenharmony_ci    *end = nullptr;
5106f6ba60Sopenharmony_ci    pthread_t tid = pthread_self();
5206f6ba60Sopenharmony_ci    pthread_attr_t attr;
5306f6ba60Sopenharmony_ci    if (pthread_getattr_np(tid, &attr) == 0) {
5406f6ba60Sopenharmony_ci        size_t stackSize;
5506f6ba60Sopenharmony_ci        if (pthread_attr_getstack(&attr, reinterpret_cast<void**>(const_cast<char**>(start)), &stackSize) == 0) {
5606f6ba60Sopenharmony_ci            *end = *start + stackSize;
5706f6ba60Sopenharmony_ci        }
5806f6ba60Sopenharmony_ci        pthread_attr_destroy(&attr);
5906f6ba60Sopenharmony_ci    }
6006f6ba60Sopenharmony_ci}
6106f6ba60Sopenharmony_ci
6206f6ba60Sopenharmony_cistatic long long CvtStrToInt(const char* str, int base)
6306f6ba60Sopenharmony_ci{
6406f6ba60Sopenharmony_ci    long long result = 0;
6506f6ba60Sopenharmony_ci    if (base >= BASE_MIN && base <= BASE_CENTRE) {
6606f6ba60Sopenharmony_ci        while (*str) {
6706f6ba60Sopenharmony_ci            if (*str >= '0' && *str <= '0' + base - 1) {
6806f6ba60Sopenharmony_ci                result = result * base + static_cast<long long>((*str) - '0');
6906f6ba60Sopenharmony_ci            } else {
7006f6ba60Sopenharmony_ci                break;
7106f6ba60Sopenharmony_ci            }
7206f6ba60Sopenharmony_ci            ++str;
7306f6ba60Sopenharmony_ci        }
7406f6ba60Sopenharmony_ci    } else if (base > BASE_CENTRE && base <= BASE_MAX) {
7506f6ba60Sopenharmony_ci        while (*str) {
7606f6ba60Sopenharmony_ci            if (*str >= '0' && *str <= '0' + base - 1) {
7706f6ba60Sopenharmony_ci                result = result * base + static_cast<long long>(*str) - '0';
7806f6ba60Sopenharmony_ci            } else if (*str >= 'a' && *str <= 'a' + base - 0x0a - 1) {
7906f6ba60Sopenharmony_ci                result = result * base + static_cast<long long>(*str) - 'a' + 0x0a;
8006f6ba60Sopenharmony_ci            } else if (*str >= 'A' && *str <= 'A' + base - 0x0a - 1) {
8106f6ba60Sopenharmony_ci                result = result * base + static_cast<long long>(*str) - 'A' + 0x0a;
8206f6ba60Sopenharmony_ci            } else {
8306f6ba60Sopenharmony_ci                break;
8406f6ba60Sopenharmony_ci            }
8506f6ba60Sopenharmony_ci            ++str;
8606f6ba60Sopenharmony_ci        }
8706f6ba60Sopenharmony_ci    } else {
8806f6ba60Sopenharmony_ci        result = 0;
8906f6ba60Sopenharmony_ci    }
9006f6ba60Sopenharmony_ci    return result;
9106f6ba60Sopenharmony_ci}
9206f6ba60Sopenharmony_ci
9306f6ba60Sopenharmony_cistatic int IsEmptyString(const std::string& str)
9406f6ba60Sopenharmony_ci{
9506f6ba60Sopenharmony_ci    size_t idx = 0;
9606f6ba60Sopenharmony_ci    size_t size = str.size();
9706f6ba60Sopenharmony_ci    while (idx < size) {
9806f6ba60Sopenharmony_ci        if (!isspace(static_cast<unsigned char>(str[idx])) && str[idx] != 0) {
9906f6ba60Sopenharmony_ci            return 0;
10006f6ba60Sopenharmony_ci        }
10106f6ba60Sopenharmony_ci        ++idx;
10206f6ba60Sopenharmony_ci    }
10306f6ba60Sopenharmony_ci    return 1;
10406f6ba60Sopenharmony_ci}
10506f6ba60Sopenharmony_ci
10606f6ba60Sopenharmony_cistatic void GetAnUnlimitedLine(FILE* fp, std::string& buf)
10706f6ba60Sopenharmony_ci{
10806f6ba60Sopenharmony_ci    if (!fp) {
10906f6ba60Sopenharmony_ci        buf.resize(0);
11006f6ba60Sopenharmony_ci        return;
11106f6ba60Sopenharmony_ci    }
11206f6ba60Sopenharmony_ci    char* retLine = nullptr;
11306f6ba60Sopenharmony_ci    if (buf.size() == 0) {
11406f6ba60Sopenharmony_ci        buf.resize(INIT_LINE_SIZE);
11506f6ba60Sopenharmony_ci    }
11606f6ba60Sopenharmony_ci
11706f6ba60Sopenharmony_ci    int offset = 0;
11806f6ba60Sopenharmony_ci    int length = 0;
11906f6ba60Sopenharmony_ci    do {
12006f6ba60Sopenharmony_ci        if (offset + length >= static_cast<int>(buf.size())) {
12106f6ba60Sopenharmony_ci            buf.resize(buf.size() + INC_LINE_SIZE);
12206f6ba60Sopenharmony_ci        }
12306f6ba60Sopenharmony_ci        retLine = fgets(&buf[0] + offset, buf.size() - offset, fp);
12406f6ba60Sopenharmony_ci        if (retLine == nullptr) {
12506f6ba60Sopenharmony_ci            break;
12606f6ba60Sopenharmony_ci        }
12706f6ba60Sopenharmony_ci        length = static_cast<int>(strlen(&buf[0] + offset));
12806f6ba60Sopenharmony_ci        if (offset + length - 1 >= 0 && buf[offset + length - 1] == '\n') {
12906f6ba60Sopenharmony_ci            break;
13006f6ba60Sopenharmony_ci        }
13106f6ba60Sopenharmony_ci        offset += length;
13206f6ba60Sopenharmony_ci    } while (1);
13306f6ba60Sopenharmony_ci}
13406f6ba60Sopenharmony_ci
13506f6ba60Sopenharmony_cistatic bool IsLegalSoName(const std::string &fileName)
13606f6ba60Sopenharmony_ci{
13706f6ba60Sopenharmony_ci    if (fileName.front() == '[' or fileName.back() == ']' or
13806f6ba60Sopenharmony_ci        std::strncmp(fileName.c_str(), "/dev/", sizeof("/dev/")) == 0 or
13906f6ba60Sopenharmony_ci        std::strncmp(fileName.c_str(), "/memfd:", sizeof("/memfd:")) == 0 or
14006f6ba60Sopenharmony_ci        std::strncmp(fileName.c_str(), "//anon", sizeof("//anon")) == 0) {
14106f6ba60Sopenharmony_ci        return false;
14206f6ba60Sopenharmony_ci    }
14306f6ba60Sopenharmony_ci    return true;
14406f6ba60Sopenharmony_ci}
14506f6ba60Sopenharmony_ci
14606f6ba60Sopenharmony_cistatic void GetStandardLibraryRange(std::string& line)
14706f6ba60Sopenharmony_ci{
14806f6ba60Sopenharmony_ci    line.resize(strlen(line.c_str()));
14906f6ba60Sopenharmony_ci    std::vector<std::string> mapTokens = OHOS::Developtools::NativeDaemon::StringSplit(line, " ");
15006f6ba60Sopenharmony_ci    const std::string& soRange = mapTokens.front();
15106f6ba60Sopenharmony_ci    std::string& soName = mapTokens.back();
15206f6ba60Sopenharmony_ci    if (IsLegalSoName(soName)) {
15306f6ba60Sopenharmony_ci        std::string::size_type concatPos = soRange.find('-');
15406f6ba60Sopenharmony_ci        uint64_t soStart = static_cast<uint64_t>(strtoll(soRange.c_str(), nullptr, BASE_MAX));
15506f6ba60Sopenharmony_ci        uint64_t soEnd = static_cast<uint64_t>(strtoll(soRange.c_str() + concatPos + 1, nullptr, BASE_MAX));
15606f6ba60Sopenharmony_ci        auto [iter, isExit] = g_stdLib.try_emplace(soName, StandardLibrary(soStart, soEnd, soName));
15706f6ba60Sopenharmony_ci        if (!isExit) {
15806f6ba60Sopenharmony_ci            if (iter->second.soBegin_ > soStart) {
15906f6ba60Sopenharmony_ci                iter->second.soBegin_ = soStart;
16006f6ba60Sopenharmony_ci            } else if (iter->second.soEnd_ < soEnd) {
16106f6ba60Sopenharmony_ci                iter->second.soEnd_ = soEnd;
16206f6ba60Sopenharmony_ci            }
16306f6ba60Sopenharmony_ci        }
16406f6ba60Sopenharmony_ci    }
16506f6ba60Sopenharmony_ci}
16606f6ba60Sopenharmony_ci
16706f6ba60Sopenharmony_civoid GetMainThreadRuntimeStackRange(std::vector<std::pair<uint64_t, uint64_t>>& filterStaLibRange)
16806f6ba60Sopenharmony_ci{
16906f6ba60Sopenharmony_ci    std::string line;
17006f6ba60Sopenharmony_ci    FILE* fp = fopen("/proc/self/maps", "re");
17106f6ba60Sopenharmony_ci    if (fp == nullptr) {
17206f6ba60Sopenharmony_ci        return;
17306f6ba60Sopenharmony_ci    }
17406f6ba60Sopenharmony_ci    while (!feof(fp)) {
17506f6ba60Sopenharmony_ci        line.clear();
17606f6ba60Sopenharmony_ci        GetAnUnlimitedLine(fp, line);
17706f6ba60Sopenharmony_ci        if (IsEmptyString(line)) {
17806f6ba60Sopenharmony_ci            continue;
17906f6ba60Sopenharmony_ci        }
18006f6ba60Sopenharmony_ci        if (line.find("[stack]") != std::string::npos) {
18106f6ba60Sopenharmony_ci            std::string::size_type concatPos = line.find('-');
18206f6ba60Sopenharmony_ci            if (concatPos != std::string::npos) {
18306f6ba60Sopenharmony_ci                g_mainStack.start = reinterpret_cast<char*>(CvtStrToInt(line.c_str(), BASE_MAX));
18406f6ba60Sopenharmony_ci                g_mainStack.end = reinterpret_cast<char*>(CvtStrToInt(line.c_str() + concatPos + 1, BASE_MAX));
18506f6ba60Sopenharmony_ci            }
18606f6ba60Sopenharmony_ci        } else if (line.find("ld-musl") != std::string::npos || line.find("libc++") != std::string::npos) {
18706f6ba60Sopenharmony_ci            GetStandardLibraryRange(line);
18806f6ba60Sopenharmony_ci        }
18906f6ba60Sopenharmony_ci    }
19006f6ba60Sopenharmony_ci    if (fclose(fp) != 0) {
19106f6ba60Sopenharmony_ci        printf("fclose failed.\n");
19206f6ba60Sopenharmony_ci    }
19306f6ba60Sopenharmony_ci    for (const auto& [soName, stdLibrary]: g_stdLib) {
19406f6ba60Sopenharmony_ci        filterStaLibRange.emplace_back(stdLibrary.soBegin_, stdLibrary.soEnd_);
19506f6ba60Sopenharmony_ci    }
19606f6ba60Sopenharmony_ci}
19706f6ba60Sopenharmony_ci
19806f6ba60Sopenharmony_cistatic bool IfContained(const char* start, const char* end, const char* ptr)
19906f6ba60Sopenharmony_ci{
20006f6ba60Sopenharmony_ci    bool ret = (ptr >= start && ptr < end);
20106f6ba60Sopenharmony_ci    return ret;
20206f6ba60Sopenharmony_ci}
20306f6ba60Sopenharmony_ci
20406f6ba60Sopenharmony_cistatic void GetRuntimeSigalAltStackRange(char** start, char** end)
20506f6ba60Sopenharmony_ci{
20606f6ba60Sopenharmony_ci    *start = nullptr;
20706f6ba60Sopenharmony_ci    *end = nullptr;
20806f6ba60Sopenharmony_ci
20906f6ba60Sopenharmony_ci    stack_t altStack;
21006f6ba60Sopenharmony_ci
21106f6ba60Sopenharmony_ci    if (sigaltstack(nullptr, &altStack) != -1) {
21206f6ba60Sopenharmony_ci        if ((altStack.ss_flags & SS_ONSTACK) != 0) {
21306f6ba60Sopenharmony_ci            *start = reinterpret_cast<char*>(altStack.ss_sp);
21406f6ba60Sopenharmony_ci            *end = reinterpret_cast<char*>(altStack.ss_sp) + altStack.ss_size;
21506f6ba60Sopenharmony_ci        }
21606f6ba60Sopenharmony_ci    }
21706f6ba60Sopenharmony_ci}
21806f6ba60Sopenharmony_ci
21906f6ba60Sopenharmony_cistatic bool IfSubThread(pid_t pid, pid_t tid)
22006f6ba60Sopenharmony_ci{
22106f6ba60Sopenharmony_ci    return pid != tid;
22206f6ba60Sopenharmony_ci}
22306f6ba60Sopenharmony_ci
22406f6ba60Sopenharmony_civoid GetRuntimeStackEnd(const char* stackptr, const char** end, pid_t pid, pid_t tid)
22506f6ba60Sopenharmony_ci{
22606f6ba60Sopenharmony_ci    const char* start = nullptr;
22706f6ba60Sopenharmony_ci    *end = nullptr;
22806f6ba60Sopenharmony_ci    bool isSubThread = IfSubThread(pid, tid);
22906f6ba60Sopenharmony_ci    if (isSubThread) {
23006f6ba60Sopenharmony_ci        GetThreadRuntimeStackRange(&start, end);
23106f6ba60Sopenharmony_ci    } else {
23206f6ba60Sopenharmony_ci        start = g_mainStack.start;
23306f6ba60Sopenharmony_ci        *end = g_mainStack.end;
23406f6ba60Sopenharmony_ci    }
23506f6ba60Sopenharmony_ci    if (!IfContained(start, *end, stackptr)) {
23606f6ba60Sopenharmony_ci        char *sigStackStart = nullptr;
23706f6ba60Sopenharmony_ci        char *sigStackEnd = nullptr;
23806f6ba60Sopenharmony_ci        GetRuntimeSigalAltStackRange(&sigStackStart, &sigStackEnd);
23906f6ba60Sopenharmony_ci        if (IfContained(sigStackStart, sigStackEnd, stackptr)) {
24006f6ba60Sopenharmony_ci            *end = sigStackEnd;
24106f6ba60Sopenharmony_ci        } else if (!(!isSubThread && stackptr < *end)) {
24206f6ba60Sopenharmony_ci            *end = nullptr;
24306f6ba60Sopenharmony_ci        }
24406f6ba60Sopenharmony_ci    }
24506f6ba60Sopenharmony_ci}
246