blob: 3ebae59dd521a60d2981675cc9604876846fdc8c [file] [log] [blame]
Eric Kunzee5e26762020-10-13 16:11:07 -07001
Jerry Ge9c9c8da2023-07-19 23:08:16 +00002// Copyright (c) 2020-2023, ARM Limited.
Eric Kunzee5e26762020-10-13 16:11:07 -07003//
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>
Jerry Ge9c9c8da2023-07-19 23:08:16 +000018#include <sstream>
Eric Kunzee5e26762020-10-13 16:11:07 -070019#include <stdarg.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/types.h>
24
25#ifndef _MSC_VER
26#include <execinfo.h>
Jack Frankland140c5402023-08-12 13:49:26 +010027#if !defined(__APPLE__) && !defined(__MACH__)
Eric Kunzee5e26762020-10-13 16:11:07 -070028#include <sys/prctl.h>
Jack Frankland140c5402023-08-12 13:49:26 +010029#endif
Eric Kunzee5e26762020-10-13 16:11:07 -070030#include <sys/ptrace.h>
31#include <sys/wait.h>
32#include <unistd.h>
33#endif
34
35#include "func_debug.h"
36
37#define MAX_FRAMES 100
38
Eric Kunze286f8342022-06-22 11:30:23 -070039static bool str_case_equal(const std::string& a, const std::string& b)
40{
41 return std::equal(a.begin(), a.end(), b.begin(), b.end(),
42 [](char ac, char bc) { return tolower(ac) == tolower(bc); });
43}
44
Jack Frankland140c5402023-08-12 13:49:26 +010045#if !defined(_MSC_VER) && !defined(__APPLE__) && !defined(__MACH__)
Eric Kunzee5e26762020-10-13 16:11:07 -070046pid_t func_print_backtrace_helper(int num_tries, int sig);
47#endif
48
49void func_print_backtrace(FILE* out, int sig)
50{
Jack Frankland140c5402023-08-12 13:49:26 +010051#if !defined(_MSC_VER) && !defined(__APPLE__) && !defined(__MACH__)
Eric Kunzee5e26762020-10-13 16:11:07 -070052 for (int i = 0; i < 2; i++)
53 {
54 const pid_t child_pid = func_print_backtrace_helper(i, sig);
55 if (child_pid < 0)
56 {
57 perror("Backtrace generation failed on fork");
58 break;
59 }
60
61 int status = 0;
62 waitpid(child_pid, &status, 0);
63 if (WEXITSTATUS(status) == 0)
64 {
65 break;
66 }
67 }
68#endif
69}
70
Jack Frankland140c5402023-08-12 13:49:26 +010071#if !defined(_MSC_VER) && !defined(__APPLE__) && !defined(__MACH__)
Eric Kunzee5e26762020-10-13 16:11:07 -070072pid_t func_print_backtrace_helper(int num_tries, int sig)
73{
74 const pid_t child_pid = fork();
75
76 if (child_pid)
77 {
78 return 0;
79 }
80
81 const pid_t ppid = getppid();
82
83 printf("Attaching debugger to pid %d\n", ppid);
84 // Check if we're in a debugger
85 if (ptrace(PTRACE_ATTACH, ppid, 0, 0) == 0)
86 {
87 // If we reach this point, no debugger is present
88 // Undo effects of PTRACE_ATTACH
89 waitpid(ppid, NULL, 0);
90 ptrace(PTRACE_CONT, 0, 0, 0);
91 ptrace(PTRACE_DETACH, ppid, 0, 0);
92
93 dup2(STDERR_FILENO, STDOUT_FILENO);
94
95 char parent_pid[20];
96 snprintf(parent_pid, sizeof(parent_pid), "attach %d", ppid);
97 fprintf(stdout, "Caught signal %d (%s)\n", sig, strsignal(sig));
98
99 execlp("gdb", "gdb", "--batch", "-n", "-ex",
100 // Don't print startup messages for each thread
101 "-ex", "set print thread-events off", "-ex", parent_pid,
102 // Turn off pagination
103 "-ex", "set height 0",
104 // Print a backtrace for the current thread
105 "-ex", "thread $_thread", "-ex", "bt",
106 // Print a backtrace for the main thread (uncomment the next two lines, if desired)
107 //"-ex", "thread 1",
108 //"-ex", "bt",
109 // Print a backtrace for all thread (TMI)
110 //"-ex", "thread apply all bt",
111 NULL);
112
113 // If we reach this point, it is bad. Attempt to print an error before exiting.
114 perror("Backtrace generation failed to invoke gdb");
115 exit(1);
116 }
117
118 // Debugger present. Exit here.
119 exit(0);
120
121 return 0;
122}
123#endif
124
125void func_backtrace_signal_handler(int sig)
126{
127 func_print_backtrace(NULL, sig);
128 exit(1);
129}
130
131// Note: this overwrites other signal handlers. May want to make this
132// more friendly sometime
133void func_enable_signal_handlers()
134{
135 static const int sig_list[] = { SIGABRT, SIGSEGV, SIGILL, SIGFPE };
136
137 if (getenv("FUNC_NO_SIG_HANDLERS"))
138 {
139 return;
140 }
141
142 for (size_t i = 0; i < sizeof(sig_list) / sizeof(int); i++)
143 {
144 struct sigaction act;
145
146 bzero(&act, sizeof(act));
147 act.sa_handler = func_backtrace_signal_handler;
148
149 if (sigaction(sig_list[i], &act, NULL))
150 {
151 perror("Error calling sigaction");
152 }
153 }
154}
155
Eric Kunze286f8342022-06-22 11:30:23 -0700156static const std::vector<std::pair<std::string, uint32_t>> func_debug_verbosity_table = {
157 { "NONE", DEBUG_VERB_NONE }, { "INFO", DEBUG_VERB_INFO }, { "IFACE", DEBUG_VERB_IFACE },
158 { "LOW", DEBUG_VERB_LOW }, { "MED", DEBUG_VERB_MED }, { "HIGH", DEBUG_VERB_HIGH }
Eric Kunzee5e26762020-10-13 16:11:07 -0700159};
160
Eric Kunzee5e26762020-10-13 16:11:07 -0700161// Initialize the debug mode
Eric Kunze286f8342022-06-22 11:30:23 -0700162int func_debug_t::init_debug(uint64_t inst_id)
Eric Kunzee5e26762020-10-13 16:11:07 -0700163{
164 // Set the default debug settings
Eric Kunze286f8342022-06-22 11:30:23 -0700165 set_mask(static_cast<uint64_t>(DEBUG_NONE));
166 set_verbosity(DEBUG_VERB_NONE);
167 set_inst_mask(DEBUG_INST_ALL);
168 func_debug_file = stderr;
Jerry Ge9c9c8da2023-07-19 23:08:16 +0000169 this->inst_id = inst_id;
Eric Kunzee5e26762020-10-13 16:11:07 -0700170
171 return 0;
172}
173
Eric Kunze286f8342022-06-22 11:30:23 -0700174int func_debug_t::fini_debug()
Eric Kunzee5e26762020-10-13 16:11:07 -0700175{
Eric Kunzee5e26762020-10-13 16:11:07 -0700176 return 0;
177}
178
Eric Kunze286f8342022-06-22 11:30:23 -0700179int func_debug_t::set_file(const std::string& filename)
Eric Kunzee5e26762020-10-13 16:11:07 -0700180{
Eric Kunzee5e26762020-10-13 16:11:07 -0700181 // Open the debug output file
Eric Kunze286f8342022-06-22 11:30:23 -0700182 func_debug_file = fopen(filename.c_str(), "w");
Eric Kunzee5e26762020-10-13 16:11:07 -0700183
Eric Kunze286f8342022-06-22 11:30:23 -0700184 if (!func_debug_file)
Eric Kunzee5e26762020-10-13 16:11:07 -0700185 {
186 perror(NULL);
Eric Kunze286f8342022-06-22 11:30:23 -0700187 FATAL_ERROR("Cannot open debug output file: %s\n", filename.c_str());
Eric Kunzee5e26762020-10-13 16:11:07 -0700188 return 1;
189 }
Eric Kunze286f8342022-06-22 11:30:23 -0700190 if (is_output_unbuffered)
Eric Kunzee5e26762020-10-13 16:11:07 -0700191 {
Eric Kunze286f8342022-06-22 11:30:23 -0700192 setvbuf(func_debug_file, nullptr, _IONBF, 0);
Eric Kunzee5e26762020-10-13 16:11:07 -0700193 }
194
195 return 0;
196}
197
Eric Kunze286f8342022-06-22 11:30:23 -0700198void func_debug_t::set_verbosity(const std::string& str)
Eric Kunzee5e26762020-10-13 16:11:07 -0700199{
Eric Kunze286f8342022-06-22 11:30:23 -0700200 for (auto& verb : func_debug_verbosity_table)
Eric Kunzee5e26762020-10-13 16:11:07 -0700201 {
Eric Kunze286f8342022-06-22 11:30:23 -0700202 if (str_case_equal(str, verb.first))
Eric Kunzee5e26762020-10-13 16:11:07 -0700203 {
Eric Kunze286f8342022-06-22 11:30:23 -0700204 set_verbosity(verb.second);
Eric Kunzee5e26762020-10-13 16:11:07 -0700205 return;
206 }
207 }
208
Eric Kunze286f8342022-06-22 11:30:23 -0700209 FATAL_ERROR("Invalid debug verbosity: %s", str.c_str());
Eric Kunzee5e26762020-10-13 16:11:07 -0700210}
211
Eric Kunze286f8342022-06-22 11:30:23 -0700212void func_debug_t::set_verbosity(const uint32_t verb)
Eric Kunzee5e26762020-10-13 16:11:07 -0700213{
214 uint32_t new_mask = verb;
215
216 switch (verb)
217 {
218 case DEBUG_VERB_NONE:
219 new_mask = DEBUG_VERB_NONE;
220 break;
221 case DEBUG_VERB_INFO:
222 new_mask = DEBUG_VERB_INFO;
223 break;
224 case DEBUG_VERB_IFACE:
225 new_mask = DEBUG_VERB_IFACE;
226 break;
227 case DEBUG_VERB_HIGH:
228 new_mask |= DEBUG_VERB_HIGH;
229 // Intentional fallthrough
230 case DEBUG_VERB_MED:
231 new_mask |= DEBUG_VERB_MED;
232 // Intentional fallthrough
233 case DEBUG_VERB_LOW:
234 new_mask |= DEBUG_VERB_LOW;
235 new_mask |= DEBUG_VERB_INFO;
236 new_mask |= DEBUG_VERB_IFACE;
237 break;
238 }
239
Eric Kunze286f8342022-06-22 11:30:23 -0700240 func_debug_verbosity = new_mask;
Eric Kunzee5e26762020-10-13 16:11:07 -0700241}
242
Eric Kunze286f8342022-06-22 11:30:23 -0700243void func_debug_t::set_mask(const uint64_t mask)
Eric Kunzee5e26762020-10-13 16:11:07 -0700244{
245 if (mask == DEBUG_NONE)
Eric Kunze286f8342022-06-22 11:30:23 -0700246 func_debug_mask = mask;
Eric Kunzee5e26762020-10-13 16:11:07 -0700247 else
Eric Kunze286f8342022-06-22 11:30:23 -0700248 func_debug_mask |= mask;
Eric Kunzee5e26762020-10-13 16:11:07 -0700249
250 // Set a minimum verbosity level
Eric Kunze286f8342022-06-22 11:30:23 -0700251 if (func_debug_verbosity == DEBUG_VERB_NONE)
252 func_debug_verbosity = DEBUG_VERB_INFO;
Eric Kunzee5e26762020-10-13 16:11:07 -0700253}
254
Eric Kunze286f8342022-06-22 11:30:23 -0700255void func_debug_t::set_inst_mask(const char* mask)
Eric Kunzee5e26762020-10-13 16:11:07 -0700256{
257 uint64_t val;
258
259 val = strtoul(mask, NULL, 0);
260
Eric Kunze286f8342022-06-22 11:30:23 -0700261 return set_inst_mask(val);
Eric Kunzee5e26762020-10-13 16:11:07 -0700262}
263
Eric Kunze286f8342022-06-22 11:30:23 -0700264void func_debug_t::set_inst_mask(const uint64_t mask)
Eric Kunzee5e26762020-10-13 16:11:07 -0700265{
266 if (mask == 0)
Eric Kunze286f8342022-06-22 11:30:23 -0700267 func_debug_inst_mask = DEBUG_INST_ALL;
Eric Kunzee5e26762020-10-13 16:11:07 -0700268 else
Eric Kunze286f8342022-06-22 11:30:23 -0700269 func_debug_inst_mask = mask;
Eric Kunzee5e26762020-10-13 16:11:07 -0700270}
271
Eric Kunze286f8342022-06-22 11:30:23 -0700272std::vector<std::pair<std::string, int>> debug_str_table = {
Jerry Ge9c9c8da2023-07-19 23:08:16 +0000273#define DEBUG_MODE(NAME, BIT) { #NAME, DEBUG_##NAME },
Eric Kunze286f8342022-06-22 11:30:23 -0700274#include "debug_modes.def"
275#undef DEBUG_MODE
276};
277
278void func_debug_t::set_mask(const std::string& str)
Eric Kunzee5e26762020-10-13 16:11:07 -0700279{
Jeremy Johnson366f2972022-09-14 17:41:11 +0100280 if (str == "ALL")
Eric Kunzee5e26762020-10-13 16:11:07 -0700281 {
Eric Kunze286f8342022-06-22 11:30:23 -0700282 set_mask(UINT64_MAX - 1);
Eric Kunzee5e26762020-10-13 16:11:07 -0700283 return;
284 }
Eric Kunze286f8342022-06-22 11:30:23 -0700285 for (auto& mode : debug_str_table)
Eric Kunzee5e26762020-10-13 16:11:07 -0700286 {
Eric Kunze286f8342022-06-22 11:30:23 -0700287 if (mode.first == str)
Eric Kunzee5e26762020-10-13 16:11:07 -0700288 {
Eric Kunze286f8342022-06-22 11:30:23 -0700289 set_mask(mode.second);
Eric Kunzee5e26762020-10-13 16:11:07 -0700290 return;
291 }
292 }
Eric Kunze286f8342022-06-22 11:30:23 -0700293 print_masks(stderr);
Eric Kunzee5e26762020-10-13 16:11:07 -0700294
Eric Kunze286f8342022-06-22 11:30:23 -0700295 FATAL_ERROR("Invalid debug mask: %s", str.c_str());
Eric Kunzee5e26762020-10-13 16:11:07 -0700296}
297
Eric Kunze286f8342022-06-22 11:30:23 -0700298void func_debug_t::print_masks(FILE* out)
Eric Kunzee5e26762020-10-13 16:11:07 -0700299{
Eric Kunzee5e26762020-10-13 16:11:07 -0700300 fprintf(out, "Available debug masks:\n");
Eric Kunze286f8342022-06-22 11:30:23 -0700301 for (auto& mode : debug_str_table)
Eric Kunzee5e26762020-10-13 16:11:07 -0700302 {
Eric Kunze286f8342022-06-22 11:30:23 -0700303 fprintf(out, "[%d] %s\n", mode.second, mode.first.c_str());
Eric Kunzee5e26762020-10-13 16:11:07 -0700304 }
305}
306
Eric Kunze286f8342022-06-22 11:30:23 -0700307void func_debug_t::set_output_unbuffered(const bool is_unbuffered)
Eric Kunzee5e26762020-10-13 16:11:07 -0700308{
Eric Kunze286f8342022-06-22 11:30:23 -0700309 is_output_unbuffered = is_unbuffered;
Eric Kunzee5e26762020-10-13 16:11:07 -0700310}
311
312// Print warnings to the debug file or optionally store them in a buffer instead
313// Note that the buffer is circular and can be overwritten if enough messages are
314// written before removing a warning from the front.
315void func_debug_warning(
316 func_debug_t* func_debug, const char* file, const char* func, const int line, const char* fmt, ...)
317{
318 va_list args;
319 va_start(args, fmt);
320
Eric Kunze286f8342022-06-22 11:30:23 -0700321 // Print to the debug file (e.g., stderr)
322 fprintf(func_debug->func_debug_file, "WARNING AT %s:%d %s():\n", file, line, func);
323 vfprintf(func_debug->func_debug_file, fmt, args);
324 fprintf(func_debug->func_debug_file, "\n");
Eric Kunzee5e26762020-10-13 16:11:07 -0700325
Eric Kunzee5e26762020-10-13 16:11:07 -0700326 va_end(args);
327}
328
Eric Kunze286f8342022-06-22 11:30:23 -0700329std::string func_debug_t::get_debug_mask_help_string()
Eric Kunzee5e26762020-10-13 16:11:07 -0700330{
Eric Kunze286f8342022-06-22 11:30:23 -0700331 std::string rval = "Set debug mask. Valid values are: ";
Jerry Ge9c9c8da2023-07-19 23:08:16 +0000332 for (auto& mask : debug_str_table)
333 {
Eric Kunze286f8342022-06-22 11:30:23 -0700334 rval += mask.first + " ";
Eric Kunzee5e26762020-10-13 16:11:07 -0700335 }
Jeremy Johnson366f2972022-09-14 17:41:11 +0100336 rval += "ALL";
Eric Kunze286f8342022-06-22 11:30:23 -0700337 return rval;
338}
339
340std::string func_debug_t::get_debug_verbosity_help_string()
341{
342 std::string rval = "Set logging level. Valid values are: ";
343 for (auto& verb : func_debug_verbosity_table)
Eric Kunzee5e26762020-10-13 16:11:07 -0700344 {
Eric Kunze286f8342022-06-22 11:30:23 -0700345 rval += verb.first + " ";
Eric Kunzee5e26762020-10-13 16:11:07 -0700346 }
Eric Kunze286f8342022-06-22 11:30:23 -0700347 return rval;
348}