1/*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2022. 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#include "kernel_symbol_info.h"
16
17#include <cstring>
18#include <fstream>
19#include <sstream>
20
21namespace OHOS {
22namespace Developtools {
23namespace Hiebpf {
24void KernelSymbolInfo::GetSymbol(const std::string &line, SymbolItem &symbol)
25{
26    std::stringstream str(line.c_str());
27    str >> std::hex >> symbol.value_;
28    str >> symbol.type_;
29    // only keep text or weak type
30    if (std::strchr("TtWw", symbol.type_)) {
31        symbol.type_ = 'T';
32    } else {
33        return;
34    }
35    str >> symbol.name_;
36}
37
38void KernelSymbolInfo::GetBinary(const std::vector<SymbolItem> &symbolItems,
39                                 uint64_t vaddrStart,
40                                 uint64_t vaddrEnd,
41                                 uint32_t strTabLen,
42                                 std::vector<uint8_t> &buf)
43{
44    // (value + size + nameOffset)
45    uint32_t symTabLen = (sizeof(uint64_t) + sizeof(uint32_t) + sizeof(uint32_t)) *
46                         symbolItems.size();
47    // vaddrStart + vaddrEnd + symTbaLen + strTabLen + symTabData + strTabData
48    uint32_t dataLen = sizeof(uint64_t) + sizeof(uint64_t) + sizeof(uint32_t) + sizeof(uint32_t)
49                       + symTabLen + strTabLen;
50    buf.resize(dataLen);
51
52    uint8_t *p = buf.data();
53    *(reinterpret_cast<uint64_t *>(p)) = vaddrStart;
54    p += sizeof(uint64_t);
55    *(reinterpret_cast<uint64_t *>(p)) = vaddrEnd;
56    p += sizeof(uint64_t);
57    *(reinterpret_cast<uint32_t *>(p)) = symTabLen;
58    p += sizeof(uint32_t);
59    *(reinterpret_cast<uint32_t *>(p)) = strTabLen;
60    p += sizeof(uint32_t);
61
62    uint32_t strTabSize = 0;
63    uint8_t *pStrTab = p + symTabLen;
64    for (auto &symbol : symbolItems) {
65        *(reinterpret_cast<uint64_t *>(p)) = symbol.value_;
66        p += sizeof(uint64_t);
67        *(reinterpret_cast<uint32_t *>(p)) = symbol.size_;
68        p += sizeof(uint32_t);
69        *(reinterpret_cast<uint32_t *>(p)) = strTabSize;
70        p += sizeof(uint32_t);
71
72        std::copy(symbol.name_.c_str(),
73                  symbol.name_.c_str() + symbol.name_.size() + 1,
74                  pStrTab + strTabSize);
75        strTabSize += symbol.name_.size() + 1;
76    }
77}
78
79uint32_t KernelSymbolInfo::GetSymbolData(std::vector<uint8_t> &buf)
80{
81    buf.clear();
82    buf.reserve(DEFAULT_BUFF_SIZE);
83
84    std::ifstream file(KALLSYMS_PATH);
85    std::string line;
86    std::getline(file, line);
87    SymbolItem prevSymbol;
88    GetSymbol(line, prevSymbol);
89    uint64_t vaddrStart = prevSymbol.value_;
90
91    std::vector<SymbolItem> symbolItems;
92    uint32_t strTabLen = 0;
93    SymbolItem currSymbol;
94    while (std::getline(file, line)) {
95        GetSymbol(line, currSymbol);
96        if (prevSymbol.value_ >= currSymbol.value_) {
97            continue; // duplicated or wrong
98        }
99        if (prevSymbol.type_ == 'T') {
100            prevSymbol.size_ = currSymbol.value_ - prevSymbol.value_;
101            symbolItems.emplace_back(prevSymbol);
102            strTabLen += prevSymbol.name_.size() + 1;
103        }
104        prevSymbol = currSymbol;
105    }
106    file.close();
107    if (prevSymbol.type_ == 'T') {
108        symbolItems.emplace_back(prevSymbol);
109        strTabLen += prevSymbol.name_.size() + 1;
110    }
111    if (symbolItems.empty()) {
112        return 0;
113    }
114
115    uint64_t vaddrEnd = prevSymbol.value_ + prevSymbol.size_;
116    GetBinary(symbolItems, vaddrStart, vaddrEnd, strTabLen, buf);
117    return buf.size();
118}
119} // namespace Hiebpf
120} // namespace Developtools
121} // namespace OHOS