• 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";
__anon4347931d0102null93     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().displayRegister, true);
647     ASSERT_EQ(DfxConfig::GetConfig().displayBacktrace, true);
648     ASSERT_EQ(DfxConfig::GetConfig().displayMaps, true);
649     ASSERT_EQ(DfxConfig::GetConfig().displayFaultStack, true);
650     ASSERT_EQ(DfxConfig::GetConfig().dumpOtherThreads, true);
651     ASSERT_EQ(DfxConfig::GetConfig().highAddressStep, 512);
652     ASSERT_EQ(DfxConfig::GetConfig().lowAddressStep, 16);
653     ASSERT_EQ(DfxConfig::GetConfig().maxFrameNums, 256);
654     GTEST_LOG_(INFO) << "DfxConfigTest001: end.";
655 }
656 
657 /**
658  * @tc.name: FillFrameTest001
659  * @tc.desc: test unwinder FillFrame interface
660  *  in local case
661  * @tc.type: FUNC
662  */
663 HWTEST_F(UnwinderTest, FillFrameTest001, TestSize.Level2)
664 {
665     GTEST_LOG_(INFO) << "FillFrameTest001: start.";
666     auto unwinder = std::make_shared<Unwinder>();
667     DfxFrame frame;
668     unwinder->FillFrame(frame);
669     GTEST_LOG_(INFO) << " when DfxFrame::map is null, frame.buildId.size() is 0";
670     ASSERT_EQ(frame.buildId.size(), 0);
671     string testMap = "f6d83000-f6d84000 r--p 00001000 b3:07 1892 /system/lib/init/libinit_context.z.so.noexit";
672     auto map = DfxMap::Create(testMap, sizeof(testMap));
673     frame.map = map;
674     unwinder->FillFrame(frame);
675     GTEST_LOG_(INFO) << " when DfxFrame::map is not null and file not exist, frame.buildId.size() is 0";
676     ASSERT_EQ(frame.buildId.size(), 0);
677 #ifdef __arm__
678     testMap = "f6d83000-f6d84000 r--p 00001000 b3:07 1892 /system/lib/init/libinit_context.z.so";
679 #else
680     testMap = "7f0ab40000-7f0ab41000 r--p 00000000 b3:07 1882 /system/lib64/init/libinit_context.z.so";
681 #endif
682     map = DfxMap::Create(testMap, sizeof(testMap));
683     frame.map = map;
684     unwinder->FillFrame(frame);
685     GTEST_LOG_(INFO) << " when DfxFrame::map is not null and file exist, frame.buildId.size() is bigger than 0";
686     ASSERT_EQ(frame.buildId.size() == 0, false);
687     GTEST_LOG_(INFO) << "FillFrameTest001: end.";
688 }
689 
690 /**
691  * @tc.name: FillJsFrameTest001
692  * @tc.desc: test unwinder FillJsFrame interface
693  *  in local case
694  * @tc.type: FUNC
695  */
696 HWTEST_F(UnwinderTest, FillJsFrameTest001, TestSize.Level2)
697 {
698     GTEST_LOG_(INFO) << "FillJsFrameTest001: start.";
699     auto unwinder = std::make_shared<Unwinder>();
700     DfxFrame frame;
701     unwinder->FillJsFrame(frame);
702     GTEST_LOG_(INFO) << " when DfxFrame::map is null, frame.map is nullptr";
703     ASSERT_EQ(frame.map, nullptr);
704     string testMap = "f6d83000-f6d84000 r--p 00001000 b3:07 1892 /system/lib/init/libinit_context.z.so";
705     auto map = DfxMap::Create(testMap, sizeof(testMap));
706     frame.map = map;
707     unwinder->FillJsFrame(frame);
708     GTEST_LOG_(INFO) << " when DfxFrame::map is not null and file exist, frame.map.GetHap is not nullptr";
709     ASSERT_NE(frame.map->GetHap(), nullptr);
710     GTEST_LOG_(INFO) << "FillJsFrameTest001: end.";
711 }
712 
713 /**
714  * @tc.name: FillFramesTest001
715  * @tc.desc: test unwinder FillFrames interface
716  *  in local case
717  * @tc.type: FUNC
718  */
719 HWTEST_F(UnwinderTest, FillFramesTest001, TestSize.Level2)
720 {
721     GTEST_LOG_(INFO) << "FillFramesTest001: start.";
722 #ifdef __arm__
723     const string testMap = "f6d83000-f6d84000 r--p 00001000 b3:07 1892 /system/lib/init/libinit_context.z.so";
724 #else
725     const string testMap = "7f0ab40000-7f0ab41000 r--p 00000000 b3:07 1882 /system/lib64/init/libinit_context.z.so";
726 #endif
727     auto unwinder = std::make_shared<Unwinder>();
728     std::vector<DfxFrame> frames;
729     DfxFrame frame;
730     auto map = DfxMap::Create(testMap, sizeof(testMap));
731     frame.map = map;
732     frames.push_back(frame);
733     ASSERT_EQ(frames[0].buildId.size(), 0);
734     unwinder->FillFrames(frames);
735     ASSERT_EQ(frames[0].buildId.size() == 0, false);
736     GTEST_LOG_(INFO) << "FillFramesTest001: end.";
737 }
738 
739 #if defined(__arm__) || defined(__aarch64__)
740 /**
741  * @tc.name: UnwindLocalWithContextTest001
742  * @tc.desc: test unwinder UnwindLocalWithContext interface
743  *  in local case
744  * @tc.type: FUNC
745  */
746 HWTEST_F(UnwinderTest, UnwindLocalWithContextTest001, TestSize.Level2)
747 {
748     GTEST_LOG_(INFO) << "UnwindLocalWithContextTest001: start.";
749     auto regs = DfxRegs::Create();
750     auto regsData = regs->RawData();
751     GetLocalRegs(regsData);
752     ucontext_t context;
753     (void)memset_s(&context, sizeof(context), 0, sizeof(context));
754 #ifdef __arm__
755     context.uc_mcontext.arm_r0 = *(regs->GetReg(REG_ARM_R0));
756     context.uc_mcontext.arm_r1 = *(regs->GetReg(REG_ARM_R1));
757     context.uc_mcontext.arm_r2 = *(regs->GetReg(REG_ARM_R2));
758     context.uc_mcontext.arm_r3 = *(regs->GetReg(REG_ARM_R3));
759     context.uc_mcontext.arm_r4 = *(regs->GetReg(REG_ARM_R4));
760     context.uc_mcontext.arm_r5 = *(regs->GetReg(REG_ARM_R5));
761     context.uc_mcontext.arm_r6 = *(regs->GetReg(REG_ARM_R6));
762     context.uc_mcontext.arm_r7 = *(regs->GetReg(REG_ARM_R7));
763     context.uc_mcontext.arm_r8 = *(regs->GetReg(REG_ARM_R8));
764     context.uc_mcontext.arm_r9 = *(regs->GetReg(REG_ARM_R9));
765     context.uc_mcontext.arm_r10 = *(regs->GetReg(REG_ARM_R10));
766     context.uc_mcontext.arm_fp = *(regs->GetReg(REG_ARM_R11));
767     context.uc_mcontext.arm_ip = *(regs->GetReg(REG_ARM_R12));
768     context.uc_mcontext.arm_sp = *(regs->GetReg(REG_ARM_R13));
769     context.uc_mcontext.arm_lr = *(regs->GetReg(REG_ARM_R14));
770     context.uc_mcontext.arm_pc = *(regs->GetReg(REG_ARM_R15));
771 #else
772     for (int i = 0; i < REG_LAST; ++i) {
773         context.uc_mcontext.regs[i] = *(regs->GetReg(i));
774     }
775 #endif
776     auto unwinder = std::make_shared<Unwinder>();
777     ASSERT_TRUE(unwinder->UnwindLocalWithContext(context));
778     auto frames = unwinder->GetFrames();
779     ASSERT_GT(frames.size(), 1);
780     GTEST_LOG_(INFO) << "UnwindLocalWithContextTest001: frames:\n" << Unwinder::GetFramesStr(frames);
781     GTEST_LOG_(INFO) << "UnwindLocalWithContextTest001: end.";
782 }
783 #endif
784 
785 static int32_t g_tid = 0;
786 static std::mutex g_mutex;
ThreadTest002()787 __attribute__((noinline)) void ThreadTest002()
788 {
789     printf("ThreadTest002\n");
790     g_mutex.lock();
791     g_mutex.unlock();
792 }
793 
ThreadTest001()794 __attribute__((noinline)) void ThreadTest001()
795 {
796     g_tid = gettid();
797     printf("ThreadTest001: tid: %d\n", g_tid);
798     ThreadTest002();
799 }
800 
801 /**
802  * @tc.name: UnwindLocalWithTidTest001
803  * @tc.desc: test unwinder UnwindLocalWithTid interface
804  *  in local case
805  * @tc.type: FUNC
806  */
807 HWTEST_F(UnwinderTest, UnwindLocalWithTidTest001, TestSize.Level2)
808 {
809     GTEST_LOG_(INFO) << "UnwindLocalWithTidTest001: start.";
810     auto unwinder = std::make_shared<Unwinder>();
811     g_mutex.lock();
812     std::thread unwThread(ThreadTest001);
813     sleep(1);
814     if (g_tid <= 0) {
815         FAIL() << "UnwindLocalWithTidTest001: Failed to create child thread.\n";
816     }
817     ASSERT_TRUE(unwinder->UnwindLocalWithTid(g_tid));
818 #if defined(__aarch64__)
819     auto pcs = unwinder->GetPcs();
820     std::vector<DfxFrame> frames;
821     unwinder->GetFramesByPcs(frames, pcs);
822 #else
823     auto frames = unwinder->GetFrames();
824 #endif
825     ASSERT_GT(frames.size(), 1);
826     GTEST_LOG_(INFO) << "UnwindLocalWithTidTest001: frames:\n" << Unwinder::GetFramesStr(frames);
827     g_mutex.unlock();
828     g_tid = 0;
829     if (unwThread.joinable()) {
830         unwThread.join();
831     }
832     GTEST_LOG_(INFO) << "UnwindLocalWithTidTest001: end.";
833 }
834 
835 #if defined(__x86_64__)
TraceFunc(_Unwind_Context * ctx,void * d)836 static _Unwind_Reason_Code TraceFunc(_Unwind_Context *ctx, void *d)
837 {
838     int *depth = (int*)d;
839     printf("\t#%d: program counter at %p\n", *depth, reinterpret_cast<void *>(_Unwind_GetIP(ctx)));
840     (*depth)++;
841     return _URC_NO_REASON;
842 }
843 
PrintUnwindBacktrace()844 static void PrintUnwindBacktrace()
845 {
846     int depth = 0;
847     _Unwind_Backtrace(&TraceFunc, &depth);
848 }
849 
850 /**
851  * @tc.name: UnwindLocalX86_64Test001
852  * @tc.desc: test unwinder UnwindLocal interface
853  * @tc.type: FUNC
854  */
855 HWTEST_F(UnwinderTest, UnwindLocalX86_64Test001, TestSize.Level2)
856 {
857     GTEST_LOG_(INFO) << "UnwindLocalX86_64Test001: start.";
858     auto unwinder = std::make_shared<Unwinder>();
859     if (unwinder->UnwindLocal()) {
860         auto frames = unwinder->GetFrames();
861         printf("Unwinder frame size: %zu\n", frames.size());
862         auto framesStr = Unwinder::GetFramesStr(frames);
863         printf("Unwinder frames:\n%s\n", framesStr.c_str());
864         ASSERT_GT(frames.size(), 0);
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         ASSERT_GT(frames.size(), 0);
888     }
889     DfxPtrace::Detach(initPid);
890 
891     GTEST_LOG_(INFO) << "UnwindRemoteX86_64Test001: end.";
892 }
893 #endif
894 
895 /**
896  * @tc.name: GetSymbolByPcTest001
897  * @tc.desc: test unwinder GetSymbolByPc interface
898  *  in local case
899  * @tc.type: FUNC
900  */
901 HWTEST_F(UnwinderTest, GetSymbolByPcTest001, TestSize.Level2)
902 {
903     GTEST_LOG_(INFO) << "GetSymbolByPcTest001: start.";
904     auto unwinder = std::make_shared<Unwinder>();
905     unwinder->UnwindLocal();
906     auto frames = unwinder->GetFrames();
907     uintptr_t pc0 = static_cast<uintptr_t>(frames[0].pc);
908     std::string funcName;
909     uint64_t funcOffset;
910     std::shared_ptr<DfxMaps> maps = std::make_shared<DfxMaps>();
911     ASSERT_FALSE(unwinder->GetSymbolByPc(0x00000000, maps, funcName, funcOffset)); // Find map is null
912     ASSERT_FALSE(unwinder->GetSymbolByPc(pc0, maps, funcName, funcOffset)); // Get elf is null
913     GTEST_LOG_(INFO) << "GetSymbolByPcTest001: end.";
914 }
915 
916 /**
917  * @tc.name: AccessMemTest001
918  * @tc.desc: test unwinder AccessMem interface
919  * @tc.type: FUNC
920  */
921 HWTEST_F(UnwinderTest, AccessMemTest001, TestSize.Level2)
922 {
923     GTEST_LOG_(INFO) << "AccessMemTest001: start.";
924     auto unwinder = std::make_shared<Unwinder>();
925     auto acc = std::make_shared<DfxAccessorsLocal>();
926     auto memory = std::make_shared<DfxMemory>(acc);
927     uintptr_t val;
928     EXPECT_FALSE(memory->ReadReg(0, &val));
929     uintptr_t regs[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa};
930     UnwindContext ctx;
931     ctx.regs = DfxRegs::CreateFromRegs(UnwindMode::DWARF_UNWIND, regs, sizeof(regs) / sizeof(regs[0]));
932     memory->SetCtx(&ctx);
933     EXPECT_FALSE(memory->ReadReg(-1, &val));
934 
935     uint8_t values[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8};
936     uintptr_t addr = reinterpret_cast<uintptr_t>(&values[0]);
937     EXPECT_FALSE(unwinder->AccessMem(&memory, addr, nullptr));
938     GTEST_LOG_(INFO) << "AccessMemTest001: end.";
939 }
940 
941 /**
942  * @tc.name: UnwinderTest001
943  * @tc.desc: test Unwinder::xxxx interface
944  * @tc.type: FUNC
945  */
946 HWTEST_F(UnwinderTest, UnwinderTest001, TestSize.Level2)
947 {
948     GTEST_LOG_(INFO) << "UnwinderTest001: start.";
949     auto unwinder = std::make_shared<Unwinder>(getpid());
950     unwinder->EnableUnwindCache(false);
951     unwinder->EnableFpCheckMapExec(false);
952     auto regs = unwinder->GetRegs();
953     ASSERT_EQ(regs, nullptr);
954     DfxFrame frame;
955     unwinder->FillFrame(frame);
956     unwinder->AddFrame(frame);
957     unwinder->ArkWriteJitCodeToFile(1);
958     auto jitCache = unwinder->GetJitCache();
959     ASSERT_EQ(jitCache.size(), 0);
960     GTEST_LOG_(INFO) << "UnwinderTest001: end.";
961 }
962 
963 /**
964  * @tc.name: UnwinderTest002
965  * @tc.desc: test DfxFrameFormatter GetFrameStr
966  * @tc.type: FUNC
967  */
968 HWTEST_F(UnwinderTest, UnwinderTest002, TestSize.Level2)
969 {
970     GTEST_LOG_(INFO) << "UnwinderTest002: start.";
971     std::shared_ptr<DfxFrame> frame = nullptr;
972     std::string str = DfxFrameFormatter::GetFrameStr(frame);
973     ASSERT_EQ(str, "");
974     std::vector<std::shared_ptr<DfxFrame>> frames;
975     str = DfxFrameFormatter::GetFramesStr(frames);
976     ASSERT_EQ(str, "");
977     GTEST_LOG_(INFO) << "UnwinderTest002: end.";
978 }
979 
980 /**
981  * @tc.name: UnwinderTest003
982  * @tc.desc: test DfxFrameFormatter GetFrameStr
983  * @tc.type: FUNC
984  */
985 HWTEST_F(UnwinderTest, UnwinderTest003, TestSize.Level2)
986 {
987     GTEST_LOG_(INFO) << "UnwinderTest003: start.";
988     std::shared_ptr<DfxFrame> frame = std::make_shared<DfxFrame>();
989     frame->isJsFrame = true;
990     frame->funcName = "testFunc";
991     frame->packageName = "testPack";
992     frame->mapName = "testMap";
993     frame->line = 1;
994     frame->column = 1;
995     std::string str = DfxFrameFormatter::GetFrameStr(frame);
996     ASSERT_FALSE(str.empty());
997     GTEST_LOG_(INFO) << "UnwinderTest003: end.";
998 }
999 } // namespace HiviewDFX
1000 } // namepsace OHOS
1001 
1002