• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 
16 #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h"
17 
18 
19 #include "ecmascript/compiler/aot_file/aot_file_manager.h"
20 #include "ecmascript/jspandafile/js_pandafile_manager.h"
21 
22 #if defined(ENABLE_FFRT_INTERFACES)
23 #include "c/executor_task.h"
24 #endif
25 
26 #if !defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
27     #error "ECMASCRIPT_SUPPORT_CPUPROFILER not defined"
28 #endif
29 
30 namespace panda::ecmascript {
31 Mutex CpuProfiler::synchronizationMutex_;
32 CMap<pthread_t, struct TaskInfo> CpuProfiler::profilerMap_ = CMap<pthread_t, struct TaskInfo>();
CpuProfiler(const EcmaVM * vm,const int interval)33 CpuProfiler::CpuProfiler(const EcmaVM *vm, const int interval) : vm_(vm), interval_(interval)
34 {
35     enableVMTag_ = const_cast<EcmaVM *>(vm)->GetJSOptions().EnableCpuProfilerVMTag();
36     generator_ = new SamplesRecord();
37     generator_->SetEnableVMTag(enableVMTag_);
38     generator_->SetSourceMapTranslateCallback(vm->GetSourceMapTranslateCallback());
39     generator_->NodeInit();
40     if (generator_->SemInit(0, 0, 0) != 0) {
41         LOG_ECMA(ERROR) << "sem_[0] init failed";
42     }
43     if (generator_->SemInit(1, 0, 0) != 0) {
44         LOG_ECMA(ERROR) << "sem_[1] init failed";
45     }
46     if (generator_->SemInit(2, 0, 0) != 0) { // 2: signal 2
47         LOG_ECMA(ERROR) << "sem_[2] init failed";
48     }
49 }
50 
RegisterGetStackSignal()51 bool CpuProfiler::RegisterGetStackSignal()
52 {
53     struct sigaction sa;
54     sa.sa_sigaction = &GetStackSignalHandler;
55     if (sigemptyset(&sa.sa_mask) != 0) {
56         LOG_ECMA(ERROR) << "CpuProfiler::RegisterGetStackSignal, sigemptyset failed, errno = " << errno;
57         return false;
58     }
59     sa.sa_flags = SA_RESTART | SA_SIGINFO;
60     if (sigaction(SIGPROF, &sa, nullptr) != 0) {
61         LOG_ECMA(ERROR) << "CpuProfiler::RegisterGetStackSignal, sigaction failed, errno = " << errno;
62         return false;
63     }
64     return true;
65 }
66 
StartCpuProfilerForInfo()67 bool CpuProfiler::StartCpuProfilerForInfo()
68 {
69     LOG_ECMA(INFO) << "CpuProfiler::StartCpuProfilerForInfo, sampling interval = " << interval_;
70     if (isProfiling_) {
71         LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForInfo, can not start when CpuProfiler is Profiling";
72         return false;
73     }
74     if (!RegisterGetStackSignal()) {
75         return false;
76     }
77     // when the ffrt is enabled for the thread, the tid_ will be task id
78     tid_ = static_cast<pthread_t>(JSThread::GetCurrentThreadId());
79     void *taskHandle = nullptr;
80     // when the ffrt is enabled for the thread,
81     // we record the task handle, which can be used to obtain the running thread id in the task
82 #if defined(ENABLE_FFRT_INTERFACES)
83     taskHandle = ffrt_get_cur_task();
84     TaskInfo taskInfo { vm_, taskHandle };
85 #else
86     TaskInfo taskInfo { vm_, nullptr };
87 #endif // defined(ENABLE_FFRT_INTERFACES)
88     {
89         LockHolder lock(synchronizationMutex_);
90         profilerMap_[tid_] = taskInfo;
91     }
92 
93     JSPandaFileManager *pandaFileManager = JSPandaFileManager::GetInstance();
94     pandaFileManager->EnumerateJSPandaFiles([&](const std::shared_ptr<JSPandaFile> &file) -> bool {
95         pandaFileManager->CpuProfilerGetJSPtExtractor(file.get());
96         return true;
97     });
98 
99     generator_->SetTimeDeltaThreshold(interval_ * THRESHOLD_GROWTH_FACTORY + THRESHOLD_FIXED_INCREMENT);
100     generator_->SetIsStart(true);
101     uint64_t startTime = SamplingProcessor::GetMicrosecondsTimeStamp();
102     generator_->SetThreadStartTime(startTime);
103     params_ = new RunParams(generator_, static_cast<uint32_t>(interval_), pthread_self(), taskHandle);
104     if (pthread_create(&tid_, nullptr, SamplingProcessor::Run, params_) != 0) {
105         LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForInfo, pthread_create failed, errno = " << errno;
106         return false;
107     }
108     isProfiling_ = true;
109     vm_->GetJSThread()->SetIsProfiling(true);
110     outToFile_ = false;
111     return true;
112 }
113 
StartCpuProfilerForFile(const std::string & fileName)114 bool CpuProfiler::StartCpuProfilerForFile(const std::string &fileName)
115 {
116     LOG_ECMA(INFO) << "CpuProfiler::StartCpuProfilerForFile, sampling interval = " << interval_;
117     if (isProfiling_) {
118         LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForFile, can not start when CpuProfiler is Profiling";
119         return false;
120     }
121     std::string absoluteFilePath("");
122     if (!CheckFileName(fileName, absoluteFilePath)) {
123         return false;
124     }
125     fileName_ = absoluteFilePath;
126     generator_->SetFileName(fileName_);
127     generator_->fileHandle_.open(fileName_.c_str());
128     if (generator_->fileHandle_.fail()) {
129         LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForFile, fileHandle_ open failed";
130         return false;
131     }
132     if (!RegisterGetStackSignal()) {
133         return false;
134     }
135     // when the ffrt is enabled for the thread, the tid_ will be task id
136     tid_ = static_cast<pthread_t>(JSThread::GetCurrentThreadId());
137     void *taskHandle = nullptr;
138     // when the ffrt is enabled for the thread,
139     // we record the task handle, which can be used to obtain the running thread id in the task
140 #if defined(ENABLE_FFRT_INTERFACES)
141     taskHandle = ffrt_get_cur_task();
142     TaskInfo taskInfo { vm_, taskHandle };
143 #else
144     TaskInfo taskInfo { vm_, nullptr };
145 #endif // defined(ENABLE_FFRT_INTERFACES)
146     {
147         LockHolder lock(synchronizationMutex_);
148         profilerMap_[tid_] = taskInfo;
149     }
150 
151     JSPandaFileManager *pandaFileManager = JSPandaFileManager::GetInstance();
152     pandaFileManager->EnumerateJSPandaFiles([&](const std::shared_ptr<JSPandaFile> &file) -> bool {
153         pandaFileManager->CpuProfilerGetJSPtExtractor(file.get());
154         return true;
155     });
156 
157     generator_->SetTimeDeltaThreshold(interval_ * THRESHOLD_GROWTH_FACTORY + THRESHOLD_FIXED_INCREMENT);
158     generator_->SetIsStart(true);
159     uint64_t startTime = SamplingProcessor::GetMicrosecondsTimeStamp();
160     generator_->SetThreadStartTime(startTime);
161     params_ = new RunParams(generator_, static_cast<uint32_t>(interval_), pthread_self(), taskHandle);
162     if (pthread_create(&tid_, nullptr, SamplingProcessor::Run, params_) != 0) {
163         LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForFile, pthread_create failed, errno = " << errno;
164         return false;
165     }
166     isProfiling_ = true;
167     vm_->GetJSThread()->SetIsProfiling(true);
168     outToFile_ = true;
169     return true;
170 }
171 
StopCpuProfilerForInfo(std::unique_ptr<struct ProfileInfo> & profileInfo)172 bool CpuProfiler::StopCpuProfilerForInfo(std::unique_ptr<struct ProfileInfo> &profileInfo)
173 {
174     LOG_ECMA(INFO) << "CpuProfiler::StopCpuProfilerForInfo enter";
175     if (!isProfiling_) {
176         LOG_ECMA(WARN) << "CpuProfiler::StopCpuProfilerForInfo, not isProfiling_";
177         return true;
178     }
179     if (outToFile_) {
180         LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForInfo, is outToFile_";
181         return false;
182     }
183     generator_->SetIsStart(false);
184     if (generator_->SemPost(0) != 0) {
185         LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForInfo, sem_[0] post failed, errno = " << errno;
186         return false;
187     }
188     if (generator_->SemWait(1) != 0) {
189         LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForInfo, sem_[1] wait failed, errno = " << errno;
190         return false;
191     }
192     isProfiling_ = false;
193     vm_->GetJSThread()->SetIsProfiling(false);
194     profileInfo = generator_->GetProfileInfo();
195     return true;
196 }
197 
SetCpuSamplingInterval(int interval)198 void CpuProfiler::SetCpuSamplingInterval(int interval)
199 {
200     interval_ = static_cast<uint32_t>(interval);
201 }
202 
StopCpuProfilerForFile()203 bool CpuProfiler::StopCpuProfilerForFile()
204 {
205     LOG_ECMA(INFO) << "CpuProfiler::StopCpuProfilerForFile enter";
206     if (!isProfiling_) {
207         LOG_ECMA(WARN) << "CpuProfiler::StopCpuProfilerForFile, not isProfiling_";
208         return true;
209     }
210     if (!outToFile_) {
211         LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForFile, not outToFile_";
212         return false;
213     }
214     generator_->SetIsStart(false);
215     if (generator_->SemPost(0) != 0) {
216         LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForFile, sem_[0] post failed, errno = " << errno;
217         return false;
218     }
219     if (generator_->SemWait(1) != 0) {
220         LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForFile, sem_[1] wait failed, errno = " << errno;
221         return false;
222     }
223     isProfiling_ = false;
224     vm_->GetJSThread()->SetIsProfiling(false);
225     generator_->StringifySampleData();
226     std::string fileData = generator_->GetSampleData();
227     generator_->fileHandle_ << fileData;
228     return true;
229 }
230 
~CpuProfiler()231 CpuProfiler::~CpuProfiler()
232 {
233     if (generator_->SemDestroy(0) != 0) {
234         LOG_ECMA(ERROR) << "sem_[0] destroy failed";
235     }
236     if (generator_->SemDestroy(1) != 0) {
237         LOG_ECMA(ERROR) << "sem_[1] destroy failed";
238     }
239     if (generator_->SemDestroy(2) != 0) { // 2: signal 2
240         LOG_ECMA(ERROR) << "sem_[2] destroy failed";
241     }
242     if (generator_ != nullptr) {
243         delete generator_;
244         generator_ = nullptr;
245     }
246     if (params_ != nullptr) {
247         delete params_;
248         params_ = nullptr;
249     }
250 }
251 
GetStack(FrameIterator & it)252 void CpuProfiler::GetStack(FrameIterator &it)
253 {
254     const CMap<struct MethodKey, struct FrameInfo> &stackInfo = generator_->GetStackInfo();
255     bool topFrame = true;
256     generator_->ResetFrameLength();
257     for (; !it.Done(); it.Advance<>()) {
258         auto method = it.CheckAndGetMethod();
259         if (method == nullptr || !JSTaggedValue(method).IsMethod()) {
260             continue;
261         }
262         bool isNative = method->IsNativeWithCallField();
263         struct MethodKey methodKey;
264         methodKey.deoptType = method->GetDeoptType();
265         if (topFrame) {
266             methodKey.state = JsStackGetter::GetRunningState(it, vm_, isNative, true, enableVMTag_);
267             topFrame = false;
268         } else {
269             methodKey.state = JsStackGetter::GetRunningState(it, vm_, isNative, false, enableVMTag_);
270         }
271         if (isNative) {
272             JsStackGetter::GetCallLineNumber(it, vm_, methodKey.lineNumber);
273         }
274         void *methodIdentifier = JsStackGetter::GetMethodIdentifier(method, it, vm_);
275         if (methodIdentifier == nullptr) {
276             continue;
277         }
278         methodKey.methodIdentifier = methodIdentifier;
279         if (stackInfo.count(methodKey) == 0) {
280             struct FrameInfoTemp codeEntry;
281             if (UNLIKELY(!JsStackGetter::ParseMethodInfo(methodKey, it, vm_, codeEntry, true))) {
282                 continue;
283             }
284             if (UNLIKELY(!generator_->PushStackInfo(codeEntry))) {
285                 return;
286             }
287         }
288         if (UNLIKELY(!generator_->PushFrameStack(methodKey))) {
289             return;
290         }
291     }
292     generator_->PostFrame();
293 }
294 
GetStackBeforeCallNapi(JSThread * thread)295 bool CpuProfiler::GetStackBeforeCallNapi(JSThread *thread)
296 {
297     uint64_t tempTimeStamp = SamplingProcessor::GetMicrosecondsTimeStamp();
298     if (tempTimeStamp - beforeCallNapiTimeStamp_ < interval_) {
299         return false;
300     }
301 
302     if (GetStackCallNapi(thread, true)) {
303         beforeCallNapiTimeStamp_ = tempTimeStamp;
304         return true;
305     }
306     return false;
307 }
308 
GetStackAfterCallNapi(JSThread * thread)309 void CpuProfiler::GetStackAfterCallNapi(JSThread *thread)
310 {
311     GetStackCallNapi(thread, false);
312 }
313 
GetStackCallNapi(JSThread * thread,bool beforeCallNapi)314 bool CpuProfiler::GetStackCallNapi(JSThread *thread, bool beforeCallNapi)
315 {
316     [[maybe_unused]] CallNapiScope scope(this);
317     const CMap<struct MethodKey, struct FrameInfo> &stackInfo = generator_->GetStackInfo();
318     generator_->ClearNapiStack();
319     bool topFrame = true;
320     auto currentFrame = const_cast<JSTaggedType *>(thread->GetCurrentFrame());
321     FrameIterator it(currentFrame, thread);
322     if (!beforeCallNapi) {
323         it.Advance<GCVisitedFlag::IGNORED>();
324     }
325     for (; !it.Done(); it.Advance<GCVisitedFlag::IGNORED>()) {
326         auto method = it.CheckAndGetMethod();
327         if (method == nullptr || !JSTaggedValue(method).IsMethod()) {
328             continue;
329         }
330 
331         bool isNative = method->IsNativeWithCallField();
332         struct MethodKey methodKey;
333         methodKey.deoptType = method->GetDeoptType();
334         if (topFrame) {
335             if (beforeCallNapi) {
336                 methodKey.state = RunningState::NAPI;
337             } else {
338                 methodKey.state = JsStackGetter::GetRunningState(it, vm_, isNative, true, enableVMTag_);
339             }
340             topFrame = false;
341         } else {
342             methodKey.state = JsStackGetter::GetRunningState(it, vm_, isNative, false, enableVMTag_);
343         }
344         if (isNative) {
345             JsStackGetter::GetCallLineNumber(it, vm_, methodKey.lineNumber);
346         }
347         void *methodIdentifier = JsStackGetter::GetMethodIdentifier(method, it, vm_);
348         if (methodIdentifier == nullptr) {
349             continue;
350         }
351         methodKey.methodIdentifier = methodIdentifier;
352         if (stackInfo.count(methodKey) == 0) {
353             struct FrameInfoTemp codeEntry;
354             if (UNLIKELY(!JsStackGetter::ParseMethodInfo(methodKey, it, vm_, codeEntry, true))) {
355                 continue;
356             }
357             if (UNLIKELY(!generator_->PushNapiStackInfo(codeEntry))) {
358                 return false;
359             }
360         }
361         if (UNLIKELY(!generator_->PushNapiFrameStack(methodKey))) {
362             return false;
363         }
364     }
365     generator_->PostNapiFrame();
366     return true;
367 }
368 
GetStackSignalHandler(int signal,siginfo_t * siginfo,void * context)369 void CpuProfiler::GetStackSignalHandler(int signal, [[maybe_unused]] siginfo_t *siginfo, void *context)
370 {
371     if (signal != SIGPROF) {
372         return;
373     }
374     CpuProfiler *profiler = nullptr;
375     JSThread *thread = nullptr;
376     {
377         LockHolder lock(synchronizationMutex_);
378         // If no task running in this thread, we get the id of the last task that ran in this thread
379         pthread_t tid = static_cast<pthread_t>(GetThreadIdOrCachedTaskId());
380         const EcmaVM *vm = profilerMap_[tid].vm_;
381         if (vm == nullptr) {
382             LOG_ECMA(ERROR) << "CpuProfiler GetStackSignalHandler vm is nullptr";
383             return;
384         }
385         profiler = vm->GetProfiler();
386         thread = vm->GetAssociatedJSThread();
387         if (profiler == nullptr) {
388             LOG_ECMA(ERROR) << "CpuProfiler GetStackSignalHandler profiler is nullptr";
389             return;
390         }
391     }
392     [[maybe_unused]] SignalStateScope scope(thread->GetEcmaVM()->GetJsDebuggerManager());
393 
394     if (profiler->GetBuildNapiStack() || thread->GetGcState()) {
395         if (profiler->generator_->SemPost(0) != 0) {
396             LOG_ECMA(ERROR) << "sem_[0] post failed";
397         }
398         return;
399     }
400 
401     uint64_t pc = 0;
402     if (thread->IsAsmInterpreter()) {
403         // If the attempt fails, the callback will be terminated directly to avoid the reentrancy deadlock,
404         // and a sampling will be abandoned. Failures are rare, so the impact on the overall sampling results
405         // is very limited.
406         if (!thread->GetEcmaVM()->GetAOTFileManager()->TryReadLock()) {
407             if (profiler->generator_->SemPost(0) != 0) {
408                 LOG_ECMA(ERROR) << "sem_[0] post failed";
409             }
410             return;
411         }
412         pc = GetPcFromContext(context);
413     }
414     if (thread->IsAsmInterpreter() && profiler->IsAddrAtStubOrAot(pc) &&
415         !profiler->IsEntryFrameHeaderOrTail(thread, pc)) {
416         if (profiler->IfNeedSkipBarrierStubHeaderOrTail(thread, pc)) {
417             return;
418         }
419         [[maybe_unused]] ucontext_t *ucontext = reinterpret_cast<ucontext_t*>(context);
420         [[maybe_unused]] mcontext_t &mcontext = ucontext->uc_mcontext;
421         [[maybe_unused]] void *fp = nullptr;
422         [[maybe_unused]] void *sp = nullptr;
423 #if defined(PANDA_TARGET_AMD64)
424         fp = reinterpret_cast<void*>(mcontext.gregs[REG_RBP]);
425         sp = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]);
426 #elif defined(PANDA_TARGET_ARM64)
427         fp = reinterpret_cast<void*>(mcontext.regs[29]); // FP is an alias for x29.
428         sp = reinterpret_cast<void*>(mcontext.sp);
429 #else
430         LOG_FULL(FATAL) << "AsmInterpreter does not currently support other platforms, please run on x64 and arm64";
431         return;
432 #endif
433         if (reinterpret_cast<uint64_t*>(sp) > reinterpret_cast<uint64_t*>(fp)) {
434             LOG_ECMA(ERROR) << "sp > fp, stack frame exception";
435             if (profiler->generator_->SemPost(0) != 0) {
436                 LOG_ECMA(ERROR) << "sem_[0] post failed";
437             }
438             return;
439         }
440         if (JsStackGetter::CheckFrameType(thread, reinterpret_cast<JSTaggedType *>(fp))) {
441             FrameIterator it(reinterpret_cast<JSTaggedType *>(fp), thread);
442             profiler->GetStack(it);
443         }
444     } else if (thread->IsAsmInterpreter()) {
445         if (thread->GetLastLeaveFrame() != nullptr) {
446             JSTaggedType *leaveFrame = const_cast<JSTaggedType *>(thread->GetLastLeaveFrame());
447             if (JsStackGetter::CheckFrameType(thread, leaveFrame)) {
448                 FrameIterator it(leaveFrame, thread);
449                 profiler->GetStack(it);
450             }
451         }
452     } else {
453         if (thread->GetCurrentFrame() != nullptr) {
454             if (JsStackGetter::CheckFrameType(thread, const_cast<JSTaggedType *>(thread->GetCurrentFrame()))) {
455                 FrameHandler frameHandler(thread);
456                 FrameIterator it(frameHandler.GetSp(), thread);
457                 profiler->GetStack(it);
458             }
459         }
460     }
461     if (profiler->generator_->SemPost(0) != 0) {
462         LOG_ECMA(ERROR) << "sem_[0] post failed";
463         return;
464     }
465 }
466 
InHeaderOrTail(uint64_t pc,uint64_t entryBegin,uint64_t entryDuration,uint64_t headerSize,uint64_t tailSize) const467 bool CpuProfiler::InHeaderOrTail(uint64_t pc, uint64_t entryBegin, uint64_t entryDuration, uint64_t headerSize,
468                                  uint64_t tailSize) const
469 {
470     uintptr_t entryEnd = entryBegin + entryDuration;
471     if (pc >= entryBegin && pc <= (entryBegin + headerSize)) {
472         return true;
473     }
474     if (pc <= entryEnd && pc >= (entryEnd - tailSize)) {
475         return true;
476     }
477     return false;
478 }
479 
IfNeedSkipBarrierStubHeaderOrTail(JSThread * thread,uint64_t pc) const480 bool CpuProfiler::IfNeedSkipBarrierStubHeaderOrTail(JSThread *thread, uint64_t pc) const
481 {
482     uint64_t headerSize = 20;
483     uintptr_t entryBegin = thread->GetFastStubEntry(kungfu::CommonStubCSigns::ID::GetValueWithBarrier);
484     bool needSkip = InHeaderOrTail(pc, entryBegin, 0, headerSize, 0);
485     return needSkip;
486 }
487 
IsEntryFrameHeaderOrTail(JSThread * thread,uint64_t pc) const488 bool CpuProfiler::IsEntryFrameHeaderOrTail(JSThread *thread, uint64_t pc) const
489 {
490     uint64_t headerSize = 0;
491     uint64_t tailSize = 0;
492     uint64_t entryDuration = 0;
493     Assembler::GetFrameCompletionPos(headerSize, tailSize, entryDuration);
494     uintptr_t entryBegin = thread->GetRTInterface(kungfu::RuntimeStubCSigns::ID_AsmInterpreterEntry);
495     bool inAsmInterpreterEntry = InHeaderOrTail(pc, entryBegin, entryDuration, headerSize, tailSize);
496     entryBegin = thread->GetRTInterface(kungfu::RuntimeStubCSigns::ID_GeneratorReEnterAsmInterp);
497     bool inGeneratorReEnterAsmInterp = InHeaderOrTail(pc, entryBegin, entryDuration, headerSize, tailSize);
498     return (inAsmInterpreterEntry || inGeneratorReEnterAsmInterp);
499 }
500 
GetPcFromContext(void * context)501 uint64_t CpuProfiler::GetPcFromContext(void *context)
502 {
503     [[maybe_unused]] ucontext_t *ucontext = reinterpret_cast<ucontext_t*>(context);
504     [[maybe_unused]] mcontext_t &mcontext = ucontext->uc_mcontext;
505     uint64_t pc = 0;
506 #if defined(PANDA_TARGET_AMD64)
507     pc = static_cast<uint64_t>(mcontext.gregs[REG_RIP]);
508 #elif defined(PANDA_TARGET_ARM64)
509     pc = static_cast<uint64_t>(mcontext.pc);
510 #else
511     LOG_FULL(FATAL) << "AsmInterpreter does not currently support other platforms, please run on x64 and arm64";
512     pc = 0;
513 #endif
514     return pc;
515 }
516 
IsAddrAtStubOrAot(uint64_t pc) const517 bool CpuProfiler::IsAddrAtStubOrAot(uint64_t pc) const
518 {
519     AOTFileManager *loader = vm_->GetAOTFileManager();
520     return loader->InsideStub(pc) || loader->InsideAOT(pc);
521 }
522 
CheckFileName(const std::string & fileName,std::string & absoluteFilePath) const523 bool CpuProfiler::CheckFileName(const std::string &fileName, std::string &absoluteFilePath) const
524 {
525     if (fileName.empty()) {
526         LOG_ECMA(ERROR) << "CpuProfiler::CheckFileName, fileName is empty";
527         return false;
528     }
529 
530     if (fileName.size() > PATH_MAX) {
531         LOG_ECMA(ERROR) << "CpuProfiler::CheckFileName, fileName exceed PATH_MAX";
532         return false;
533     }
534 
535     CVector<char> resolvedPath(PATH_MAX);
536     auto result = realpath(fileName.c_str(), resolvedPath.data());
537     if (result == nullptr) {
538         LOG_ECMA(ERROR) << "CpuProfiler::CheckFileName, realpath fail, errno = " << errno;
539         return false;
540     }
541     std::ofstream file(resolvedPath.data());
542     if (!file.good()) {
543         LOG_ECMA(ERROR) << "CpuProfiler::CheckFileName, file is not good, errno = " << errno;
544         return false;
545     }
546     file.close();
547     absoluteFilePath = resolvedPath.data();
548     return true;
549 }
550 
SetBuildNapiStack(bool flag)551 void CpuProfiler::SetBuildNapiStack(bool flag)
552 {
553     isBuildNapiStack_.store(flag);
554 }
555 
GetBuildNapiStack()556 bool CpuProfiler::GetBuildNapiStack()
557 {
558     return isBuildNapiStack_.load();
559 }
560 
GetOutToFile()561 bool CpuProfiler::GetOutToFile()
562 {
563     return outToFile_;
564 }
565 
GetVmbyTid(pthread_t tid)566 EcmaVM* CpuProfiler::GetVmbyTid(pthread_t tid)
567 {
568     LockHolder lock(synchronizationMutex_);
569     return const_cast<EcmaVM *>(profilerMap_[tid].vm_);
570 }
571 } // namespace panda::ecmascript
572