blob: 745d07630a77f2ce57864c7a4585fffd5f23e38c [file] [log] [blame]
Eric Kunzee5e26762020-10-13 16:11:07 -07001
2// Copyright (c) 2020, ARM Limited.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#include <ctype.h>
17#include <signal.h>
18#include <stdarg.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <sys/types.h>
Eric Kunze286f8342022-06-22 11:30:23 -070023#include <sstream>
Eric Kunzee5e26762020-10-13 16:11:07 -070024
25#ifndef _MSC_VER
26#include <execinfo.h>
27#include <sys/prctl.h>
28#include <sys/ptrace.h>
29#include <sys/wait.h>
30#include <unistd.h>
31#endif
32
33#include "func_debug.h"
34
35#define MAX_FRAMES 100
36
Eric Kunze286f8342022-06-22 11:30:23 -070037static bool str_case_equal(const std::string& a, const std::string& b)
38{
39 return std::equal(a.begin(), a.end(), b.begin(), b.end(),
40 [](char ac, char bc) { return tolower(ac) == tolower(bc); });
41}
42
Eric Kunzee5e26762020-10-13 16:11:07 -070043#ifndef _MSC_VER
44pid_t func_print_backtrace_helper(int num_tries, int sig);
45#endif
46
47void func_print_backtrace(FILE* out, int sig)
48{
49#ifndef _MSC_VER
50 for (int i = 0; i < 2; i++)
51 {
52 const pid_t child_pid = func_print_backtrace_helper(i, sig);
53 if (child_pid < 0)
54 {
55 perror("Backtrace generation failed on fork");
56 break;
57 }
58
59 int status = 0;
60 waitpid(child_pid, &status, 0);
61 if (WEXITSTATUS(status) == 0)
62 {
63 break;
64 }
65 }
66#endif
67}
68
69#ifndef _MSC_VER
70pid_t func_print_backtrace_helper(int num_tries, int sig)
71{
72 const pid_t child_pid = fork();
73
74 if (child_pid)
75 {
76 return 0;
77 }
78
79 const pid_t ppid = getppid();
80
81 printf("Attaching debugger to pid %d\n", ppid);
82 // Check if we're in a debugger
83 if (ptrace(PTRACE_ATTACH, ppid, 0, 0) == 0)
84 {
85 // If we reach this point, no debugger is present
86 // Undo effects of PTRACE_ATTACH
87 waitpid(ppid, NULL, 0);
88 ptrace(PTRACE_CONT, 0, 0, 0);
89 ptrace(PTRACE_DETACH, ppid, 0, 0);
90
91 dup2(STDERR_FILENO, STDOUT_FILENO);
92
93 char parent_pid[20];
94 snprintf(parent_pid, sizeof(parent_pid), "attach %d", ppid);
95 fprintf(stdout, "Caught signal %d (%s)\n", sig, strsignal(sig));
96
97 execlp("gdb", "gdb", "--batch", "-n", "-ex",
98 // Don't print startup messages for each thread
99 "-ex", "set print thread-events off", "-ex", parent_pid,
100 // Turn off pagination
101 "-ex", "set height 0",
102 // Print a backtrace for the current thread
103 "-ex", "thread $_thread", "-ex", "bt",
104 // Print a backtrace for the main thread (uncomment the next two lines, if desired)
105 //"-ex", "thread 1",
106 //"-ex", "bt",
107 // Print a backtrace for all thread (TMI)
108 //"-ex", "thread apply all bt",
109 NULL);
110
111 // If we reach this point, it is bad. Attempt to print an error before exiting.
112 perror("Backtrace generation failed to invoke gdb");
113 exit(1);
114 }
115
116 // Debugger present. Exit here.
117 exit(0);
118
119 return 0;
120}
121#endif
122
123void func_backtrace_signal_handler(int sig)
124{
125 func_print_backtrace(NULL, sig);
126 exit(1);
127}
128
129// Note: this overwrites other signal handlers. May want to make this
130// more friendly sometime
131void func_enable_signal_handlers()
132{
133 static const int sig_list[] = { SIGABRT, SIGSEGV, SIGILL, SIGFPE };
134
135 if (getenv("FUNC_NO_SIG_HANDLERS"))
136 {
137 return;
138 }
139
140 for (size_t i = 0; i < sizeof(sig_list) / sizeof(int); i++)
141 {
142 struct sigaction act;
143
144 bzero(&act, sizeof(act));
145 act.sa_handler = func_backtrace_signal_handler;
146
147 if (sigaction(sig_list[i], &act, NULL))
148 {
149 perror("Error calling sigaction");
150 }
151 }
152}
153
Eric Kunze286f8342022-06-22 11:30:23 -0700154static const std::vector<std::pair<std::string, uint32_t>> func_debug_verbosity_table = {
155 { "NONE", DEBUG_VERB_NONE }, { "INFO", DEBUG_VERB_INFO }, { "IFACE", DEBUG_VERB_IFACE },
156 { "LOW", DEBUG_VERB_LOW }, { "MED", DEBUG_VERB_MED }, { "HIGH", DEBUG_VERB_HIGH }
Eric Kunzee5e26762020-10-13 16:11:07 -0700157};
158
Eric Kunzee5e26762020-10-13 16:11:07 -0700159// Initialize the debug mode
Eric Kunze286f8342022-06-22 11:30:23 -0700160int func_debug_t::init_debug(uint64_t inst_id)
Eric Kunzee5e26762020-10-13 16:11:07 -0700161{
162 // Set the default debug settings
Eric Kunze286f8342022-06-22 11:30:23 -0700163 set_mask(static_cast<uint64_t>(DEBUG_NONE));
164 set_verbosity(DEBUG_VERB_NONE);
165 set_inst_mask(DEBUG_INST_ALL);
166 func_debug_file = stderr;
167 this->inst_id = inst_id;
Eric Kunzee5e26762020-10-13 16:11:07 -0700168
169 return 0;
170}
171
Eric Kunze286f8342022-06-22 11:30:23 -0700172int func_debug_t::fini_debug()
Eric Kunzee5e26762020-10-13 16:11:07 -0700173{
Eric Kunzee5e26762020-10-13 16:11:07 -0700174 return 0;
175}
176
Eric Kunze286f8342022-06-22 11:30:23 -0700177int func_debug_t::set_file(const std::string& filename)
Eric Kunzee5e26762020-10-13 16:11:07 -0700178{
Eric Kunzee5e26762020-10-13 16:11:07 -0700179 // Open the debug output file
Eric Kunze286f8342022-06-22 11:30:23 -0700180 func_debug_file = fopen(filename.c_str(), "w");
Eric Kunzee5e26762020-10-13 16:11:07 -0700181
Eric Kunze286f8342022-06-22 11:30:23 -0700182 if (!func_debug_file)
Eric Kunzee5e26762020-10-13 16:11:07 -0700183 {
184 perror(NULL);
Eric Kunze286f8342022-06-22 11:30:23 -0700185 FATAL_ERROR("Cannot open debug output file: %s\n", filename.c_str());
Eric Kunzee5e26762020-10-13 16:11:07 -0700186 return 1;
187 }
Eric Kunze286f8342022-06-22 11:30:23 -0700188 if (is_output_unbuffered)
Eric Kunzee5e26762020-10-13 16:11:07 -0700189 {
Eric Kunze286f8342022-06-22 11:30:23 -0700190 setvbuf(func_debug_file, nullptr, _IONBF, 0);
Eric Kunzee5e26762020-10-13 16:11:07 -0700191 }
192
193 return 0;
194}
195
Eric Kunze286f8342022-06-22 11:30:23 -0700196void func_debug_t::set_verbosity(const std::string& str)
Eric Kunzee5e26762020-10-13 16:11:07 -0700197{
Eric Kunze286f8342022-06-22 11:30:23 -0700198 for (auto& verb : func_debug_verbosity_table)
Eric Kunzee5e26762020-10-13 16:11:07 -0700199 {
Eric Kunze286f8342022-06-22 11:30:23 -0700200 if (str_case_equal(str, verb.first))
Eric Kunzee5e26762020-10-13 16:11:07 -0700201 {
Eric Kunze286f8342022-06-22 11:30:23 -0700202 set_verbosity(verb.second);
Eric Kunzee5e26762020-10-13 16:11:07 -0700203 return;
204 }
205 }
206
Eric Kunze286f8342022-06-22 11:30:23 -0700207 FATAL_ERROR("Invalid debug verbosity: %s", str.c_str());
Eric Kunzee5e26762020-10-13 16:11:07 -0700208}
209
Eric Kunze286f8342022-06-22 11:30:23 -0700210void func_debug_t::set_verbosity(const uint32_t verb)
Eric Kunzee5e26762020-10-13 16:11:07 -0700211{
212 uint32_t new_mask = verb;
213
214 switch (verb)
215 {
216 case DEBUG_VERB_NONE:
217 new_mask = DEBUG_VERB_NONE;
218 break;
219 case DEBUG_VERB_INFO:
220 new_mask = DEBUG_VERB_INFO;
221 break;
222 case DEBUG_VERB_IFACE:
223 new_mask = DEBUG_VERB_IFACE;
224 break;
225 case DEBUG_VERB_HIGH:
226 new_mask |= DEBUG_VERB_HIGH;
227 // Intentional fallthrough
228 case DEBUG_VERB_MED:
229 new_mask |= DEBUG_VERB_MED;
230 // Intentional fallthrough
231 case DEBUG_VERB_LOW:
232 new_mask |= DEBUG_VERB_LOW;
233 new_mask |= DEBUG_VERB_INFO;
234 new_mask |= DEBUG_VERB_IFACE;
235 break;
236 }
237
Eric Kunze286f8342022-06-22 11:30:23 -0700238 func_debug_verbosity = new_mask;
Eric Kunzee5e26762020-10-13 16:11:07 -0700239}
240
Eric Kunze286f8342022-06-22 11:30:23 -0700241void func_debug_t::set_mask(const uint64_t mask)
Eric Kunzee5e26762020-10-13 16:11:07 -0700242{
243 if (mask == DEBUG_NONE)
Eric Kunze286f8342022-06-22 11:30:23 -0700244 func_debug_mask = mask;
Eric Kunzee5e26762020-10-13 16:11:07 -0700245 else
Eric Kunze286f8342022-06-22 11:30:23 -0700246 func_debug_mask |= mask;
Eric Kunzee5e26762020-10-13 16:11:07 -0700247
248 // Set a minimum verbosity level
Eric Kunze286f8342022-06-22 11:30:23 -0700249 if (func_debug_verbosity == DEBUG_VERB_NONE)
250 func_debug_verbosity = DEBUG_VERB_INFO;
Eric Kunzee5e26762020-10-13 16:11:07 -0700251}
252
Eric Kunze286f8342022-06-22 11:30:23 -0700253void func_debug_t::set_inst_mask(const char* mask)
Eric Kunzee5e26762020-10-13 16:11:07 -0700254{
255 uint64_t val;
256
257 val = strtoul(mask, NULL, 0);
258
Eric Kunze286f8342022-06-22 11:30:23 -0700259 return set_inst_mask(val);
Eric Kunzee5e26762020-10-13 16:11:07 -0700260}
261
Eric Kunze286f8342022-06-22 11:30:23 -0700262void func_debug_t::set_inst_mask(const uint64_t mask)
Eric Kunzee5e26762020-10-13 16:11:07 -0700263{
264 if (mask == 0)
Eric Kunze286f8342022-06-22 11:30:23 -0700265 func_debug_inst_mask = DEBUG_INST_ALL;
Eric Kunzee5e26762020-10-13 16:11:07 -0700266 else
Eric Kunze286f8342022-06-22 11:30:23 -0700267 func_debug_inst_mask = mask;
Eric Kunzee5e26762020-10-13 16:11:07 -0700268}
269
Eric Kunze286f8342022-06-22 11:30:23 -0700270std::vector<std::pair<std::string, int>> debug_str_table = {
Jeremy Johnson366f2972022-09-14 17:41:11 +0100271#define DEBUG_MODE(NAME, BIT) {#NAME, DEBUG_##NAME},
Eric Kunze286f8342022-06-22 11:30:23 -0700272#include "debug_modes.def"
273#undef DEBUG_MODE
274};
275
276void func_debug_t::set_mask(const std::string& str)
Eric Kunzee5e26762020-10-13 16:11:07 -0700277{
Jeremy Johnson366f2972022-09-14 17:41:11 +0100278 if (str == "ALL")
Eric Kunzee5e26762020-10-13 16:11:07 -0700279 {
Eric Kunze286f8342022-06-22 11:30:23 -0700280 set_mask(UINT64_MAX - 1);
Eric Kunzee5e26762020-10-13 16:11:07 -0700281 return;
282 }
Eric Kunze286f8342022-06-22 11:30:23 -0700283 for (auto& mode : debug_str_table)
Eric Kunzee5e26762020-10-13 16:11:07 -0700284 {
Eric Kunze286f8342022-06-22 11:30:23 -0700285 if (mode.first == str)
Eric Kunzee5e26762020-10-13 16:11:07 -0700286 {
Eric Kunze286f8342022-06-22 11:30:23 -0700287 set_mask(mode.second);
Eric Kunzee5e26762020-10-13 16:11:07 -0700288 return;
289 }
290 }
Eric Kunze286f8342022-06-22 11:30:23 -0700291 print_masks(stderr);
Eric Kunzee5e26762020-10-13 16:11:07 -0700292
Eric Kunze286f8342022-06-22 11:30:23 -0700293 FATAL_ERROR("Invalid debug mask: %s", str.c_str());
Eric Kunzee5e26762020-10-13 16:11:07 -0700294}
295
Eric Kunze286f8342022-06-22 11:30:23 -0700296void func_debug_t::print_masks(FILE* out)
Eric Kunzee5e26762020-10-13 16:11:07 -0700297{
Eric Kunzee5e26762020-10-13 16:11:07 -0700298 fprintf(out, "Available debug masks:\n");
Eric Kunze286f8342022-06-22 11:30:23 -0700299 for (auto& mode : debug_str_table)
Eric Kunzee5e26762020-10-13 16:11:07 -0700300 {
Eric Kunze286f8342022-06-22 11:30:23 -0700301 fprintf(out, "[%d] %s\n", mode.second, mode.first.c_str());
Eric Kunzee5e26762020-10-13 16:11:07 -0700302 }
303}
304
Eric Kunze286f8342022-06-22 11:30:23 -0700305void func_debug_t::set_output_unbuffered(const bool is_unbuffered)
Eric Kunzee5e26762020-10-13 16:11:07 -0700306{
Eric Kunze286f8342022-06-22 11:30:23 -0700307 is_output_unbuffered = is_unbuffered;
Eric Kunzee5e26762020-10-13 16:11:07 -0700308}
309
310// Print warnings to the debug file or optionally store them in a buffer instead
311// Note that the buffer is circular and can be overwritten if enough messages are
312// written before removing a warning from the front.
313void func_debug_warning(
314 func_debug_t* func_debug, const char* file, const char* func, const int line, const char* fmt, ...)
315{
316 va_list args;
317 va_start(args, fmt);
318
Eric Kunze286f8342022-06-22 11:30:23 -0700319 // Print to the debug file (e.g., stderr)
320 fprintf(func_debug->func_debug_file, "WARNING AT %s:%d %s():\n", file, line, func);
321 vfprintf(func_debug->func_debug_file, fmt, args);
322 fprintf(func_debug->func_debug_file, "\n");
Eric Kunzee5e26762020-10-13 16:11:07 -0700323
Eric Kunzee5e26762020-10-13 16:11:07 -0700324 va_end(args);
325}
326
Eric Kunze286f8342022-06-22 11:30:23 -0700327std::string func_debug_t::get_debug_mask_help_string()
Eric Kunzee5e26762020-10-13 16:11:07 -0700328{
Eric Kunze286f8342022-06-22 11:30:23 -0700329 std::string rval = "Set debug mask. Valid values are: ";
330 for (auto& mask : debug_str_table) {
331 rval += mask.first + " ";
Eric Kunzee5e26762020-10-13 16:11:07 -0700332 }
Jeremy Johnson366f2972022-09-14 17:41:11 +0100333 rval += "ALL";
Eric Kunze286f8342022-06-22 11:30:23 -0700334 return rval;
335}
336
337std::string func_debug_t::get_debug_verbosity_help_string()
338{
339 std::string rval = "Set logging level. Valid values are: ";
340 for (auto& verb : func_debug_verbosity_table)
Eric Kunzee5e26762020-10-13 16:11:07 -0700341 {
Eric Kunze286f8342022-06-22 11:30:23 -0700342 rval += verb.first + " ";
Eric Kunzee5e26762020-10-13 16:11:07 -0700343 }
Eric Kunze286f8342022-06-22 11:30:23 -0700344 return rval;
345}