1/* 2 * Copyright (c) 2022-2023 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#include <cerrno> 18#include <unistd.h> 19 20#include "dfx_fault_stack.h" 21#include "dfx_frame_formatter.h" 22#include "dfx_maps.h" 23#include "dfx_regs.h" 24#include "dfx_ring_buffer_wrapper.h" 25#include "dfx_thread.h" 26#include "dfx_unwind_remote.h" 27 28using namespace OHOS::HiviewDFX; 29using namespace testing::ext; 30using namespace std; 31 32namespace OHOS { 33namespace HiviewDFX { 34class FaultStackUnittest : public testing::Test { 35public: 36 static void SetUpTestCase(void); 37 static void TearDownTestCase(void); 38 void SetUp(); 39 void TearDown(); 40 41 static int WriteLogFunc(int32_t fd, const char *buf, int len); 42 static std::string result; 43}; 44} // namespace HiviewDFX 45} // namespace OHOS 46 47std::string FaultStackUnittest::result = ""; 48 49void FaultStackUnittest::SetUpTestCase(void) 50{ 51 result = ""; 52} 53 54void FaultStackUnittest::TearDownTestCase(void) 55{ 56} 57 58void FaultStackUnittest::SetUp(void) 59{ 60 DfxRingBufferWrapper::GetInstance().SetWriteFunc(FaultStackUnittest::WriteLogFunc); 61} 62 63void FaultStackUnittest::TearDown(void) 64{ 65} 66 67int FaultStackUnittest::WriteLogFunc(int32_t fd, const char *buf, int len) 68{ 69 printf("%d: %s", fd, buf); 70 FaultStackUnittest::result.append(std::string(buf, len)); 71 return 0; 72} 73 74namespace { 75/** 76 * @tc.name: FaultStackUnittest001 77 * @tc.desc: check whether fault stack and register can be print out 78 * @tc.type: FUNC 79 */ 80HWTEST_F(FaultStackUnittest, FaultStackUnittest001, TestSize.Level2) 81{ 82 GTEST_LOG_(INFO) << "FaultStackUnittest001: start."; 83 84 auto unwinder = std::make_shared<Unwinder>(); 85 bool unwRet = unwinder->UnwindLocal(); 86 if (!unwRet) { 87 FAIL() << "Failed to unwind local"; 88 } 89 auto frames = unwinder->GetFrames(); 90 int childPid = fork(); 91 bool isSuccess = childPid >= 0; 92 if (!isSuccess) { 93 ASSERT_FALSE(isSuccess); 94 printf("Failed to fork child process, errno(%d).\n", errno); 95 return; 96 } 97 if (childPid == 0) { 98 uint32_t left = 10; 99 while (left > 0) { 100 left = sleep(left); 101 } 102 _exit(0); 103 } 104 DfxThread thread(childPid, childPid, childPid); 105 ASSERT_EQ(true, thread.Attach()); 106 auto maps = DfxMaps::Create(childPid); 107 auto reg = DfxRegs::CreateRemoteRegs(childPid); 108 std::unique_ptr<FaultStack> stack = std::make_unique<FaultStack>(childPid); 109 stack->CollectStackInfo(frames); 110 stack->CollectRegistersBlock(reg, maps); 111 stack->Print(); 112 thread.Detach(); 113 114 if (result.find("Memory near registers") == std::string::npos) { 115 FAIL(); 116 } 117 118 if (result.find("FaultStack") == std::string::npos) { 119 FAIL(); 120 } 121 122 if (result.find("pc") == std::string::npos) { 123 FAIL(); 124 } 125 126 if (result.find("sp2:") == std::string::npos) { 127 FAIL(); 128 } 129 GTEST_LOG_(INFO) << "Result Log length:" << result.length(); 130 ASSERT_GT(result.length(), 0); 131 GTEST_LOG_(INFO) << "FaultStackUnittest001: end."; 132} 133}