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