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
18#include <cstdlib>
19#include <dbghelp.h>
20#include <iostream>
21#include <sstream>
22#include <unistd.h>
23#include <windows.h>
24
25#include "PreviewerEngineLog.h"
26#include "PublicMethods.h"
27
28static const int MAX_ADDRESS_LENGTH = 32;
29
30struct CrashInfo {
31    CHAR ErrorCode[MAX_ADDRESS_LENGTH];
32    CHAR Address[MAX_ADDRESS_LENGTH];
33    CHAR Flags[MAX_ADDRESS_LENGTH];
34};
35
36void CrashHandler::RecordCallStack(const CONTEXT *context)
37{
38    HANDLE hProcess = GetCurrentProcess();
39    SymInitialize(hProcess, NULL, TRUE);
40
41    CONTEXT crashContext = *context;
42
43    STACKFRAME64 sf = {};
44    DWORD imageType = IMAGE_FILE_MACHINE_I386;
45
46#ifdef _M_X64
47    imageType = IMAGE_FILE_MACHINE_AMD64;
48    sf.AddrPC.Offset = crashContext.Rip;
49    sf.AddrPC.Mode = AddrModeFlat;
50    sf.AddrFrame.Offset = crashContext.Rsp;
51    sf.AddrFrame.Mode = AddrModeFlat;
52    sf.AddrStack.Offset = crashContext.Rsp;
53    sf.AddrStack.Mode = AddrModeFlat;
54#endif
55
56    HANDLE hThread = GetCurrentThread();
57
58    while (true) {
59        if (!StackWalk64(imageType, hProcess, hThread, &sf, &crashContext, NULL,
60                         SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
61            break;
62        }
63        if (sf.AddrFrame.Offset == 0) {
64            break;
65        }
66
67        int8_t stackIntLog[PublicMethods::MAX_ITOA_BIT] = {0};
68        unsigned int itoaLength = PublicMethods::Ulltoa(sf.AddrPC.Offset, stackIntLog);
69        int8_t offsetLog[] = "\n[JsEngine Crash]sf.AddrPC.Offset : 0x";
70        write(STDERR_FILENO, offsetLog, sizeof(offsetLog));
71        write(STDERR_FILENO, stackIntLog, itoaLength);
72    }
73    SymCleanup(hProcess);
74}
75
76LONG CrashHandler::ApplicationCrashHandler(EXCEPTION_POINTERS *exception)
77{
78    int8_t crashBeginLog[] = "[JsEngine Crash]Engine Crash Info Begin.\n";
79    write(STDERR_FILENO, crashBeginLog, sizeof(crashBeginLog) - 1);
80
81    int8_t stackIntLog[PublicMethods::MAX_ITOA_BIT] = {0};
82    // 16 means hexadecimal
83    unsigned int itoaLength = PublicMethods::Ulltoa(reinterpret_cast<uintptr_t>
84                                                    (exception->ExceptionRecord->ExceptionAddress), stackIntLog);
85    int8_t ELOG[] = "[JsEngine Crash]Address: 0x";
86    write(STDERR_FILENO, ELOG, sizeof(ELOG) - 1);
87    write(STDERR_FILENO, stackIntLog, itoaLength);
88    // 16 means hexadecimal
89    itoaLength = PublicMethods::Ulltoa(exception->ExceptionRecord->ExceptionCode, stackIntLog);
90    int8_t addressLog[] = "\n[JsEngine Crash]ErrorCode: 0x";
91    write(STDERR_FILENO, addressLog, sizeof(addressLog) - 1);
92    write(STDERR_FILENO, stackIntLog, itoaLength);
93    // 16 means hexadecimal
94    RecordCallStack(exception->ContextRecord);
95
96    int8_t crashEndLog[] = "\n[JsEngine Crash]Engine Crash Info End.\n";
97    write(STDERR_FILENO, crashEndLog, sizeof(crashEndLog) - 1);
98    return 0;
99}
100
101void CrashHandler::InitExceptionHandler()
102{
103    SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)ApplicationCrashHandler);
104}
105