blob: 837ce52786bf26324e65cf2e1a52b97776e01f83 [file] [log] [blame]
Keir Mierle3cee8792020-01-22 17:08:13 -08001// Copyright 2020 The Pigweed Authors
2//
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
20#include "pw_assert_basic/assert_basic.h"
21
22#include <cstring>
23
Keir Mierle3cee8792020-01-22 17:08:13 -080024#include "pw_preprocessor/util.h"
25#include "pw_string/string_builder.h"
Armando Montanezf7a5a742020-03-02 14:58:59 -080026#include "pw_sys_io/sys_io.h"
Keir Mierle3cee8792020-01-22 17:08:13 -080027
Keir Mierle52e4acc2020-04-15 21:20:21 -070028// If 1, call C's standard abort() function on assert failure.
29#ifndef PW_ASSERT_BASIC_ABORT
30#define PW_ASSERT_BASIC_ABORT 1
31#endif // PW_ASSERT_BASIC_ABORT
32
Keir Mierle3cee8792020-01-22 17:08:13 -080033// TODO(pwbug/17): Expose these through the config system.
34#define PW_ASSERT_BASIC_SHOW_BANNER 1
35#define PW_ASSERT_BASIC_USE_COLORS 1
36
37// ANSI color constants to control the terminal. Not Windows compatible.
38// clang-format off
39#if PW_ASSERT_BASIC_USE_COLORS
40#define MAGENTA "\033[35m"
41#define YELLOW "\033[33m"
42#define RED "\033[31m"
43#define GREEN "\033[32m"
44#define BLUE "\033[96m"
45#define BLACK "\033[30m"
46#define YELLOW_BG "\033[43m"
47#define WHITE_BG "\033[47m"
48#define RED_BG "\033[41m"
49#define BOLD "\033[1m"
50#define RESET "\033[0m"
51#else
52#define MAGENTA ""
53#define YELLOW ""
54#define RED ""
55#define GREEN ""
56#define BLUE ""
57#define BLACK ""
58#define YELLOW_BG ""
59#define WHITE_BG ""
60#define RED_BG ""
61#define BOLD ""
62#define RESET ""
63#endif // PW_ASSERT_BASIC_USE_COLORS
64// clang-format on
65
66static const char* kCrashBanner[] = {
67 " ",
68 " ▄████▄ ██▀███ ▄▄▄ ██████ ██░ ██ ",
69 " ▒██▀ ▀█ ▓██ ▒ ██▒ ▒████▄ ▒██ ▒ ▓██░ ██▒ ",
70 " ▒▓█ 💥 ▄ ▓██ ░▄█ ▒ ▒██ ▀█▄ ░ ▓██▄ ▒██▀▀██░ ",
71 " ▒▓▓▄ ▄██▒ ▒██▀▀█▄ ░██▄▄▄▄██ ▒ ██▒ ░▓█ ░██ ",
72 " ▒ ▓███▀ ░ ░██▓ ▒██▒ ▓█ ▓██▒ ▒██████▒▒ ░▓█▒░██▓ ",
73 " ░ ░▒ ▒ ░ ░ ▒▓ ░▒▓░ ▒▒ ▓▒█░ ▒ ▒▓▒ ▒ ░ ▒ ░░▒░▒ ",
74 " ░ ▒ ░▒ ░ ▒░ ▒ ▒▒ ░ ░ ░▒ ░ ░ ▒ ░▒░ ░ ",
75 " ░ ░░ ░ ░ ▒ ░ ░ ░ ░ ░░ ░ ",
76 " ░ ░ ░ ░ ░ ░ ░ ░ ░ ",
77 " ░",
78 " ",
79};
80
Armando Montanezf7a5a742020-03-02 14:58:59 -080081using pw::sys_io::WriteLine;
Keir Mierle3cee8792020-01-22 17:08:13 -080082
83typedef pw::StringBuffer<150> Buffer;
84
85extern "C" void pw_Crash(const char* file_name,
86 int line_number,
87 const char* function_name,
88 const char* message,
89 ...) {
90 // As a matter of usability, crashes should be visible; make it so.
91#if PW_ASSERT_BASIC_SHOW_BANNER
92 WriteLine(RED);
93 for (const char* line : kCrashBanner) {
94 WriteLine(line);
95 }
96 WriteLine(RESET);
97#endif // PW_ASSERT_BASIC_SHOW_BANNER
98
99 WriteLine(
100 " Welp, that didn't go as planned. "
101 "It seems we crashed. Terribly sorry!");
102 WriteLine("");
103 WriteLine(YELLOW " CRASH MESSAGE" RESET);
104 WriteLine("");
105 {
106 Buffer buffer;
107 buffer << " ";
108 va_list args;
109 va_start(args, message);
110 buffer.FormatVaList(message, args);
111 va_end(args);
Armando Montanezf7a5a742020-03-02 14:58:59 -0800112 WriteLine(buffer.view());
Keir Mierle3cee8792020-01-22 17:08:13 -0800113 }
114
115 WriteLine("");
116 WriteLine(YELLOW " CRASH FILE & LINE" RESET);
117 WriteLine("");
118 {
119 Buffer buffer;
120 buffer.Format(" %s:%d", file_name, line_number);
121 WriteLine(buffer.view());
122 }
123 WriteLine("");
124 WriteLine(YELLOW " CRASH FUNCTION" RESET);
125 WriteLine("");
126 {
127 Buffer buffer;
128 buffer.Format(" %s", function_name);
129 WriteLine(buffer.view());
130 }
131 WriteLine("");
132
133 // TODO(pwbug/95): Perhaps surprisingly, this doesn't actually crash the
134 // device. At some point we'll have a reboot BSP function or similar, but for
135 // now this is acceptable since no one is using this basic backend.
136 if (!PW_ASSERT_BASIC_DISABLE_NORETURN) {
Keir Mierle52e4acc2020-04-15 21:20:21 -0700137 if (PW_ASSERT_BASIC_ABORT) {
138 abort();
139 } else {
140 WriteLine(MAGENTA " HANG TIME" RESET);
141 WriteLine("");
142 WriteLine(
143 " ... until a debugger joins. System is waiting in a while(1)");
144 while (1) {
145 }
Keir Mierle3cee8792020-01-22 17:08:13 -0800146 }
147 PW_UNREACHABLE;
148 } else {
149 WriteLine(MAGENTA " NOTE: YOU ARE IN ASSERT BASIC TEST MODE" RESET);
150 WriteLine("");
151 WriteLine(" This build returns from the crash handler for testing.");
152 WriteLine(" If you see this message in production, your build is ");
153 WriteLine(" incorrectly configured. Search for");
154 WriteLine(" PW_ASSERT_BASIC_DISABLE_NORETURN to fix it.");
155 WriteLine("");
156 }
157}