• 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 #include "hook_standalone.h"
16 #include <functional>
17 #include <linux/types.h>
18 #include "utilities.h"
19 #include "hook_common.h"
20 #include "hook_service.h"
21 #include "logging.h"
22 #include "share_memory_allocator.h"
23 #include "event_notifier.h"
24 #include "epoll_event_poller.h"
25 #include "virtual_runtime.h"
26 
27 using namespace OHOS::Developtools::NativeDaemon;
28 namespace OHOS {
29 namespace Developtools {
30 namespace Profiler {
31 namespace Hook {
32 const int DEFAULT_EVENT_POLLING_INTERVAL = 5000;
33 const int MOVE_BIT_16 = 16;
34 const int MOVE_BIT_32 = 32;
35 std::string g_smbName = "hooknativesmb";
36 std::shared_ptr<VirtualRuntime> g_runtimeInstance;
37 std::unique_ptr<EpollEventPoller> g_eventPoller_;
38 std::shared_ptr<ShareMemoryBlock> g_shareMemoryBlock;
39 std::shared_ptr<EventNotifier> g_eventNotifier;
40 std::shared_ptr<HookService> g_hookService;
41 uint32_t g_maxStackDepth;
42 bool g_unwindErrorFlag = false;
43 bool g_fpUnwind = false;
44 std::unique_ptr<FILE, decltype(&fclose)> g_fpHookFile(nullptr, nullptr);
45 
writeFrames(StackRawData * data,const std::vector<CallFrame> & callsFrames)46 void writeFrames(StackRawData *data, const std::vector<CallFrame>& callsFrames)
47 {
48     if (data->type == MALLOC_MSG) {
49         fprintf(g_fpHookFile.get(), "malloc;%" PRId64 ";%ld;0x%" PRIx64 ";%zu\n",
50                 (int64_t)data->ts.tv_sec, data->ts.tv_nsec, (uint64_t)data->addr, data->mallocSize);
51     } else if (data->type == FREE_MSG) {
52         fprintf(g_fpHookFile.get(), "free;%" PRId64 ";%ld;0x%" PRIx64 "\n",
53                 (int64_t)data->ts.tv_sec, data->ts.tv_nsec, (uint64_t)data->addr);
54     } else if (data->type == MMAP_MSG) {
55         fprintf(g_fpHookFile.get(), "mmap;%" PRId64 ";%ld;0x%" PRIx64 ";%zu\n",
56                 (int64_t)data->ts.tv_sec, data->ts.tv_nsec, (uint64_t)data->addr, data->mallocSize);
57     } else if (data->type == MUNMAP_MSG) {
58         fprintf(g_fpHookFile.get(), "munmap;%" PRId64 ";%ld;0x%" PRIx64 ";%zu\n",
59                 (int64_t)data->ts.tv_sec, data->ts.tv_nsec, (uint64_t)data->addr, data->mallocSize);
60     } else {
61         return;
62     }
63 
64     for (size_t idx = 0; idx < callsFrames.size(); ++idx) {
65         auto item = callsFrames[idx];
66         (void)fprintf(g_fpHookFile.get(), "0x%" PRIx64 ";0x%" PRIx64 ";%s;%s;0x%" PRIx64 ";%" PRIu64 "\n",
67                       item.ip_, item.sp_, std::string(item.symbolName_).c_str(),
68                       std::string(item.filePath_).c_str(), item.offset_, item.symbolOffset_);
69     }
70     fflush(g_fpHookFile.get());
71 }
72 
ReadShareMemory(uint64_t duration,const std::string & performance_filename)73 void ReadShareMemory(uint64_t duration, const std::string& performance_filename)
74 {
75     CHECK_NOTNULL(g_shareMemoryBlock, NO_RETVAL, "smb is null!");
76     uint64_t value = g_eventNotifier->Take();
77 
78     static bool first_flag = true;
79     static bool end_flag = false;
80     static uint64_t times = 0;
81 
82     struct timespec first_time;
83     struct timespec begin_time;
84     struct timespec end_time;
85     uint64_t total_time = 0;
86 
87     while (true) {
88         bool ret = g_shareMemoryBlock->TakeData([&](const int8_t data[], uint32_t size) -> bool {
89             if (size < sizeof(StackRawData)) {
90                 HILOG_ERROR(LOG_CORE, "stack data invalid!");
91                 return false;
92             }
93             StackRawData *rawData = reinterpret_cast<StackRawData *>(const_cast<int8_t *>(data));
94             const uint8_t *stackData = reinterpret_cast<const uint8_t *>(data + sizeof(StackRawData));
95             uint32_t stackSize = size - sizeof(StackRawData);
96 
97             std::vector<u64> u64regs;
98             std::vector<CallFrame> callsFrames;
99 
100             if (g_fpUnwind) {
101                 for (int idx = 1; idx < MAX_UNWIND_DEPTH; ++idx) {
102                     if (rawData->ip[idx] == 0) {
103                         break;
104                     }
105                     OHOS::Developtools::NativeDaemon::CallFrame frame(0);
106                     frame.ip_ = rawData->ip[idx];
107                     callsFrames.push_back(frame);
108                 }
109             } else {
110                 int regCount = OHOS::Developtools::NativeDaemon::RegisterGetCount();
111 #if defined(__arm__)
112                 uint32_t *regAddrArm = reinterpret_cast<uint32_t *>(rawData->regs);
113                 for (int idx = 0; idx < regCount; ++idx) {
114                     u64regs.push_back(*regAddrArm++);
115                 }
116 #else
117                 uint64_t *regAddrAarch64 = reinterpret_cast<uint64_t *>(rawData->regs);
118                 for (int idx = 0; idx < regCount; ++idx) {
119                     u64regs.push_back(*regAddrAarch64++);
120                 }
121 #endif
122             }
123 
124             if (!end_flag && duration != 0) {
125                 clock_gettime(CLOCK_REALTIME, &begin_time);
126                 if (first_flag) {
127                     first_flag = false;
128                     first_time = begin_time;
129                 }
130             }
131 
132             bool ret = g_runtimeInstance->UnwindStack(u64regs, stackData, stackSize, rawData->pid,
133                 rawData->tid, callsFrames,
134                 (g_maxStackDepth > 0) ? g_maxStackDepth + FILTER_STACK_DEPTH : MAX_CALL_FRAME_UNWIND_SIZE);
135             if (!ret && !g_unwindErrorFlag) {
136                 HILOG_ERROR(LOG_CORE, "unwind error, try unwind twice");
137                 g_runtimeInstance = nullptr;
138                 g_runtimeInstance = std::make_shared<VirtualRuntime>();
139                 callsFrames.clear();
140                 bool ret = g_runtimeInstance->UnwindStack(u64regs, stackData, stackSize, rawData->pid,
141                     rawData->tid, callsFrames,
142                     (g_maxStackDepth > 0) ? g_maxStackDepth + FILTER_STACK_DEPTH : MAX_CALL_FRAME_UNWIND_SIZE);
143                 if (!ret) {
144                     g_unwindErrorFlag = true;
145                     HILOG_ERROR(LOG_CORE, "unwind fatal error, do not try unwind twice!");
146                     return true;
147                 }
148             }
149 
150             if (!end_flag && duration != 0) {
151                 clock_gettime(CLOCK_REALTIME, &end_time);
152                 total_time += (end_time.tv_sec - begin_time.tv_sec) * 1000000000LLU +
153                     (end_time.tv_nsec - begin_time.tv_nsec);
154                 ++times;
155                 if (end_time.tv_sec - first_time.tv_sec >= duration) {
156                     end_flag = true;
157                     FILE *fp = fopen(performance_filename.c_str(), "a");
158                     if (fp) {
159                         time_t now = time(NULL);
160                         struct tm now_tm;
161                         localtime_r(&now, &now_tm);
162                         fprintf(fp, "Current time: %04d-%02d-%02d %02d:%02d:%02d\n", now_tm.tm_year + 1900,
163                                 now_tm.tm_mon + 1, now_tm.tm_mday, now_tm.tm_hour, now_tm.tm_min, now_tm.tm_sec);
164                         fprintf(fp, "Total durations: %" PRIu64 " nanoseconds\n", total_time);
165                         fprintf(fp, "Total times: %" PRIu64 "\n", times);
166                         fprintf(fp, "Average unwinding stack time: %.2f  nanoseconds\n\n",
167                                 (double)(total_time) / times);
168                         fclose(fp);
169                         printf("Performance data has already been generated.\n");
170                     }
171                 }
172             }
173 
174             writeFrames(rawData, callsFrames);
175 
176             return true;
177         });
178         if (!ret) {
179             break;
180         }
181     }
182 }
183 
StartHook(HookData & hookData)184 bool StartHook(HookData& hookData)
185 {
186     g_runtimeInstance = std::make_shared<VirtualRuntime>();
187     FILE *fp = fopen(hookData.fileName.c_str(), "wb+");
188     if (fp != nullptr) {
189         g_fpHookFile.reset();
190         g_fpHookFile = std::unique_ptr<FILE, decltype(&fclose)>(fp, fclose);
191     }
192     if (g_fpHookFile == nullptr) {
193         printf("create file failed!\n");
194         return false;
195     }
196     // create smb and eventNotifier
197     g_shareMemoryBlock = ShareMemoryAllocator::GetInstance().CreateMemoryBlockLocal(g_smbName, hookData.smbSize);
198     g_eventNotifier = EventNotifier::Create(0, EventNotifier::NONBLOCK);
199     // start event poller task
200     g_eventPoller_ = std::make_unique<EpollEventPoller>(DEFAULT_EVENT_POLLING_INTERVAL);
201     g_eventPoller_->Init();
202     g_eventPoller_->Start();
203     g_eventPoller_->AddFileDescriptor(g_eventNotifier->GetFd(),
204                                       std::bind(ReadShareMemory, hookData.duration, hookData.performance_filename));
205 
206     HILOG_INFO(LOG_CORE, "hookservice smbFd = %d, eventFd = %d\n", g_shareMemoryBlock->GetfileDescriptor(),
207                g_eventNotifier->GetFd());
208 
209     // hook config |F F            F F              F F F F       F F F F      F F F F|
210     //              stack depth    malloctype       filtersize    sharememory  size
211 #if defined(__arm__)
212     hookData.fpUnwind = false;
213 #endif
214     uint64_t hookConfig = (uint8_t)hookData.maxStackDepth;
215     const int moveBit8 = 8;
216     hookConfig <<= moveBit8;
217 
218     hookConfig |= hookData.mallocDisable ? MALLOCDISABLE : 0;
219     hookConfig |= hookData.mmapDisable ? MMAPDISABLE : 0;
220     hookConfig |= hookData.freemsgstack ? FREEMSGSTACK : 0;
221     hookConfig |= hookData.munmapmsgstack ? MUNMAPMSGSTACK : 0;
222     hookConfig |= hookData.fpUnwind ? FPUNWIND : 0;
223 
224     hookConfig <<= MOVE_BIT_16;
225     hookConfig |= hookData.filterSize;
226     hookConfig <<= MOVE_BIT_32;
227     hookConfig |= hookData.smbSize;
228 
229     HILOG_INFO(LOG_CORE, "hookConfig = 0x%" PRIx64 ",  hookservice smbFd = %d, eventFd = %d\n",
230         hookConfig, g_shareMemoryBlock->GetfileDescriptor(), g_eventNotifier->GetFd());
231 
232     g_hookService = std::make_shared<HookService>(g_shareMemoryBlock->GetfileDescriptor(),
233         g_eventNotifier->GetFd(), hookData.pid, hookData.processName, hookConfig);
234 
235     g_maxStackDepth = hookData.maxStackDepth;
236     g_fpUnwind = hookData.fpUnwind;
237     return true;
238 }
239 } // namespace Hook
240 } // namespace Profiler
241 } // namespace Developtools
242 } // namespace OHOS
243