blob: 6a6e734146d6f4b10dc86912708124e755978327 [file] [log] [blame]
Nathaniel Broughbe3fba12021-02-28 21:47:28 +08001// Copyright 2021 The Pigweed Authors
Ewout van Bekkumf7a5b512020-12-29 16:44:52 -08002//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://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, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15// This is a very basic direct output log implementation with no buffering.
16
17//#define PW_LOG_MODULE_NAME "ASRT"
18//#include "pw_log/log.h"
19
Wyatt Hepler52790392021-06-18 12:08:42 -070020#include <cstdio>
Ewout van Bekkumf7a5b512020-12-29 16:44:52 -080021#include <cstring>
22
Ewout van Bekkum2aff88e2021-11-12 15:36:57 -080023#include "pw_assert/config.h"
Ewout van Bekkumf7a5b512020-12-29 16:44:52 -080024#include "pw_assert_basic/handler.h"
25#include "pw_preprocessor/util.h"
26#include "pw_string/string_builder.h"
27#include "pw_sys_io/sys_io.h"
28
29// If 1, call C's standard abort() function on assert failure.
30#ifndef PW_ASSERT_BASIC_ABORT
31#define PW_ASSERT_BASIC_ABORT 1
32#endif // PW_ASSERT_BASIC_ABORT
33
34// TODO(pwbug/17): Expose these through the config system.
35#define PW_ASSERT_BASIC_SHOW_BANNER 1
36#define PW_ASSERT_BASIC_USE_COLORS 1
37
38// ANSI color constants to control the terminal. Not Windows compatible.
39// clang-format off
40#if PW_ASSERT_BASIC_USE_COLORS
41#define MAGENTA "\033[35m"
42#define YELLOW "\033[33m"
43#define RED "\033[31m"
44#define GREEN "\033[32m"
45#define BLUE "\033[96m"
46#define BLACK "\033[30m"
47#define YELLOW_BG "\033[43m"
48#define WHITE_BG "\033[47m"
49#define RED_BG "\033[41m"
50#define BOLD "\033[1m"
51#define RESET "\033[0m"
52#else
53#define MAGENTA ""
54#define YELLOW ""
55#define RED ""
56#define GREEN ""
57#define BLUE ""
58#define BLACK ""
59#define YELLOW_BG ""
60#define WHITE_BG ""
61#define RED_BG ""
62#define BOLD ""
63#define RESET ""
64#endif // PW_ASSERT_BASIC_USE_COLORS
65// clang-format on
66
67static const char* kCrashBanner[] = {
68 " ",
69 " ▄████▄ ██▀███ ▄▄▄ ██████ ██░ ██ ",
70 " ▒██▀ ▀█ ▓██ ▒ ██▒ ▒████▄ ▒██ ▒ ▓██░ ██▒ ",
71 " ▒▓█ 💥 ▄ ▓██ ░▄█ ▒ ▒██ ▀█▄ ░ ▓██▄ ▒██▀▀██░ ",
72 " ▒▓▓▄ ▄██▒ ▒██▀▀█▄ ░██▄▄▄▄██ ▒ ██▒ ░▓█ ░██ ",
73 " ▒ ▓███▀ ░ ░██▓ ▒██▒ ▓█ ▓██▒ ▒██████▒▒ ░▓█▒░██▓ ",
74 " ░ ░▒ ▒ ░ ░ ▒▓ ░▒▓░ ▒▒ ▓▒█░ ▒ ▒▓▒ ▒ ░ ▒ ░░▒░▒ ",
75 " ░ ▒ ░▒ ░ ▒░ ▒ ▒▒ ░ ░ ░▒ ░ ░ ▒ ░▒░ ░ ",
76 " ░ ░░ ░ ░ ▒ ░ ░ ░ ░ ░░ ░ ",
77 " ░ ░ ░ ░ ░ ░ ░ ░ ░ ",
78 " ░",
79 " ",
80};
81
Adrien Larbanetd1ca56c2021-06-10 14:20:45 +000082static void WriteLine(const std::string_view& s) {
83 pw::sys_io::WriteLine(s)
84 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
85}
Ewout van Bekkumf7a5b512020-12-29 16:44:52 -080086
87typedef pw::StringBuffer<150> Buffer;
88
89extern "C" void pw_assert_basic_HandleFailure(const char* file_name,
90 int line_number,
91 const char* function_name,
92 const char* format,
93 ...) {
94 // As a matter of usability, crashes should be visible; make it so.
95#if PW_ASSERT_BASIC_SHOW_BANNER
96 WriteLine(RED);
97 for (const char* line : kCrashBanner) {
98 WriteLine(line);
99 }
100 WriteLine(RESET);
101#endif // PW_ASSERT_BASIC_SHOW_BANNER
102
103 WriteLine(
104 " Welp, that didn't go as planned. "
105 "It seems we crashed. Terribly sorry!");
106 WriteLine("");
107 WriteLine(YELLOW " CRASH MESSAGE" RESET);
108 WriteLine("");
109 {
110 Buffer buffer;
111 buffer << " ";
112 va_list args;
113 va_start(args, format);
114 buffer.FormatVaList(format, args);
115 va_end(args);
116 WriteLine(buffer.view());
117 }
118
119 if (file_name != nullptr && line_number != -1) {
120 WriteLine("");
121 WriteLine(YELLOW " CRASH FILE & LINE" RESET);
122 WriteLine("");
123 {
124 Buffer buffer;
125 buffer.Format(" %s:%d", file_name, line_number);
126 WriteLine(buffer.view());
127 }
128 }
129 if (function_name != nullptr) {
130 WriteLine("");
131 WriteLine(YELLOW " CRASH FUNCTION" RESET);
132 WriteLine("");
133 {
134 Buffer buffer;
135 buffer.Format(" %s", function_name);
136 WriteLine(buffer.view());
137 }
138 }
139
140 // TODO(pwbug/95): Perhaps surprisingly, this doesn't actually crash the
141 // device. At some point we'll have a reboot BSP function or similar, but for
142 // now this is acceptable since no one is using this basic backend.
143 if (!PW_ASSERT_BASIC_DISABLE_NORETURN) {
144 if (PW_ASSERT_BASIC_ABORT) {
Wyatt Hepler52790392021-06-18 12:08:42 -0700145 // abort() doesn't flush stderr/stdout, so manually flush them before
146 // aborting. abort() is preferred to exit(1) because debuggers catch it.
147 std::fflush(stderr);
148 std::fflush(stdout);
149 std::abort();
Ewout van Bekkumf7a5b512020-12-29 16:44:52 -0800150 } else {
151 WriteLine("");
152 WriteLine(MAGENTA " HANG TIME" RESET);
153 WriteLine("");
154 WriteLine(
155 " ... until a debugger joins. System is waiting in a while(1)");
Henri Chataing77f2f352021-07-29 14:29:21 +0000156 while (true) {
Ewout van Bekkumf7a5b512020-12-29 16:44:52 -0800157 }
158 }
159 PW_UNREACHABLE;
160 } else {
161 WriteLine("");
162 WriteLine(MAGENTA " NOTE: YOU ARE IN ASSERT BASIC TEST MODE" RESET);
163 WriteLine("");
164 WriteLine(" This build returns from the crash handler for testing.");
165 WriteLine(" If you see this message in production, your build is ");
166 WriteLine(" incorrectly configured. Search for");
167 WriteLine(" PW_ASSERT_BASIC_DISABLE_NORETURN to fix it.");
168 WriteLine("");
169 }
170}