• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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