1 /*
2 * Copyright (c) 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 "CrashHandler.h"
17 #include <iomanip>
18 #include <cstdlib>
19 #include <vector>
20 #include <dbghelp.h>
21 #include <iostream>
22 #include <sstream>
23 #include <unistd.h>
24 #include <windows.h>
25
26 #include "PreviewerEngineLog.h"
27 #include "PublicMethods.h"
28
29 static const int MAX_NAME_LENGTH = 512;
30 static const int MAX_ADDRESS_LENGTH = 16;
31
32 namespace {
GetBacktrace(HANDLE hProcess,STACKFRAME64 & sf,SYMBOL_INFO * symbol)33 void GetBacktrace(HANDLE hProcess, STACKFRAME64 &sf, SYMBOL_INFO *symbol)
34 {
35 // get addr info
36 if (SymFromAddr(hProcess, sf.AddrPC.Offset, 0, symbol)) {
37 // get module info
38 IMAGEHLP_MODULE64 modInfo;
39 modInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
40 if (!SymGetModuleInfo64(hProcess, sf.AddrPC.Offset, &modInfo)) {
41 std::cout << "Unable to retrieve module information." << std::endl;
42 }
43 // print module name,function name and dll path
44 std::cout << "0x" << std::setw(MAX_ADDRESS_LENGTH) << std::setfill('0') << std::hex << sf.AddrPC.Offset
45 << std::dec << " in " << modInfo.ModuleName << "!_" << symbol->Name << " ()" << std::endl;
46 IMAGEHLP_LINE64 line;
47 line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
48 DWORD displacement = 0;
49 // get line of source code
50 if (SymGetLineFromAddr64(hProcess, sf.AddrPC.Offset, &displacement, &line)) {
51 std::cout << "Source: " << line.FileName << " Line: " << line.LineNumber << std::endl;
52 }
53 } else {
54 std::cout << "Unable to retrieve symbol for address 0x"
55 << std::hex << sf.AddrPC.Offset << std::dec << std::endl;
56 }
57 }
58 }
59
RecordCallStack(const CONTEXT * context)60 void CrashHandler::RecordCallStack(const CONTEXT *context)
61 {
62 HANDLE hProcess = GetCurrentProcess();
63 SymInitialize(hProcess, NULL, TRUE);
64 CONTEXT crashContext = *context;
65 STACKFRAME64 sf = {};
66 DWORD imageType = IMAGE_FILE_MACHINE_I386;
67 #ifdef _M_X64
68 imageType = IMAGE_FILE_MACHINE_AMD64;
69 sf.AddrPC.Offset = crashContext.Rip;
70 sf.AddrPC.Mode = AddrModeFlat;
71 sf.AddrFrame.Offset = crashContext.Rsp;
72 sf.AddrFrame.Mode = AddrModeFlat;
73 sf.AddrStack.Offset = crashContext.Rsp;
74 sf.AddrStack.Mode = AddrModeFlat;
75 #endif
76 HANDLE hThread = GetCurrentThread();
77 std::vector<BYTE> symbolBuffer(sizeof(SYMBOL_INFO) + MAX_NAME_LENGTH * sizeof(TCHAR));
78 SYMBOL_INFO *symbol = reinterpret_cast<SYMBOL_INFO*>(symbolBuffer.data());
79 symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
80 symbol->MaxNameLen = MAX_NAME_LENGTH;
81 while (StackWalk64(imageType, hProcess, hThread, &sf, &crashContext,
82 NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
83 if (sf.AddrPC.Offset == 0) {
84 break;
85 }
86 GetBacktrace(hProcess, sf, symbol);
87 }
88 SymCleanup(hProcess);
89 }
90
ApplicationCrashHandler(EXCEPTION_POINTERS * exception)91 LONG CrashHandler::ApplicationCrashHandler(EXCEPTION_POINTERS *exception)
92 {
93 int8_t crashBeginLog[] = "[JsEngine Crash]Engine Crash Info Begin.\n";
94 write(STDERR_FILENO, crashBeginLog, sizeof(crashBeginLog) - 1);
95
96 int8_t stackIntLog[PublicMethods::MAX_ITOA_BIT] = {0};
97 // 16 means hexadecimal
98 unsigned int itoaLength = PublicMethods::Ulltoa(reinterpret_cast<uintptr_t>
99 (exception->ExceptionRecord->ExceptionAddress), stackIntLog);
100 int8_t ELOG[] = "[JsEngine Crash]Address: 0x";
101 write(STDERR_FILENO, ELOG, sizeof(ELOG) - 1);
102 write(STDERR_FILENO, stackIntLog, itoaLength);
103 // 16 means hexadecimal
104 itoaLength = PublicMethods::Ulltoa(exception->ExceptionRecord->ExceptionCode, stackIntLog);
105 int8_t addressLog[] = "\n[JsEngine Crash]ErrorCode: 0x";
106 write(STDERR_FILENO, addressLog, sizeof(addressLog) - 1);
107 write(STDERR_FILENO, stackIntLog, itoaLength);
108 // 16 means hexadecimal
109 RecordCallStack(exception->ContextRecord);
110
111 int8_t crashEndLog[] = "\n[JsEngine Crash]Engine Crash Info End.\n";
112 write(STDERR_FILENO, crashEndLog, sizeof(crashEndLog) - 1);
113 return 0;
114 }
115
InitExceptionHandler()116 void CrashHandler::InitExceptionHandler()
117 {
118 SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)ApplicationCrashHandler);
119 }
120