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#ifndef STACK_PREPROCESS_H
1606f6ba60Sopenharmony_ci#define STACK_PREPROCESS_H
1706f6ba60Sopenharmony_ci
1806f6ba60Sopenharmony_ci#include <chrono>
1906f6ba60Sopenharmony_ci#include <thread>
2006f6ba60Sopenharmony_ci#include <unordered_map>
2106f6ba60Sopenharmony_ci#include <list>
2206f6ba60Sopenharmony_ci#include <algorithm>
2306f6ba60Sopenharmony_ci#include <mutex>
2406f6ba60Sopenharmony_ci#include <variant>
2506f6ba60Sopenharmony_ci
2606f6ba60Sopenharmony_ci#include "logging.h"
2706f6ba60Sopenharmony_ci#include "nocopyable.h"
2806f6ba60Sopenharmony_ci#include "stack_data_repeater.h"
2906f6ba60Sopenharmony_ci#include "buffer_writer.h"
3006f6ba60Sopenharmony_ci#include "virtual_runtime.h"
3106f6ba60Sopenharmony_ci#include "hook_common.h"
3206f6ba60Sopenharmony_ci#include "native_hook_config.pb.h"
3306f6ba60Sopenharmony_ci#include "native_hook_result.pb.h"
3406f6ba60Sopenharmony_ci#include "native_hook_result.pbencoder.h"
3506f6ba60Sopenharmony_ci#include "safe_map.h"
3606f6ba60Sopenharmony_ci#include "schedule_task_manager.h"
3706f6ba60Sopenharmony_ci
3806f6ba60Sopenharmony_ciusing WriterStructPtr = std::unique_ptr<WriterStruct>::pointer;
3906f6ba60Sopenharmony_ciclass StackPreprocess : public std::enable_shared_from_this<StackPreprocess> {
4006f6ba60Sopenharmony_cipublic:
4106f6ba60Sopenharmony_ci    struct RecordStatistic {
4206f6ba60Sopenharmony_ci        uint32_t pid {0};
4306f6ba60Sopenharmony_ci        uint32_t callstackId {0};
4406f6ba60Sopenharmony_ci        uint32_t tagId {0};
4506f6ba60Sopenharmony_ci        RecordStatisticsEvent::MemoryType type {RecordStatisticsEvent::MALLOC};
4606f6ba60Sopenharmony_ci        uint64_t applyCount {0};
4706f6ba60Sopenharmony_ci        uint64_t releaseCount {0};
4806f6ba60Sopenharmony_ci        uint64_t applySize {0};
4906f6ba60Sopenharmony_ci        uint64_t releaseSize {0};
5006f6ba60Sopenharmony_ci    };
5106f6ba60Sopenharmony_ci
5206f6ba60Sopenharmony_ci    explicit StackPreprocess(const StackDataRepeaterPtr& dataRepeater, const NativeHookConfig& hookConfig,
5306f6ba60Sopenharmony_ci        clockid_t pluginDataClockId, FILE* fpHookData = nullptr, bool isHookStandalone = false,
5406f6ba60Sopenharmony_ci        bool isSaService = false, bool isProtobufSerialize = true);
5506f6ba60Sopenharmony_ci    ~StackPreprocess();
5606f6ba60Sopenharmony_ci    void SetWriter(const std::shared_ptr<Writer>& writer);
5706f6ba60Sopenharmony_ci    void SetWriter(const WriterStructPtr& writer);
5806f6ba60Sopenharmony_ci    bool StartTakeResults();
5906f6ba60Sopenharmony_ci    bool StopTakeResults();
6006f6ba60Sopenharmony_ci    void FinishTraceFile();
6106f6ba60Sopenharmony_ci    bool FlushRecordStatistics();
6206f6ba60Sopenharmony_ci    void FlushRecordApplyAndReleaseMatchData();
6306f6ba60Sopenharmony_ci    void ForceStop();
6406f6ba60Sopenharmony_ci    inline void SetPid(int32_t pid)
6506f6ba60Sopenharmony_ci    {
6606f6ba60Sopenharmony_ci        pid_ = pid;
6706f6ba60Sopenharmony_ci    }
6806f6ba60Sopenharmony_ci    inline void InitStatisticsTime()
6906f6ba60Sopenharmony_ci    {
7006f6ba60Sopenharmony_ci        lastStatisticsTime_ = std::chrono::steady_clock::now();
7106f6ba60Sopenharmony_ci    }
7206f6ba60Sopenharmony_ci    void SaveMemTag(uint32_t tagId, const std::string& tagName);
7306f6ba60Sopenharmony_ci    bool GetMemTag(uint32_t tagId, std::string& tagName);
7406f6ba60Sopenharmony_ci    void SaveJsRawStack(uint64_t jsChainId, const char* jsRawStack);
7506f6ba60Sopenharmony_ci    const char* GetJsRawStack(uint64_t jsChainId);
7606f6ba60Sopenharmony_ci    void ReportBasicData();
7706f6ba60Sopenharmony_ci    void WriteHookConfig();
7806f6ba60Sopenharmony_ci    void TakeResultsFromShmem(const std::shared_ptr<EventNotifier>&, const std::shared_ptr<ShareMemoryBlock>&);
7906f6ba60Sopenharmony_ci    void SetNmdFd(uint32_t fd)
8006f6ba60Sopenharmony_ci    {
8106f6ba60Sopenharmony_ci        nmdFd_ = fd;
8206f6ba60Sopenharmony_ci    }
8306f6ba60Sopenharmony_ci    void SetFlushSize(uint64_t size)
8406f6ba60Sopenharmony_ci    {
8506f6ba60Sopenharmony_ci        double tenth = static_cast<double>(size) / 10.0;
8606f6ba60Sopenharmony_ci        flushSize_ = static_cast<uint64_t>(std::ceil(tenth));
8706f6ba60Sopenharmony_ci        PROFILER_LOG_INFO(LOG_CORE, "SetFlushSize size: %" PRIu64 ", flushSize_: %" PRIu64 "", size, flushSize_);
8806f6ba60Sopenharmony_ci        if (isProtobufSerialize_) {
8906f6ba60Sopenharmony_ci            bufferSize_ = flushSize_ << 1;
9006f6ba60Sopenharmony_ci            buffer_ = std::make_unique<uint8_t[]>(bufferSize_);
9106f6ba60Sopenharmony_ci        }
9206f6ba60Sopenharmony_ci    }
9306f6ba60Sopenharmony_ci
9406f6ba60Sopenharmony_ciprivate:
9506f6ba60Sopenharmony_ci    using CallFrame = OHOS::Developtools::NativeDaemon::CallFrame;
9606f6ba60Sopenharmony_ci    struct ElfSymbolTable {
9706f6ba60Sopenharmony_ci        uint64_t textVaddr;
9806f6ba60Sopenharmony_ci        uint32_t textOffset;
9906f6ba60Sopenharmony_ci        uint32_t symEntSize;
10006f6ba60Sopenharmony_ci        std::vector<uint8_t> strTable;
10106f6ba60Sopenharmony_ci        std::vector<uint8_t> symTable;
10206f6ba60Sopenharmony_ci    };
10306f6ba60Sopenharmony_ci
10406f6ba60Sopenharmony_ci    enum RecordStatisticsLimit : std::size_t {
10506f6ba60Sopenharmony_ci        STATISTICS_MAP_SZIE = 100000,
10606f6ba60Sopenharmony_ci        STATISTICS_PERIOD_DATA_SIZE = 100000,
10706f6ba60Sopenharmony_ci        ALLOC_ADDRMAMP_SIZE = 100000,
10806f6ba60Sopenharmony_ci        MATCH_ADDRMAMP_SIZE = 100000,
10906f6ba60Sopenharmony_ci    };
11006f6ba60Sopenharmony_ci
11106f6ba60Sopenharmony_ci    struct ScopedLockFile {
11206f6ba60Sopenharmony_ci        ScopedLockFile(FILE* fpHook): fpHookData(fpHook)
11306f6ba60Sopenharmony_ci        {
11406f6ba60Sopenharmony_ci            flockfile(fpHookData);
11506f6ba60Sopenharmony_ci        }
11606f6ba60Sopenharmony_ci        ~ScopedLockFile()
11706f6ba60Sopenharmony_ci        {
11806f6ba60Sopenharmony_ci            funlockfile(fpHookData);
11906f6ba60Sopenharmony_ci        }
12006f6ba60Sopenharmony_ci        FILE* fpHookData {nullptr};
12106f6ba60Sopenharmony_ci    };
12206f6ba60Sopenharmony_ci
12306f6ba60Sopenharmony_ciprivate:
12406f6ba60Sopenharmony_ci    void TakeResults();
12506f6ba60Sopenharmony_ci    template <typename T>
12606f6ba60Sopenharmony_ci    void SetHookData(RawStackPtr rawStack, T& stackData);
12706f6ba60Sopenharmony_ci    template <typename T>
12806f6ba60Sopenharmony_ci    void SetHookData(RawStackPtr rawStack, std::vector<CallFrame>& callFrames, T& stackData);
12906f6ba60Sopenharmony_ci    void WriteFrames(RawStackPtr RawStack, const std::vector<CallFrame>& callFrames);
13006f6ba60Sopenharmony_ci    template <typename T>
13106f6ba60Sopenharmony_ci    void SetFrameInfo(T& frame, CallFrame& callFrame);
13206f6ba60Sopenharmony_ci    template <typename T>
13306f6ba60Sopenharmony_ci    void ReportSymbolNameMap(CallFrame& callFrame, T& stackData);
13406f6ba60Sopenharmony_ci    template <typename T>
13506f6ba60Sopenharmony_ci    void ReportFilePathMap(CallFrame& callFrame, T& stackData);
13606f6ba60Sopenharmony_ci    template <typename T>
13706f6ba60Sopenharmony_ci    void ReportFrameMap(CallFrame& callFrame, T& stackData);
13806f6ba60Sopenharmony_ci    void ReportThreadNameMap(uint32_t tid, const std::string& tname);
13906f6ba60Sopenharmony_ci    void SetMapsInfo();
14006f6ba60Sopenharmony_ci    template <typename T>
14106f6ba60Sopenharmony_ci    void SetSymbolInfo(uint32_t filePathId, ElfSymbolTable& symbolInfo, T& batchNativeHookData);
14206f6ba60Sopenharmony_ci    template <typename T>
14306f6ba60Sopenharmony_ci    void FlushCheck(T& stackData);
14406f6ba60Sopenharmony_ci    void FlushData(BatchNativeHookData& stackData);
14506f6ba60Sopenharmony_ci    void FlushData(OHOS::Developtools::Profiler::ProtoEncoder::BatchNativeHookData& stackData);
14606f6ba60Sopenharmony_ci    void Flush(const uint8_t* src, size_t size);
14706f6ba60Sopenharmony_ci    void GetSymbols(const std::string& filePath, ElfSymbolTable& symbols);
14806f6ba60Sopenharmony_ci    template <typename T>
14906f6ba60Sopenharmony_ci    void FillOfflineCallStack(std::vector<CallFrame>& callFrames, size_t idx, T& stackData);
15006f6ba60Sopenharmony_ci    template <typename T>
15106f6ba60Sopenharmony_ci    void FillCallStack(std::vector<CallFrame>& callFrames, size_t idx, T& stackData);
15206f6ba60Sopenharmony_ci    template <typename T>
15306f6ba60Sopenharmony_ci    uint32_t SetCallStackMap(T& stackData);
15406f6ba60Sopenharmony_ci    template <typename T>
15506f6ba60Sopenharmony_ci    uint32_t GetCallStackId(const RawStackPtr& rawStack, std::vector<CallFrame>& callFrames, T& stackData);
15606f6ba60Sopenharmony_ci    uint32_t FindCallStackId(std::vector<uint64_t>& callStack);
15706f6ba60Sopenharmony_ci    template <typename T>
15806f6ba60Sopenharmony_ci    void SetEventFrame(const RawStackPtr& rawStack, std::vector<CallFrame>& callFrames,
15906f6ba60Sopenharmony_ci        T* event, uint32_t stackId, const std::string& type = "");
16006f6ba60Sopenharmony_ci    template <typename T>
16106f6ba60Sopenharmony_ci    void SetEventFrame(const ReportEventBaseData& rawStack, T* event, uint32_t stackMapId,
16206f6ba60Sopenharmony_ci                       const std::string& type = "");
16306f6ba60Sopenharmony_ci    template <typename T>
16406f6ba60Sopenharmony_ci    void SetAllocStatisticsFrame(const RawStackPtr& rawStack, std::vector<CallFrame>& callFrames, T& stackData);
16506f6ba60Sopenharmony_ci    template <typename T>
16606f6ba60Sopenharmony_ci    void SetAllocStatisticsFrame(const RawStackPtr& rawStack, T& stackData);
16706f6ba60Sopenharmony_ci    template <typename T>
16806f6ba60Sopenharmony_ci    void SetApplyAndReleaseMatchFrame(RawStackPtr rawStack, std::vector<CallFrame>& callFrames, T& stackData);
16906f6ba60Sopenharmony_ci    void IntervalFlushRecordStatistics();
17006f6ba60Sopenharmony_ci    void IntervalFlushApplyAndReleaseMatchData();
17106f6ba60Sopenharmony_ci    bool HandleNoStackEvent(RawStackPtr& rawStack);
17206f6ba60Sopenharmony_ci    bool SetFreeStatisticsData(uint64_t addr);
17306f6ba60Sopenharmony_ci    void SetAllocStatisticsData(const RawStackPtr& rawStack, size_t stackId, bool isExists = false);
17406f6ba60Sopenharmony_ci    unsigned LgFloor(unsigned long x);
17506f6ba60Sopenharmony_ci    uint64_t PowCeil(uint64_t x);
17606f6ba60Sopenharmony_ci    size_t ComputeAlign(size_t size);
17706f6ba60Sopenharmony_ci    void ReportOfflineSymbolizationData();
17806f6ba60Sopenharmony_ci
17906f6ba60Sopenharmony_ci    RandomWriteCtx* StartReport();
18006f6ba60Sopenharmony_ci    void FinishReport();
18106f6ba60Sopenharmony_ci    void FillFpNativeIp(RawStackPtr& rawData);
18206f6ba60Sopenharmony_ci    void FillFpJsData(RawStackPtr& rawData);
18306f6ba60Sopenharmony_ci    void FillDwarfErrorStack();
18406f6ba60Sopenharmony_ci    void FillNapiStack(std::string& tagName, std::vector<CallFrame>& callFrames, uint64_t napiIndex);
18506f6ba60Sopenharmony_ciprivate:
18606f6ba60Sopenharmony_ci    std::chrono::steady_clock::time_point lastStatisticsTime_ = std::chrono::steady_clock::now();
18706f6ba60Sopenharmony_ci    std::shared_ptr<Writer> writer_ = nullptr;
18806f6ba60Sopenharmony_ci    StackDataRepeaterPtr dataRepeater_ = nullptr;
18906f6ba60Sopenharmony_ci    std::thread thread_ {};
19006f6ba60Sopenharmony_ci    std::unique_ptr<uint8_t[]> buffer_;
19106f6ba60Sopenharmony_ci    std::atomic_bool isStopTakeData_ = false;
19206f6ba60Sopenharmony_ci    std::shared_ptr<OHOS::Developtools::NativeDaemon::VirtualRuntime> runtime_instance;
19306f6ba60Sopenharmony_ci    DISALLOW_COPY_AND_MOVE(StackPreprocess);
19406f6ba60Sopenharmony_ci    OHOS::SafeMap<uint32_t, std::string> memTagMap_ = {};
19506f6ba60Sopenharmony_ci    std::unordered_map<uint32_t, std::string> threadNameMap_ = {};
19606f6ba60Sopenharmony_ci    NativeHookConfig hookConfig_;
19706f6ba60Sopenharmony_ci    uint32_t ignoreCnts_ = 0;
19806f6ba60Sopenharmony_ci    uint32_t eventCnts_ = 0;
19906f6ba60Sopenharmony_ci    bool flushBasicData_ {true};
20006f6ba60Sopenharmony_ci    std::vector<u64> u64regs_;
20106f6ba60Sopenharmony_ci    std::vector<CallFrame> callFrames_;
20206f6ba60Sopenharmony_ci    std::vector<uint64_t> callStack_;
20306f6ba60Sopenharmony_ci    // Key is callStack_, value is call stack id
20406f6ba60Sopenharmony_ci    std::map<std::vector<uint64_t>, uint32_t> callStackMap_;
20506f6ba60Sopenharmony_ci    // Key is ip , response_library_mode used
20606f6ba60Sopenharmony_ci    std::unordered_map<uint64_t, uint32_t> responseLibraryMap_;
20706f6ba60Sopenharmony_ci    std::chrono::seconds statisticsInterval_ {0};
20806f6ba60Sopenharmony_ci    // Key is call stack id, value is recordstatistic data
20906f6ba60Sopenharmony_ci    std::unordered_map<uint32_t, RecordStatistic> recordStatisticsMap_;
21006f6ba60Sopenharmony_ci    // Key is call stack id, value is recordstatistic data pointer
21106f6ba60Sopenharmony_ci    std::unordered_map<uint32_t, RecordStatistic*> statisticsPeriodData_;
21206f6ba60Sopenharmony_ci    // Key is alloc or mmap address, value first is mallocsize, second is recordstatistic data pointer
21306f6ba60Sopenharmony_ci    std::unordered_map<uint64_t, std::pair<uint64_t, RecordStatistic*>> allocAddrMap_;
21406f6ba60Sopenharmony_ci    // Key is alloc or mmap address, value is ReportEventBaseData list iterator
21506f6ba60Sopenharmony_ci    std::unordered_map<uint64_t, std::list<ReportEventBaseData>::iterator> applyAndReleaseMatchIntervallMap_;
21606f6ba60Sopenharmony_ci    std::list<ReportEventBaseData> applyAndReleaseMatchPeriodListData_;
21706f6ba60Sopenharmony_ci    std::chrono::seconds applyAndReleaseMatchInterval_{0};
21806f6ba60Sopenharmony_ci    // used for plugin data
21906f6ba60Sopenharmony_ci    clockid_t pluginDataClockId_ = CLOCK_REALTIME;
22006f6ba60Sopenharmony_ci    // used for clac wait time in StackDataRepeater::TakeRawData() or statistics HookData
22106f6ba60Sopenharmony_ci    clockid_t hookDataClockId_ = CLOCK_REALTIME;
22206f6ba60Sopenharmony_ci    FILE* fpHookData_ {nullptr};
22306f6ba60Sopenharmony_ci    bool isHookStandaloneSerialize_ {false};
22406f6ba60Sopenharmony_ci    int32_t pid_ {-1};
22506f6ba60Sopenharmony_ci    std::mutex mtx_;
22606f6ba60Sopenharmony_ci    bool isSaService_{false};
22706f6ba60Sopenharmony_ci    std::mutex allocAddrMapMtx_;
22806f6ba60Sopenharmony_ci    bool isProtobufSerialize_{true};
22906f6ba60Sopenharmony_ci    WriterStructPtr resultWriter_{nullptr};
23006f6ba60Sopenharmony_ci    std::variant<BatchNativeHookData, OHOS::Developtools::Profiler::ProtoEncoder::BatchNativeHookData> stackData_;
23106f6ba60Sopenharmony_ci    uint64_t flushSize_{0};
23206f6ba60Sopenharmony_ci    uint64_t bufferSize_{0};
23306f6ba60Sopenharmony_ci    bool statisticsModelFlushCallstack_{false};
23406f6ba60Sopenharmony_ci    OHOS::Developtools::Profiler::ProtoEncoder::ProfilerPluginData profilerPluginData_;
23506f6ba60Sopenharmony_ci    // Key is js stack id , value is js raw stack pointer
23606f6ba60Sopenharmony_ci    std::map<uint64_t, const char*> jsStackMap_ = {};
23706f6ba60Sopenharmony_ci    std::set<std::string> jsStackSet_ = {};
23806f6ba60Sopenharmony_ci    bool unwindFailReport_ = true;
23906f6ba60Sopenharmony_ci    std::vector<std::string> prctlPeriodTags_; // applyAndReleaseMatchInterval mode used
24006f6ba60Sopenharmony_ci    std::vector<std::string> fpJsCallStacks_;
24106f6ba60Sopenharmony_ci    std::atomic<uint64_t> napiIndex_{1};
24206f6ba60Sopenharmony_ci    ScheduleTaskManager scheduleTaskManager_;
24306f6ba60Sopenharmony_ci    uint32_t nmdFd_ = 0;
24406f6ba60Sopenharmony_ci};
24506f6ba60Sopenharmony_ci
24606f6ba60Sopenharmony_ci#endif // STACK_PREPROCESS_H