1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #define NVOC_CRASHCAT_REPORT_H_PRIVATE_ACCESS_ALLOWED
25 #include "crashcat/crashcat_report.h"
26 #include "crashcat/crashcat_engine.h"
27 #include "libos_v2_crashcat.h"
28 #include "utils/nvprintf.h"
29 #include "nv-crashcat-decoder.h"
30 
31 static inline const char *crashcatReportModeToString_LIBOS2(NV_CRASHCAT_RISCV_MODE mode)
32 {
33     switch (mode)
34     {
35         case NV_CRASHCAT_RISCV_MODE_M:
36         case NV_CRASHCAT_RISCV_MODE_S:
37             return MAKE_NV_PRINTF_STR("kernel");
38         case NV_CRASHCAT_RISCV_MODE_U:
39             return MAKE_NV_PRINTF_STR("task");
40         default:
41             return MAKE_NV_PRINTF_STR("unspecified");
42     }
43 }
44 
45 static inline const char *crashcatReportPanicReasonToString_LIBOS2(LibosPanicReason reason)
46 {
47 #define LIBOS_PANIC_REASON_CASE(reason, str)   \
48     case LibosPanicReason ## reason: return MAKE_NV_PRINTF_STR(str)
49     switch (reason)
50     {
51         LIBOS_PANIC_REASON_CASE(UnrecoverableTaskCrash, "unrecoverable task crash");
52         LIBOS_PANIC_REASON_CASE(UnhandledState,         "unhandled state");
53         LIBOS_PANIC_REASON_CASE(InvalidConfiguration,   "invalid configuration");
54         LIBOS_PANIC_REASON_CASE(FatalHardwareError,     "fatal hardware error");
55         LIBOS_PANIC_REASON_CASE(InsufficientResources,  "insufficient resources");
56         LIBOS_PANIC_REASON_CASE(Timeout,                "timeout");
57         LIBOS_PANIC_REASON_CASE(EnvCallFailed,          "environment call failed");
58         LIBOS_PANIC_REASON_CASE(SspStackCheckFailed,    "stack smashing detected");
59         LIBOS_PANIC_REASON_CASE(AsanMemoryError,        "asan memory error detected");
60         LIBOS_PANIC_REASON_CASE(Test,                   "test");
61         LIBOS_PANIC_REASON_CASE(ProgrammingError,       "programming error");
62         LIBOS_PANIC_REASON_CASE(DebugAssertionFailed,   "debug assertion failed");
63         default: return MAKE_NV_PRINTF_STR("unknown error");
64     }
65 }
66 
67 void crashcatReportLogSource_V1_LIBOS2(CrashCatReport *pReport)
68 {
69     NvCrashCatReport_V1 *pReportV1 = &pReport->v1.report;
70 
71     NvU8 taskId = crashcatReportV1SourceLibos2TaskId(pReportV1);
72 
73 #define CRASHCAT_LOG_LIBOS2_SOURCE(fmt, ...)                                                    \
74     if (taskId == NV_CRASHCAT_REPORT_V1_SOURCE_ID_LIBOS2_TASK_ID_UNSPECIFIED)                   \
75         crashcatEnginePrintf(pReport->pEngine, NV_TRUE, fmt, __VA_ARGS__ );                     \
76     else                                                                                        \
77         crashcatEnginePrintf(pReport->pEngine, NV_TRUE, fmt ", task:%u", __VA_ARGS__, taskId)
78 
79     const char *pModeStr = crashcatReportModeToString_LIBOS2(crashcatReportV1SourceMode(pReportV1));
80     switch (crashcatReportV1SourceCauseType(pReportV1))
81     {
82         case NV_CRASHCAT_CAUSE_TYPE_EXCEPTION:
83         {
84             // Kernel or task unhandled exception - the sourceData is the xcause value
85             NvU64 xcause = pReportV1->sourceData;
86             CRASHCAT_LOG_LIBOS2_SOURCE(
87                 "%s exception: %s (cause:0x%" NvU64_fmtx ") @ pc:0x%" NvU64_fmtx,
88                 pModeStr, crashcatReportRiscvCauseToString(xcause), xcause,
89                 pReportV1->sourcePc);
90             break;
91         }
92         case NV_CRASHCAT_CAUSE_TYPE_TIMEOUT:
93         {
94             // Task timeout (no way for libos2 to self-report kernel timeouts)
95             CRASHCAT_LOG_LIBOS2_SOURCE(
96                 "%s timeout @ pc:0x%" NvU64_fmtx, pModeStr, pReportV1->sourcePc);
97             break;
98         }
99         case NV_CRASHCAT_CAUSE_TYPE_PANIC:
100         {
101             // Kernel or task panic
102             LibosPanicReason reason = crashcatReportV1SourceCauseLibos2Reason(pReportV1);
103             CRASHCAT_LOG_LIBOS2_SOURCE(
104                 "%s panic: %s (%u) @ pc:0x%" NvU64_fmtx ", aux:0x%" NvU64_fmtx,
105                 pModeStr, crashcatReportPanicReasonToString_LIBOS2(reason),
106                 reason, pReportV1->sourcePc, pReportV1->sourceData);
107             break;
108         }
109     }
110 }
111 
112 void crashcatReportLogReporter_V1_LIBOS2(CrashCatReport *pReport)
113 {
114     NvCrashCatReport_V1 *pReportV1 = &pReport->v1.report;
115     NvU8 taskId = crashcatReportV1ReporterLibos2TaskId(pReportV1);
116 
117     if (taskId == NV_CRASHCAT_REPORT_V1_REPORTER_ID_LIBOS2_TASK_ID_UNSPECIFIED)
118     {
119         crashcatEnginePrintf(pReport->pEngine, NV_FALSE,
120             "Reported by libos kernel v%u.%u [%u] @ %u",
121             crashcatReportV1ReporterVersionLibos2Major(pReportV1),
122             crashcatReportV1ReporterVersionLibos2Minor(pReportV1),
123             crashcatReportV1ReporterVersionLibos2Cl(pReportV1),
124             crashcatReportV1ReporterTimestamp(pReportV1));
125     }
126     else
127     {
128         crashcatEnginePrintf(pReport->pEngine, NV_FALSE,
129             "Reported by libos task:%u v%u.%u [%u] @ ts:%u",
130             taskId, crashcatReportV1ReporterVersionLibos2Major(pReportV1),
131             crashcatReportV1ReporterVersionLibos2Minor(pReportV1),
132             crashcatReportV1ReporterVersionLibos2Cl(pReportV1),
133             crashcatReportV1ReporterTimestamp(pReportV1));
134     }
135 }
136