• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2025 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 <gtest/gtest.h>
17 
18 #include <cstdio>
19 #include <malloc.h>
20 #include <map>
21 #include <securec.h>
22 #include <thread>
23 #include <unistd.h>
24 
25 #include "dfx_frame_formatter.h"
26 #include "dfx_ptrace.h"
27 #include "dfx_regs_get.h"
28 #include "dfx_test_util.h"
29 #include "elapsed_time.h"
30 #include "unwinder.h"
31 
32 #if defined(__x86_64__)
33 #include <unwind.h> // GCC's internal unwinder, part of libgcc
34 #endif
35 
36 using namespace testing;
37 using namespace testing::ext;
38 
39 namespace OHOS {
40 namespace HiviewDFX {
41 #undef LOG_DOMAIN
42 #undef LOG_TAG
43 #define LOG_TAG "DfxUnwinderTest"
44 #define LOG_DOMAIN 0xD002D11
45 #define TIME_SLEEP 3
46 
47 class UnwinderTest : public testing::Test {
48 public:
SetUpTestCase()49     static void SetUpTestCase() {}
TearDownTestCase()50     static void TearDownTestCase() {}
SetUp()51     void SetUp() {}
TearDown()52     void TearDown() {}
53 
54     std::map<int, std::shared_ptr<Unwinder>> unwinders_;
55     const size_t skipFrameNum = 2;
56 };
57 
58 /**
59  * @tc.name: GetStackRangeTest001
60  * @tc.desc: test unwinder GetStackRange interface in pid == tid
61  * @tc.type: FUNC
62  */
63 HWTEST_F(UnwinderTest, GetStackRangeTest001, TestSize.Level2)
64 {
65     GTEST_LOG_(INFO) << "GetStackRangeTest001: start.";
66     auto unwinder = std::make_shared<Unwinder>();
67     uintptr_t stackBottom = 1;
68     uintptr_t stackTop = static_cast<uintptr_t>(-1);
69     GTEST_LOG_(INFO) << "when pid == tid and maps_ != null, GetStackRange(stackBottom, stackTop) is true";
70     ASSERT_TRUE(unwinder->GetStackRange(stackBottom, stackTop));
71     // When the param is less than -1, maps_ = null when method Unwinder is constructed
72     auto unwinderNegative = std::make_shared<Unwinder>(-2);
73     GTEST_LOG_(INFO) << "when pid == tid and maps_ == null, GetStackRange(stackBottom, stackTop) is false";
74     ASSERT_TRUE(unwinderNegative->GetStackRange(stackBottom, stackTop));
75     GTEST_LOG_(INFO) << "GetStackRangeTest001: end.";
76 }
77 
78 /**
79  * @tc.name: GetStackRangeTest002
80  * @tc.desc: test unwinder GetStackRange interface in pid != tid
81  * @tc.type: FUNC
82  */
83 HWTEST_F(UnwinderTest, GetStackRangeTest002, TestSize.Level2)
84 {
85     GTEST_LOG_(INFO) << "GetStackRangeTest002: start.";
86     auto unwinder = std::make_shared<Unwinder>();
87     uintptr_t stackBottom = 1;
88     uintptr_t stackTop = static_cast<uintptr_t>(-1);
89     bool result = false;
90     GTEST_LOG_(INFO) << "Run the function with thread will get pid != tid, "
91                         "GetStackRange(stackBottom, stackTop) is true";
__anon7b98447f0102null92     std::thread th([unwinder, &stackBottom, &stackTop, &result] {
93         result = unwinder->GetStackRange(stackBottom, stackTop);
94     });
95     if (th.joinable()) {
96         th.join();
97     }
98     ASSERT_TRUE(result);
99     GTEST_LOG_(INFO) << "GetStackRangeTest002: end.";
100 }
101 
102 /**
103  * @tc.name: UnwinderLocalTest001
104  * @tc.desc: test unwinder local unwind
105  * @tc.type: FUNC
106  */
107 HWTEST_F(UnwinderTest, UnwinderLocalTest001, TestSize.Level2)
108 {
109     GTEST_LOG_(INFO) << "UnwinderLocalTest001: start.";
110     auto unwinder = std::make_shared<Unwinder>();
111     ElapsedTime counter;
112     MAYBE_UNUSED bool unwRet = unwinder->UnwindLocal();
113     time_t elapsed1 = counter.Elapsed();
114     EXPECT_EQ(true, unwRet) << "UnwinderLocalTest001: Unwind:" << unwRet;
115     auto frames = unwinder->GetFrames();
116     ASSERT_GT(frames.size(), 1);
117     time_t elapsed2 = counter.Elapsed();
118     GTEST_LOG_(INFO) << "Elapsed-: " << elapsed1 << "\tElapsed+: " << elapsed2;
119     GTEST_LOG_(INFO) << "UnwinderLocalTest001: frames:\n" << Unwinder::GetFramesStr(frames);
120     unwRet = unwinder->UnwindLocal(false, false, DEFAULT_MAX_FRAME_NUM, skipFrameNum);
121     EXPECT_EQ(true, unwRet) << "UnwinderLocalTest001: Unwind:" << unwRet;
122     auto frames2 = unwinder->GetFrames();
123     ASSERT_GT(frames.size(), frames2.size());
124     GTEST_LOG_(INFO) << "UnwinderLocalTest001: frames2:\n" << Unwinder::GetFramesStr(frames2);
125     GTEST_LOG_(INFO) << "UnwinderLocalTest001: end.";
126 }
127 
128 /**
129  * @tc.name: UnwinderLocalTest002
130  * @tc.desc: test unwinder local unwind n counts
131  * @tc.type: FUNC
132  */
133 HWTEST_F(UnwinderTest, UnwinderLocalTest002, TestSize.Level2)
134 {
135     GTEST_LOG_(INFO) << "UnwinderLocalTest002: start.";
136     unwinders_.clear();
137     std::shared_ptr<Unwinder> unwinder = nullptr;
138     pid_t pid = getpid();
139     GTEST_LOG_(INFO) << "pid: " << pid;
140     for (int i = 0; i < 10; ++i) {
141         auto it = unwinders_.find(pid);
142         if (it != unwinders_.end()) {
143             unwinder = it->second;
144         } else {
145             unwinder = std::make_shared<Unwinder>();
146         }
147         ElapsedTime counter;
148         MAYBE_UNUSED bool unwRet = unwinder->UnwindLocal();
149         time_t elapsed1 = counter.Elapsed();
150         EXPECT_EQ(true, unwRet) << "UnwinderLocalTest002: Unwind:" << unwRet;
151         auto frames = unwinder->GetFrames();
152         ASSERT_GT(frames.size(), 1);
153         time_t elapsed2 = counter.Elapsed();
154         GTEST_LOG_(INFO) << "Elapsed-: " << elapsed1 << "\tElapsed+: " << elapsed2;
155         GTEST_LOG_(INFO) << "UnwinderLocalTest002: frames:\n" << Unwinder::GetFramesStr(frames);
156         unwinders_[pid] = unwinder;
157         sleep(1);
158     };
159     GTEST_LOG_(INFO) << "UnwinderLocalTest002: end.";
160 }
161 
162 /**
163  * @tc.name: UnwinderLocalTest003
164  * @tc.desc: test unwinder UnwindLocal interface
165  * @tc.type: FUNC
166  */
167 HWTEST_F(UnwinderTest, UnwinderLocalTest003, TestSize.Level2)
168 {
169     GTEST_LOG_(INFO) << "UnwinderLocalTest003: start.";
170     // When the param is less than -1, maps_ = null when method Unwinder is constructed
171     auto unwinderNegative = std::make_shared<Unwinder>(-2);
172     GTEST_LOG_(INFO) << "when pid == tid and maps_ == null, "
173                          "UnwindLocal(maxFrameNum, skipFrameNum) is false";
174     ASSERT_FALSE(unwinderNegative->UnwindLocal());
175     auto unwinder = std::make_shared<Unwinder>();
176     GTEST_LOG_(INFO) << "when pid == tid and maps_ != null, "
177                         "UnwindLocal(maxFrameNum, skipFrameNum) is true";
178     ASSERT_TRUE(unwinder->UnwindLocal());
179     GTEST_LOG_(INFO) << "UnwinderLocalTest003: end.";
180 }
181 
182 /**
183  * @tc.name: UnwinderRemoteTest001
184  * @tc.desc: test unwinder remote unwind
185  * @tc.type: FUNC
186  */
187 HWTEST_F(UnwinderTest, UnwinderRemoteTest001, TestSize.Level2)
188 {
189     GTEST_LOG_(INFO) << "UnwinderRemoteTest001: start.";
190     pid_t child = fork();
191     if (child == 0) {
192         sleep(TIME_SLEEP);
193         _exit(0);
194     }
195 
196     GTEST_LOG_(INFO) << "pid: " << child << ", ppid:" << getpid();
197     auto unwinder = std::make_shared<Unwinder>(child);
198     bool unwRet = DfxPtrace::Attach(child);
199     EXPECT_EQ(true, unwRet) << "UnwinderRemoteTest001: Attach:" << unwRet;
200     ElapsedTime counter;
201     unwRet = unwinder->UnwindRemote(child);
202     time_t elapsed1 = counter.Elapsed();
203     EXPECT_EQ(true, unwRet) << "UnwinderRemoteTest001: unwRet:" << unwRet;
204     auto frames = unwinder->GetFrames();
205     ASSERT_GT(frames.size(), 1);
206     time_t elapsed2 = counter.Elapsed();
207     GTEST_LOG_(INFO) << "Elapsed-: " << elapsed1 << "\tElapsed+: " << elapsed2;
208     GTEST_LOG_(INFO) << "UnwinderRemoteTest001: frames:\n" << Unwinder::GetFramesStr(frames);
209     unwRet = unwinder->UnwindRemote(child, false, DEFAULT_MAX_FRAME_NUM, skipFrameNum);
210     EXPECT_EQ(true, unwRet) << "UnwinderRemoteTest001: unwRet:" << unwRet;
211     auto frames2 = unwinder->GetFrames();
212     ASSERT_GT(frames.size(), frames2.size());
213     GTEST_LOG_(INFO) << "UnwinderRemoteTest001: frames2:\n" << Unwinder::GetFramesStr(frames2);
214     DfxPtrace::Detach(child);
215     GTEST_LOG_(INFO) << "UnwinderRemoteTest001: end.";
216 }
217 
218 /**
219  * @tc.name: UnwinderRemoteTest002
220  * @tc.desc: test unwinder remote unwind n counts
221  * @tc.type: FUNC
222  */
223 HWTEST_F(UnwinderTest, UnwinderRemoteTest002, TestSize.Level2)
224 {
225     GTEST_LOG_(INFO) << "UnwinderRemoteTest002: start.";
226     pid_t child = fork();
227     if (child == 0) {
228         sleep(TIME_SLEEP);
229         _exit(0);
230     }
231 
232     GTEST_LOG_(INFO) << "pid: " << child << ", ppid:" << getpid();
233     unwinders_.clear();
234     std::shared_ptr<Unwinder> unwinder = nullptr;
235     bool unwRet = DfxPtrace::Attach(child);
236     EXPECT_EQ(true, unwRet) << "UnwinderRemoteTest002: Attach:" << unwRet;
237     for (int i = 0; i < 10; ++i) {
238         auto it = unwinders_.find(child);
239         if (it != unwinders_.end()) {
240             unwinder = it->second;
241         } else {
242             unwinder = std::make_shared<Unwinder>(child);
243         }
244         ElapsedTime counter;
245         unwRet = unwinder->UnwindRemote(child);
246         time_t elapsed1 = counter.Elapsed();
247         EXPECT_EQ(true, unwRet) << "UnwinderRemoteTest002: Unwind:" << unwRet;
248         auto frames = unwinder->GetFrames();
249         ASSERT_GT(frames.size(), 1);
250         time_t elapsed2 = counter.Elapsed();
251         GTEST_LOG_(INFO) << "Elapsed-: " << elapsed1 << "\tElapsed+: " << elapsed2;
252         GTEST_LOG_(INFO) << "UnwinderRemoteTest002: frames:\n" << Unwinder::GetFramesStr(frames);
253         unwinders_[child] = unwinder;
254         sleep(1);
255     }
256     DfxPtrace::Detach(child);
257     GTEST_LOG_(INFO) << "UnwinderRemoteTest002: end.";
258 }
259 
260 /**
261  * @tc.name: UnwinderRemoteTest003
262  * @tc.desc: test unwinder UnwindRemote interface
263  * @tc.type: FUNC
264  */
265 HWTEST_F(UnwinderTest, UnwinderRemoteTest003, TestSize.Level2)
266 {
267     GTEST_LOG_(INFO) << "UnwinderRemoteTest003: start.";
268     // When the param is less than -1, pid_ < 0 when method Unwinder is constructed
269     auto unwinderNegative = std::make_shared<Unwinder>(-2);
270     size_t maxFrameNum = 64;
271     size_t skipFrameNum = 0;
272     GTEST_LOG_(INFO) << "when pid <= 0, UnwindRemote(maxFrameNum, skipFrameNum) is false";
273     ASSERT_FALSE(unwinderNegative->UnwindRemote(-2, maxFrameNum, skipFrameNum));
274     GTEST_LOG_(INFO) << "UnwinderRemoteTest003: end.";
275 }
276 
277 /**
278  * @tc.name: UnwindTest001
279  * @tc.desc: test unwinder unwind interface in remote case
280  * @tc.type: FUNC
281  */
282 HWTEST_F(UnwinderTest, UnwindTest001, TestSize.Level2)
283 {
284     GTEST_LOG_(INFO) << "UnwindTest001: start.";
285     pid_t child = fork();
286     if (child == 0) {
287         sleep(TIME_SLEEP);
288         _exit(0);
289     }
290 
291     GTEST_LOG_(INFO) << "pid: " << child << ", ppid:" << getpid();
292     auto unwinder = std::make_shared<Unwinder>(child);
293     bool unwRet = DfxPtrace::Attach(child);
294     EXPECT_EQ(true, unwRet) << "UnwindTest001: Attach:" << unwRet;
295     auto regs = DfxRegs::CreateRemoteRegs(child);
296     unwinder->SetRegs(regs);
297     auto maps = DfxMaps::Create(child);
298     UnwindContext context;
299     context.pid = child;
300     context.regs = regs;
301     context.maps = maps;
302     ElapsedTime counter;
303     unwRet = unwinder->Unwind(&context);
304     time_t elapsed1 = counter.Elapsed();
305     EXPECT_EQ(true, unwRet) << "UnwindTest001: Unwind:" << unwRet;
306     auto frames = unwinder->GetFrames();
307     ASSERT_GT(frames.size(), 1);
308     time_t elapsed2 = counter.Elapsed();
309     GTEST_LOG_(INFO) << "Elapsed-: " << elapsed1 << "\tElapsed+: " << elapsed2;
310     GTEST_LOG_(INFO) << "UnwindTest001: frames:\n" << Unwinder::GetFramesStr(frames);
311     DfxPtrace::Detach(child);
312     GTEST_LOG_(INFO) << "UnwindTest001: end.";
313 }
314 
315 /**
316  * @tc.name: UnwindTest002
317  * @tc.desc: test unwinder unwind interface in local case
318  * @tc.type: FUNC
319  */
320 HWTEST_F(UnwinderTest, UnwindTest002, TestSize.Level2)
321 {
322     GTEST_LOG_(INFO) << "UnwindTest002: start.";
323     auto unwinder = std::make_shared<Unwinder>();
324     uintptr_t stackBottom = 1, stackTop = static_cast<uintptr_t>(-1);
325     ASSERT_TRUE(unwinder->GetStackRange(stackBottom, stackTop));
326     GTEST_LOG_(INFO) << "UnwindTest002: GetStackRange.";
327     UnwindContext context;
328     context.stackCheck = false;
329     context.stackBottom = stackBottom;
330     context.stackTop = stackTop;
331 
332     auto regs = DfxRegs::Create();
333     auto regsData = regs->RawData();
334     GetLocalRegs(regsData);
335     unwinder->SetRegs(regs);
336     auto maps = DfxMaps::Create(getpid());
337     context.pid = UNWIND_TYPE_LOCAL;
338     context.regs = regs;
339     context.maps = maps;
340     bool unwRet = unwinder->Unwind(&context);
341     EXPECT_EQ(true, unwRet) << "UnwindTest002: unwRet:" << unwRet;
342     auto frames = unwinder->GetFrames();
343     ASSERT_GT(frames.size(), 1);
344     GTEST_LOG_(INFO) << "UnwindTest002:frames:\n" << Unwinder::GetFramesStr(frames);
345     GTEST_LOG_(INFO) << "UnwindTest002: end.";
346 }
347 
348 /**
349  * @tc.name: UnwindTest003
350  * @tc.desc: test GetLastErrorCode GetLastErrorAddr functions
351  *  in local case
352  * @tc.type: FUNC
353  */
354 HWTEST_F(UnwinderTest, UnwindTest003, TestSize.Level2)
355 {
356     GTEST_LOG_(INFO) << "UnwindTest003: start.";
357 
358     auto unwinder = std::make_shared<Unwinder>();
359     unwinder->IgnoreMixstack(true);
360     MAYBE_UNUSED bool unwRet = unwinder->UnwindLocal();
361     EXPECT_EQ(true, unwRet) << "UnwindTest003: Unwind ret:" << unwRet;
362     unwinder->EnableFillFrames(false);
363     const auto& frames = unwinder->GetFrames();
364     ASSERT_GT(frames.size(), 1) << "frames.size() error";
365 
366     uint16_t errorCode = unwinder->GetLastErrorCode();
367     uint64_t errorAddr = unwinder->GetLastErrorAddr();
368     GTEST_LOG_(INFO) << "errorCode:" << errorCode;
369     GTEST_LOG_(INFO) << "errorAddr:" << errorAddr;
370     GTEST_LOG_(INFO) << "UnwindTest003: end.";
371 }
372 
373 /**
374  * @tc.name: UnwindTest004
375  * @tc.desc: test unwinder local unwind for
376  * GetFramesStr(const std::vector<std::shared_ptr<DfxFrame>>& frames)
377  * @tc.type: FUNC
378  */
379 HWTEST_F(UnwinderTest, UnwindTest004, TestSize.Level2)
380 {
381     GTEST_LOG_(INFO) << "UnwindTest004: start.";
382 
383     auto unwinder = std::make_shared<Unwinder>();
384     ElapsedTime counter;
385     MAYBE_UNUSED bool unwRet = unwinder->UnwindLocal();
386     ASSERT_EQ(true, unwRet) << "UnwindTest004: Unwind:" << unwRet;
387     auto frames = unwinder->GetFrames();
388     ASSERT_GT(frames.size(), 1);
389 
390     std::string framesStr = DfxFrameFormatter::GetFramesStr(frames);
391     GTEST_LOG_(INFO) << "UnwindTest004: frames:\n" << framesStr;
392 
393     string log[] = {"pc", "test_unwind", "#00", "#01", "#02"};
394     int len = sizeof(log) / sizeof(log[0]);
395     int count = GetKeywordsNum(framesStr, log, len);
396     ASSERT_EQ(count, len) << "UnwindTest004 Failed";
397     GTEST_LOG_(INFO) << "UnwindTest004: end.";
398 }
399 
400 /**
401  * @tc.name: StepTest001
402  * @tc.desc: test unwinder Step interface in remote case
403  * @tc.type: FUNC
404  */
405 HWTEST_F(UnwinderTest, StepTest001, TestSize.Level2)
406 {
407     GTEST_LOG_(INFO) << "StepTest001: start.";
408     pid_t child = fork();
409     if (child == 0) {
410         sleep(TIME_SLEEP);
411         _exit(0);
412     }
413 
414     GTEST_LOG_(INFO) << "pid: " << child << ", ppid:" << getpid();
415     auto unwinder = std::make_shared<Unwinder>(child);
416     bool unwRet = DfxPtrace::Attach(child);
417     EXPECT_EQ(true, unwRet) << "StepTest001: Attach:" << unwRet;
418     auto regs = DfxRegs::CreateRemoteRegs(child);
419     auto maps = DfxMaps::Create(child);
420     unwinder->SetRegs(regs);
421     UnwindContext context;
422     context.pid = child;
423     context.regs = regs;
424     context.maps = maps;
425 
426     uintptr_t pc, sp;
427     pc = regs->GetPc();
428     sp = regs->GetSp();
429     std::shared_ptr<DfxMap> map = nullptr;
430     ASSERT_TRUE(maps->FindMapByAddr(pc, map));
431     context.map = map;
432     unwRet = unwinder->Step(pc, sp, &context);
433     ASSERT_TRUE(unwRet) << "StepTest001: Unwind:" << unwRet;
434     DfxPtrace::Detach(child);
435     GTEST_LOG_(INFO) << "StepTest001: end.";
436 }
437 
438 /**
439  * @tc.name: StepTest002
440  * @tc.desc: test unwinder Step interface in local case
441  * @tc.type: FUNC
442  */
443 HWTEST_F(UnwinderTest, StepTest002, TestSize.Level2)
444 {
445     GTEST_LOG_(INFO) << "StepTest002: start.";
446     auto unwinder = std::make_shared<Unwinder>();
447     uintptr_t stackBottom = 1, stackTop = static_cast<uintptr_t>(-1);
448     ASSERT_TRUE(unwinder->GetStackRange(stackBottom, stackTop));
449     GTEST_LOG_(INFO) << "StepTest002: GetStackRange.";
450     auto maps = DfxMaps::Create(getpid());
451     UnwindContext context;
452     context.pid = UNWIND_TYPE_LOCAL;
453     context.stackCheck = false;
454     context.stackBottom = stackBottom;
455     context.stackTop = stackTop;
456 
457     auto regs = DfxRegs::Create();
458     auto regsData = regs->RawData();
459     GetLocalRegs(regsData);
460     unwinder->SetRegs(regs);
461     context.regs = regs;
462     context.maps = maps;
463 
464     uintptr_t pc, sp;
465     pc = regs->GetPc();
466     sp = regs->GetSp();
467     bool unwRet = unwinder->Step(pc, sp, &context);
468     ASSERT_TRUE(unwRet) << "StepTest002: unwRet:" << unwRet;
469     GTEST_LOG_(INFO) << "StepTest002: end.";
470 }
471 
472 #if defined(__aarch64__)
473 /**
474  * @tc.name: StepTest003
475  * @tc.desc: test unwinder UnwindByFp interface in remote case
476  * @tc.type: FUNC
477  */
478 HWTEST_F(UnwinderTest, StepTest003, TestSize.Level2)
479 {
480     GTEST_LOG_(INFO) << "StepTest003: start.";
481     pid_t child = fork();
482     if (child == 0) {
483         sleep(TIME_SLEEP);
484         _exit(0);
485     }
486 
487     GTEST_LOG_(INFO) << "pid: " << child << ", ppid:" << getpid();
488     auto unwinder = std::make_shared<Unwinder>(child);
489     bool unwRet = DfxPtrace::Attach(child);
490     EXPECT_EQ(true, unwRet) << "StepTest003: Attach:" << unwRet;
491     auto regs = DfxRegs::CreateRemoteRegs(child);
492     unwinder->SetRegs(regs);
493     UnwindContext context;
494     context.pid = child;
495     ElapsedTime counter;
496     unwRet = unwinder->UnwindByFp(&context);
497     ASSERT_TRUE(unwRet) << "StepTest003: unwind:" << unwRet;
498     DfxPtrace::Detach(child);
499     time_t elapsed = counter.Elapsed();
500     GTEST_LOG_(INFO) << "StepTest003: Elapsed: " << elapsed;
501     auto pcs = unwinder->GetPcs();
502     std::vector<DfxFrame> frames;
503     unwinder->GetFramesByPcs(frames, pcs);
504     ASSERT_GT(frames.size(), 1);
505     GTEST_LOG_(INFO) << "StepTest003: frames:\n" << Unwinder::GetFramesStr(frames);
506     GTEST_LOG_(INFO) << "StepTest003: end.";
507 }
508 
509 /**
510  * @tc.name: StepTest004
511  * @tc.desc: test unwinder FpStep interface in local case
512  * @tc.type: FUNC
513  */
514 HWTEST_F(UnwinderTest, StepTest004, TestSize.Level2)
515 {
516     GTEST_LOG_(INFO) << "StepTest004: start.";
517     auto unwinder = std::make_shared<Unwinder>();
518     ElapsedTime counter;
519     uintptr_t stackBottom = 1, stackTop = static_cast<uintptr_t>(-1);
520     ASSERT_TRUE(unwinder->GetStackRange(stackBottom, stackTop));
521     GTEST_LOG_(INFO) << "StepTest004: GetStackRange.";
522 
523     auto regs = DfxRegs::Create();
524     auto regsData = regs->RawData();
525     GetLocalRegs(regsData);
526     UnwindContext context;
527     context.pid = UNWIND_TYPE_LOCAL;
528     context.stackCheck = false;
529     context.stackBottom = stackBottom;
530     context.stackTop = stackTop;
531     unwinder->SetRegs(regs);
532 
533     bool unwRet = unwinder->UnwindByFp(&context);
534     ASSERT_TRUE(unwRet) << "StepTest004: unwRet:" << unwRet;
535     auto unwSize = unwinder->GetPcs().size();
536     ASSERT_GT(unwSize, 1) << "pcs.size() error";
537 
538     uintptr_t miniRegs[FP_MINI_REGS_SIZE] = {0};
539     GetFramePointerMiniRegs(miniRegs, sizeof(miniRegs) / sizeof(miniRegs[0]));
540     regs = DfxRegs::CreateFromRegs(UnwindMode::FRAMEPOINTER_UNWIND, miniRegs, sizeof(miniRegs) / sizeof(miniRegs[0]));
541     unwinder->SetRegs(regs);
542     size_t idx = 0;
543     uintptr_t pc, fp;
544     while (true) {
545         pc = regs->GetPc();
546         fp = regs->GetFp();
547         idx++;
548         if (!unwinder->FpStep(fp, pc, &context) || (pc == 0)) {
549             break;
550         }
551     };
552     ASSERT_EQ(idx, unwSize) << "StepTest004: idx:" << idx;
553     time_t elapsed = counter.Elapsed();
554     GTEST_LOG_(INFO) << "StepTest004: Elapsed: " << elapsed;
555     GTEST_LOG_(INFO) << "StepTest004: end.";
556 }
557 #endif
558 
559 #if defined(__arm__) || defined(__aarch64__)
560 /**
561  * @tc.name: StepTest005
562  * @tc.desc: test unwinder Step interface in lr callback with apply failed case
563  * @tc.type: FUNC
564  */
565 HWTEST_F(UnwinderTest, StepTest005, TestSize.Level2)
566 {
567     GTEST_LOG_(INFO) << "StepTest005: start.";
568     auto unwinder = std::make_shared<Unwinder>();
569     uintptr_t stackBottom = 1, stackTop = static_cast<uintptr_t>(-1);
570     ASSERT_TRUE(unwinder->GetStackRange(stackBottom, stackTop));
571     GTEST_LOG_(INFO) << "StepTest005: GetStackRange.";
572 
573     UnwindContext context;
574     context.pid = UNWIND_TYPE_LOCAL;
575     context.stackCheck = false;
576     context.stackBottom = stackBottom;
577     context.stackTop = stackTop;
578 
579     auto regs = DfxRegs::Create();
580     auto regsData = regs->RawData();
581     GetLocalRegs(regsData);
582     unwinder->SetRegs(regs);
583     context.regs = regs;
584     context.maps = unwinder->GetMaps();
585 
586     uintptr_t lr = *(regs->GetReg(REG_LR));
587     uintptr_t pc = regs->GetPc();
588     uintptr_t failSp = stackTop + 1; // arm cfa get from sp
589     regs->SetSp(failSp);
590     uintptr_t failFp = stackTop + 1; // arm64 cfa get from fp
591     regs->SetFp(failFp);
592     bool unwRet = unwinder->Step(pc, failSp, &context);
593     ASSERT_TRUE(unwRet) << "StepTest005: unwRet:" << unwRet;
594     ASSERT_EQ(lr, pc) << "StepTest005: lr callback";
595     GTEST_LOG_(INFO) << "StepTest005: end.";
596 }
597 
598 /**
599  * @tc.name: StepTest006
600  * @tc.desc: test unwinder Step interface in lr callback with step failed case
601  * @tc.type: FUNC
602  */
603 HWTEST_F(UnwinderTest, StepTest006, TestSize.Level2)
604 {
605     GTEST_LOG_(INFO) << "StepTest006: start.";
606     auto unwinder = std::make_shared<Unwinder>();
607     uintptr_t stackBottom = 1, stackTop = static_cast<uintptr_t>(-1);
608     ASSERT_TRUE(unwinder->GetStackRange(stackBottom, stackTop));
609     GTEST_LOG_(INFO) << "StepTest006: GetStackRange.";
610 
611     UnwindContext context;
612     context.pid = UNWIND_TYPE_LOCAL;
613     context.stackCheck = true;
614     context.stackBottom = stackBottom;
615     context.stackTop = stackTop;
616 
617     auto regs = DfxRegs::Create();
618     auto regsData = regs->RawData();
619     GetLocalRegs(regsData);
620     unwinder->SetRegs(regs);
621     context.regs = regs;
622     context.maps = unwinder->GetMaps();
623 
624     uintptr_t lr = *(regs->GetReg(REG_LR));
625     uintptr_t sp = regs->GetSp();
626     uintptr_t failPc = stackTop + 1;
627     regs->SetPc(failPc);
628     bool unwRet = unwinder->Step(failPc, sp, &context);
629     ASSERT_TRUE(unwRet) << "StepTest006: unwRet:" << unwRet;
630     ASSERT_EQ(lr, failPc) << "StepTest006: lr callback";
631 
632     GTEST_LOG_(INFO) << "StepTest006: end.";
633 }
634 #endif
635 
636 /**
637  * @tc.name: FillFrameTest001
638  * @tc.desc: test unwinder FillFrame interface
639  *  in local case
640  * @tc.type: FUNC
641  */
642 HWTEST_F(UnwinderTest, FillFrameTest001, TestSize.Level2)
643 {
644     GTEST_LOG_(INFO) << "FillFrameTest001: start.";
645     auto unwinder = std::make_shared<Unwinder>();
646     DfxFrame frame;
647     unwinder->FillFrame(frame);
648     GTEST_LOG_(INFO) << " when DfxFrame::map is null, frame.buildId.size() is 0";
649     ASSERT_EQ(frame.buildId.size(), 0);
650     string testMap = "f6d83000-f6d84000 r--p 00001000 b3:07 1892 /system/lib/init/libinit_context.z.so.noexit";
651     auto map = DfxMap::Create(testMap);
652     frame.map = map;
653     unwinder->FillFrame(frame);
654     GTEST_LOG_(INFO) << " when DfxFrame::map is not null and file not exist, frame.buildId.size() is 0";
655     ASSERT_EQ(frame.buildId.size(), 0);
656 #ifdef __arm__
657     testMap = "f6d83000-f6d84000 r--p 00001000 b3:07 1892 /system/lib/init/libinit_context.z.so";
658 #else
659     testMap = "7f0ab40000-7f0ab41000 r--p 00000000 b3:07 1882 /system/lib64/init/libinit_context.z.so";
660 #endif
661     map = DfxMap::Create(testMap);
662     frame.map = map;
663     unwinder->FillFrame(frame);
664     GTEST_LOG_(INFO) << " when DfxFrame::map is not null and file exist, frame.buildId.size() is bigger than 0";
665     ASSERT_EQ(frame.buildId.size() == 0, false);
666     GTEST_LOG_(INFO) << "FillFrameTest001: end.";
667 }
668 
669 /**
670  * @tc.name: FillJsFrameTest001
671  * @tc.desc: test unwinder FillJsFrame interface
672  *  in local case
673  * @tc.type: FUNC
674  */
675 HWTEST_F(UnwinderTest, FillJsFrameTest001, TestSize.Level2)
676 {
677     GTEST_LOG_(INFO) << "FillJsFrameTest001: start.";
678     auto unwinder = std::make_shared<Unwinder>();
679     DfxFrame frame;
680     unwinder->FillJsFrame(frame);
681     GTEST_LOG_(INFO) << " when DfxFrame::map is null, frame.map is nullptr";
682     ASSERT_EQ(frame.map, nullptr);
683     string testMap = "f6d83000-f6d84000 r--p 00001000 b3:07 1892 /system/lib/init/libinit_context.z.so";
684     auto map = DfxMap::Create(testMap);
685     frame.map = map;
686     unwinder->FillJsFrame(frame);
687     GTEST_LOG_(INFO) << " when DfxFrame::map is not null and file exist, frame.map.GetHap is not nullptr";
688     ASSERT_NE(frame.map->GetHap(), nullptr);
689     GTEST_LOG_(INFO) << "FillJsFrameTest001: end.";
690 }
691 
692 /**
693  * @tc.name: FillFramesTest001
694  * @tc.desc: test unwinder FillFrames interface
695  *  in local case
696  * @tc.type: FUNC
697  */
698 HWTEST_F(UnwinderTest, FillFramesTest001, TestSize.Level2)
699 {
700     GTEST_LOG_(INFO) << "FillFramesTest001: start.";
701 #ifdef __arm__
702     const string testMap = "f6d83000-f6d84000 r--p 00001000 b3:07 1892 /system/lib/init/libinit_context.z.so";
703 #else
704     const string testMap = "7f0ab40000-7f0ab41000 r--p 00000000 b3:07 1882 /system/lib64/init/libinit_context.z.so";
705 #endif
706     auto unwinder = std::make_shared<Unwinder>();
707     std::vector<DfxFrame> frames;
708     DfxFrame frame;
709     auto map = DfxMap::Create(testMap);
710     frame.map = map;
711     frames.push_back(frame);
712     ASSERT_EQ(frames[0].buildId.size(), 0);
713     unwinder->FillFrames(frames);
714     ASSERT_EQ(frames[0].buildId.size() == 0, false);
715     GTEST_LOG_(INFO) << "FillFramesTest001: end.";
716 }
717 
718 #if defined(__arm__) || defined(__aarch64__)
719 /**
720  * @tc.name: UnwindLocalWithContextTest001
721  * @tc.desc: test unwinder UnwindLocalWithContext interface
722  *  in local case
723  * @tc.type: FUNC
724  */
725 HWTEST_F(UnwinderTest, UnwindLocalWithContextTest001, TestSize.Level2)
726 {
727     GTEST_LOG_(INFO) << "UnwindLocalWithContextTest001: start.";
728     auto regs = DfxRegs::Create();
729     auto regsData = regs->RawData();
730     GetLocalRegs(regsData);
731     ucontext_t context;
732     (void)memset_s(&context, sizeof(context), 0, sizeof(context));
733 #ifdef __arm__
734     context.uc_mcontext.arm_r0 = *(regs->GetReg(REG_ARM_R0));
735     context.uc_mcontext.arm_r1 = *(regs->GetReg(REG_ARM_R1));
736     context.uc_mcontext.arm_r2 = *(regs->GetReg(REG_ARM_R2));
737     context.uc_mcontext.arm_r3 = *(regs->GetReg(REG_ARM_R3));
738     context.uc_mcontext.arm_r4 = *(regs->GetReg(REG_ARM_R4));
739     context.uc_mcontext.arm_r5 = *(regs->GetReg(REG_ARM_R5));
740     context.uc_mcontext.arm_r6 = *(regs->GetReg(REG_ARM_R6));
741     context.uc_mcontext.arm_r7 = *(regs->GetReg(REG_ARM_R7));
742     context.uc_mcontext.arm_r8 = *(regs->GetReg(REG_ARM_R8));
743     context.uc_mcontext.arm_r9 = *(regs->GetReg(REG_ARM_R9));
744     context.uc_mcontext.arm_r10 = *(regs->GetReg(REG_ARM_R10));
745     context.uc_mcontext.arm_fp = *(regs->GetReg(REG_ARM_R11));
746     context.uc_mcontext.arm_ip = *(regs->GetReg(REG_ARM_R12));
747     context.uc_mcontext.arm_sp = *(regs->GetReg(REG_ARM_R13));
748     context.uc_mcontext.arm_lr = *(regs->GetReg(REG_ARM_R14));
749     context.uc_mcontext.arm_pc = *(regs->GetReg(REG_ARM_R15));
750 #else
751     for (int i = 0; i < REG_LAST; ++i) {
752         context.uc_mcontext.regs[i] = *(regs->GetReg(i));
753     }
754 #endif
755     auto unwinder = std::make_shared<Unwinder>();
756     ASSERT_TRUE(unwinder->UnwindLocalWithContext(context));
757     auto frames = unwinder->GetFrames();
758     ASSERT_GT(frames.size(), 1);
759     GTEST_LOG_(INFO) << "UnwindLocalWithContextTest001: frames:\n" << Unwinder::GetFramesStr(frames);
760     GTEST_LOG_(INFO) << "UnwindLocalWithContextTest001: end.";
761 }
762 #endif
763 
764 static int32_t g_tid = 0;
765 static std::mutex g_mutex;
ThreadTest002()766 __attribute__((noinline)) void ThreadTest002()
767 {
768     printf("ThreadTest002\n");
769     g_mutex.lock();
770     g_mutex.unlock();
771 }
772 
ThreadTest001()773 __attribute__((noinline)) void ThreadTest001()
774 {
775     g_tid = gettid();
776     printf("ThreadTest001: tid: %d\n", g_tid);
777     ThreadTest002();
778 }
779 
780 /**
781  * @tc.name: UnwindLocalWithTidTest001
782  * @tc.desc: test unwinder UnwindLocalWithTid interface
783  *  in local case
784  * @tc.type: FUNC
785  */
786 HWTEST_F(UnwinderTest, UnwindLocalWithTidTest001, TestSize.Level2)
787 {
788     GTEST_LOG_(INFO) << "UnwindLocalWithTidTest001: start.";
789     auto unwinder = std::make_shared<Unwinder>();
790     g_mutex.lock();
791     std::thread unwThread(ThreadTest001);
792     sleep(1);
793     if (g_tid <= 0) {
794         FAIL() << "UnwindLocalWithTidTest001: Failed to create child thread.\n";
795     }
796     ASSERT_TRUE(unwinder->UnwindLocalWithTid(g_tid));
797 #if defined(__aarch64__)
798     auto pcs = unwinder->GetPcs();
799     std::vector<DfxFrame> frames;
800     unwinder->GetFramesByPcs(frames, pcs);
801 #else
802     auto frames = unwinder->GetFrames();
803 #endif
804     ASSERT_GT(frames.size(), 1);
805     GTEST_LOG_(INFO) << "UnwindLocalWithTidTest001: frames:\n" << Unwinder::GetFramesStr(frames);
806     g_mutex.unlock();
807     g_tid = 0;
808     if (unwThread.joinable()) {
809         unwThread.join();
810     }
811     GTEST_LOG_(INFO) << "UnwindLocalWithTidTest001: end.";
812 }
813 
814 /**
815  * @tc.name: UnwindLocalWithTidTest002
816  * @tc.desc: test unwinder UnwindLocalWithTid interface
817  *  in local case
818  * @tc.type: FUNC
819  */
820 HWTEST_F(UnwinderTest, UnwindLocalWithTidTest002, TestSize.Level2)
821 {
822     GTEST_LOG_(INFO) << "UnwindLocalWithTidTest002: start.";
823     auto unwinder = std::make_shared<Unwinder>();
824     ASSERT_FALSE(unwinder->UnwindLocalWithTid(-1));
825     ASSERT_FALSE(unwinder->UnwindLocalWithTid(gettid()));
826     UnwindContext context;
827     uintptr_t pc, sp;
828     ASSERT_FALSE(unwinder->UnwindByFp(&context));
829     ASSERT_FALSE(unwinder->FpStep(pc, sp, nullptr));
830     ASSERT_FALSE(unwinder->Step(pc, sp, &context));
831     std::vector<DfxFrame> frames;
832     std::vector<uintptr_t> pcs;
833     unwinder->GetFramesByPcs(frames, pcs);
834     std::string funcName = "";
835     uint64_t funcOffset = 0;
836     ASSERT_FALSE(unwinder->GetSymbolByPc(pc, nullptr, funcName, funcOffset));
837     ASSERT_FALSE(unwinder->UnwindLocalByOtherTid(-1));
838     ASSERT_FALSE(unwinder->UnwindLocalByOtherTid(gettid()));
839     GTEST_LOG_(INFO) << "UnwindLocalWithTidTest002: end.";
840 }
841 
842 #if defined(__x86_64__)
TraceFunc(_Unwind_Context * ctx,void * d)843 static _Unwind_Reason_Code TraceFunc(_Unwind_Context *ctx, void *d)
844 {
845     int *depth = (int*)d;
846     printf("\t#%d: program counter at %p\n", *depth, reinterpret_cast<void *>(_Unwind_GetIP(ctx)));
847     (*depth)++;
848     return _URC_NO_REASON;
849 }
850 
PrintUnwindBacktrace()851 static void PrintUnwindBacktrace()
852 {
853     int depth = 0;
854     _Unwind_Backtrace(&TraceFunc, &depth);
855 }
856 
857 /**
858  * @tc.name: UnwindLocalX86_64Test001
859  * @tc.desc: test unwinder UnwindLocal interface
860  * @tc.type: FUNC
861  */
862 HWTEST_F(UnwinderTest, UnwindLocalX86_64Test001, TestSize.Level2)
863 {
864     GTEST_LOG_(INFO) << "UnwindLocalX86_64Test001: start.";
865     auto unwinder = std::make_shared<Unwinder>();
866     if (unwinder->UnwindLocal()) {
867         auto frames = unwinder->GetFrames();
868         printf("Unwinder frame size: %zu\n", frames.size());
869         auto framesStr = Unwinder::GetFramesStr(frames);
870         printf("Unwinder frames:\n%s\n", framesStr.c_str());
871         ASSERT_GT(frames.size(), 0);
872     }
873 
874     PrintUnwindBacktrace();
875     GTEST_LOG_(INFO) << "UnwindLocalX86_64Test001: end.";
876 }
877 
878 /**
879  * @tc.name: UnwindRemoteX86_64Test001
880  * @tc.desc: test unwinder UnwindRemote interface
881  * @tc.type: FUNC
882  */
883 HWTEST_F(UnwinderTest, UnwindRemoteX86_64Test001, TestSize.Level2)
884 {
885     GTEST_LOG_(INFO) << "UnwindLocalX86_64Test001: start.";
886     const pid_t initPid = 1;
887     auto unwinder = std::make_shared<Unwinder>(initPid);
888     DfxPtrace::Attach(initPid);
889     if (unwinder->UnwindRemote(initPid)) {
890         auto frames = unwinder->GetFrames();
891         printf("Unwinder frame size: %zu\n", frames.size());
892         auto framesStr = Unwinder::GetFramesStr(frames);
893         printf("Unwinder frames:\n%s\n", framesStr.c_str());
894         ASSERT_GT(frames.size(), 0);
895     }
896     DfxPtrace::Detach(initPid);
897 
898     GTEST_LOG_(INFO) << "UnwindRemoteX86_64Test001: end.";
899 }
900 #endif
901 
902 /**
903  * @tc.name: GetSymbolByPcTest001
904  * @tc.desc: test unwinder GetSymbolByPc interface
905  *  in local case
906  * @tc.type: FUNC
907  */
908 HWTEST_F(UnwinderTest, GetSymbolByPcTest001, TestSize.Level2)
909 {
910     GTEST_LOG_(INFO) << "GetSymbolByPcTest001: start.";
911     auto unwinder = std::make_shared<Unwinder>();
912     unwinder->UnwindLocal();
913     auto frames = unwinder->GetFrames();
914     uintptr_t pc0 = static_cast<uintptr_t>(frames[0].pc);
915     std::string funcName;
916     uint64_t funcOffset;
917     std::shared_ptr<DfxMaps> maps = std::make_shared<DfxMaps>();
918     ASSERT_FALSE(unwinder->GetSymbolByPc(0x00000000, maps, funcName, funcOffset)); // Find map is null
919     ASSERT_FALSE(unwinder->GetSymbolByPc(pc0, maps, funcName, funcOffset)); // Get elf is null
920     GTEST_LOG_(INFO) << "GetSymbolByPcTest001: end.";
921 }
922 
923 /**
924  * @tc.name: AccessMemTest001
925  * @tc.desc: test unwinder AccessMem interface
926  * @tc.type: FUNC
927  */
928 HWTEST_F(UnwinderTest, AccessMemTest001, TestSize.Level2)
929 {
930     GTEST_LOG_(INFO) << "AccessMemTest001: start.";
931     auto unwinder = std::make_shared<Unwinder>();
932     auto memory = std::make_shared<DfxMemory>(UNWIND_TYPE_LOCAL);
933     uintptr_t val;
934     EXPECT_FALSE(memory->ReadReg(0, &val));
935     uintptr_t regs[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa};
936     UnwindContext ctx;
937     ctx.regs = DfxRegs::CreateFromRegs(UnwindMode::DWARF_UNWIND, regs, sizeof(regs) / sizeof(regs[0]));
938     memory->SetCtx(&ctx);
939     EXPECT_FALSE(memory->ReadReg(-1, &val));
940 
941     uint8_t values[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8};
942     uintptr_t addr = reinterpret_cast<uintptr_t>(&values[0]);
943     EXPECT_FALSE(unwinder->AccessMem(memory.get(), addr, nullptr));
944     GTEST_LOG_(INFO) << "AccessMemTest001: end.";
945 }
946 
947 /**
948  * @tc.name: UnwinderTest001
949  * @tc.desc: test Unwinder::xxxx interface
950  * @tc.type: FUNC
951  */
952 HWTEST_F(UnwinderTest, UnwinderTest001, TestSize.Level2)
953 {
954     GTEST_LOG_(INFO) << "UnwinderTest001: start.";
955     auto unwinder = std::make_shared<Unwinder>(getpid());
956     unwinder->EnableUnwindCache(false);
957     unwinder->EnableFpCheckMapExec(false);
958     unwinder->EnableJsvmstack(false);
959     auto regs = unwinder->GetRegs();
960     ASSERT_EQ(regs, nullptr);
961     DfxFrame frame;
962     unwinder->FillFrame(frame);
963     unwinder->AddFrame(frame);
964     unwinder->ArkWriteJitCodeToFile(1);
965     auto jitCache = unwinder->GetJitCache();
966     ASSERT_EQ(jitCache.size(), 0);
967     GTEST_LOG_(INFO) << "UnwinderTest001: end.";
968 }
969 
970 /**
971  * @tc.name: UnwinderTest002
972  * @tc.desc: test DfxFrameFormatter GetFrameStr
973  * @tc.type: FUNC
974  */
975 HWTEST_F(UnwinderTest, UnwinderTest002, TestSize.Level2)
976 {
977     GTEST_LOG_(INFO) << "UnwinderTest002: start.";
978     std::shared_ptr<DfxFrame> frame = nullptr;
979     std::string str = DfxFrameFormatter::GetFrameStr(frame);
980     ASSERT_EQ(str, "") << "UnwinderTest002: end.";
981 }
982 
983 /**
984  * @tc.name: UnwinderTest003
985  * @tc.desc: test DfxFrameFormatter GetFrameStr
986  * @tc.type: FUNC
987  */
988 HWTEST_F(UnwinderTest, UnwinderTest003, TestSize.Level2)
989 {
990     GTEST_LOG_(INFO) << "UnwinderTest003: start.";
991     DfxFrame frame;
992     frame.isJsFrame = true;
993     std::string str = DfxFrameFormatter::GetFrameStr(frame);
994     ASSERT_NE(str, "") << "UnwinderTest003: end.";
995 }
996 
997 /**
998  * @tc.name: UnwinderTest004
999  * @tc.desc: test DfxFrameFormatter GetFrameStr
1000  * @tc.type: FUNC
1001  */
1002 HWTEST_F(UnwinderTest, UnwinderTest004, TestSize.Level2)
1003 {
1004     GTEST_LOG_(INFO) << "UnwinderTest004: start.";
1005     DfxFrame frame;
1006     frame.isJsFrame = true;
1007     frame.funcName = "test";
1008     frame.packageName = "test";
1009     frame.mapName = "test";
1010     std::string str = DfxFrameFormatter::GetFrameStr(frame);
1011     ASSERT_NE(str, "") << "UnwinderTest004: end.";
1012 }
1013 } // namespace HiviewDFX
1014 } // namepsace OHOS
1015 
1016