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
16#include "hiebpf_data_file.h"
17
18#include <vector>
19
20#include "kernel_symbol_info.h"
21
22
23std::shared_ptr<HiebpfDataFile> HiebpfDataFile::MakeShared(
24    const std::string& cmd,
25    const std::string& filename,
26    const std::size_t pages)
27{
28    std::shared_ptr<HiebpfDataFile> obj {new(std::nothrow) HiebpfDataFile {cmd, filename, pages}};
29    CHECK_NOTNULL(obj, nullptr, "failed to make HiebpfDataFile");
30    CHECK_TRUE(obj->OpenFile() == 0, nullptr, "failed to open hiebpf data file");
31    CHECK_TRUE(obj->MapFile() == 0, nullptr, "failed to map hiebpf data file into memory");
32    return obj;
33}
34
35void* HiebpfDataFile::Reserve(const std::size_t size)
36{
37    std::lock_guard<std::mutex> lk {mtx_};
38    if (offset_ + size >= length_) {
39        if (RemapFile(size) != 0) {
40            return nullptr;
41        }
42    }
43
44    if (mapAddr_ == nullptr) {
45        return nullptr;
46    }
47    char* buffer = static_cast<char *>(mapAddr_);
48    buffer += offset_;
49    (void)memset_s(buffer, size, 0, size);
50    uint32_t *tracer = reinterpret_cast<uint32_t *>(buffer);
51    (*tracer) = BADTRACE;
52    uint32_t *len = tracer + 1;
53    (*len) = size - sizeof(uint32_t) * 2; // 2: double
54    offset_ += size;
55    return buffer;
56}
57
58void HiebpfDataFile::Discard(void *data)
59{
60    if (data) {
61        int64_t interval = static_cast<int64_t>((__u64)data) - ((__u64)mapAddr_);
62        if (0 <= interval and static_cast<uint64_t>(interval) < length_) {
63            uint32_t *tracer = static_cast<uint32_t*>(data);
64            (*tracer) = BADTRACE;
65        }
66    }
67}
68
69void HiebpfDataFile::WriteKernelSymbol()
70{
71    std::vector<uint8_t> buf;
72    uint32_t bufSize = OHOS::Developtools::Hiebpf::KernelSymbolInfo::GetSymbolData(buf);
73    char *tmp = static_cast<char *>(Reserve(bufSize + sizeof(uint32_t) * 2));
74    if (tmp == nullptr) {
75        return;
76    }
77    uint32_t *type = reinterpret_cast<uint32_t *>(tmp);
78    (*type) = KERNEL_SYM;
79    uint32_t *len = type + 1;
80    (*len) = bufSize;
81    if (memcpy_s(tmp + sizeof(uint32_t) * 2, bufSize, buf.data(), bufSize) != EOK) { // 2: double
82        HHLOGE(true, "failed to memcpy");
83        return;
84    }
85}
86
87void HiebpfDataFile::Submit(void *data)
88{
89    __u64 addr = (__u64) data;
90    addr &= ~(pageSize_ - 1);
91    __u32 *len = static_cast<__u32 *>(data);
92    ++len;
93    int ret = msync(reinterpret_cast<void*>(addr), *len, MS_ASYNC);
94    HHLOGF(ret == -1, "failed msync data item with %u bytes", *len);
95    return;
96}
97
98int HiebpfDataFile::MapFile()
99{
100    CHECK_TRUE(ExtendFile(mapPos_, length_) == 0, -1,
101               "failed to extend data file from %u with %u bytes", mapPos_, length_);
102    HHLOGI(true, "done extending the data file");
103    // map the file
104    mapAddr_ = mmap(
105        nullptr, length_,
106        PROT_WRITE | PROT_READ, MAP_SHARED | MAP_POPULATE,
107        fd_, mapPos_);
108    CHECK_TRUE(mapAddr_ != MAP_FAILED, -1, "mmap() failed: %s", strerror(errno));
109    HHLOGI(true, "done mem mapping hiebpf data file");
110    // hiebpf data file header
111    CHECK_TRUE(WriteFileHeader() == 0, -1, "failed to write hiebpf data file header");
112    HHLOGI(true, "done writing hiebpf data file header");
113    return 0;
114}
115
116int HiebpfDataFile::RemapFile(const std::size_t size)
117{
118    if (munmap(mapAddr_, length_) != 0) {
119        return -1;
120    }
121    std::size_t curPos = mapPos_ + offset_;
122    std::size_t remapPos = curPos & ~(pageSize_ - 1);
123    std::size_t remapOff = curPos - remapPos;
124
125    size_t extendLength = DEFAULT_MMAP_LENGTH;
126    while (remapOff + size > extendLength) {
127        extendLength += DEFAULT_MMAP_LENGTH;
128    }
129
130    CHECK_TRUE(ExtendFile(remapPos, extendLength) == 0, -1,
131               "failed to extend file from %u with %u bytes", remapPos, length_);
132    HHLOGI(true, "done extending the data file");
133    mapAddr_ = mmap(
134        nullptr, extendLength,
135        PROT_WRITE | PROT_READ, MAP_SHARED | MAP_POPULATE,
136        fd_, remapPos);
137    CHECK_TRUE(mapAddr_ != MAP_FAILED, -1, "failed to remap data file from %u to %u", mapPos_, remapPos);
138    HHLOGI(true, "done remapping data file from %u, to %u", mapPos_, remapPos);
139    mapPos_ = remapPos;
140    offset_ = remapOff;
141    length_ = extendLength;
142    return 0;
143}