Motr  M0
uassert.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2013-2020 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
23 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_LIB
24 #include "lib/trace.h"
25 
26 #ifdef HAVE_BACKTRACE
27 # include <execinfo.h> /* backtrace */
28 #endif
29 #include <sys/types.h> /* waitpid */
30 #include <sys/wait.h> /* waitpid */
31 #include <linux/limits.h> /* PATH_MAX */
32 #include <stdio.h> /* fprintf */
33 #include <stdlib.h> /* abort */
34 #include <unistd.h> /* fork, sleep */
35 #include "lib/errno.h"
36 #include "lib/assert.h"
37 #include "lib/trace_internal.h" /* m0_trace_file_path_get */
38 #include "lib/misc.h" /* ARRAY_SIZE */
39 #include "motr/version.h" /* m0_build_info */
40 
48 enum { BACKTRACE_DEPTH_MAX = 256 };
49 
50 M0_EXTERN char *m0_debugger_args[4];
51 
52 #ifdef ENABLE_DETAILED_BACKTRACE
53 static void arch_backtrace_detailed(void)
54 {
55  const char *gdb_path = "/usr/bin/gdb";
56  const char *gdb_cmd = "thread apply all bt";
57  pid_t pid;
58  char pid_str[32];
59  char path_str[PATH_MAX];
60  ssize_t path_str_len;
61 
62  fprintf(stderr, "Trying to recover detailed backtrace...\n");
63  fflush(stderr);
64 
65  snprintf(pid_str, sizeof(pid_str), "%ld", (long) getpid());
66  path_str_len = readlink("/proc/self/exe",
67  path_str, sizeof(path_str) - 1);
68  if (path_str_len == -1)
69  return;
70  path_str[path_str_len] = '\0';
71 
72  pid = fork();
73  if (pid > 0) {
74  /* parent */
75  waitpid(pid, NULL, 0);
76  } else if (pid == 0) {
77  /* child */
78  dup2(STDERR_FILENO, STDOUT_FILENO);
79  execl(gdb_path, gdb_path, "-batch", "-nx", "-ex", gdb_cmd,
80  path_str, pid_str, NULL);
81  /* if execl() failed */
82  _exit(EXIT_SUCCESS);
83  } else {
84  /* fork() failed, nothing to do */
85  }
86 }
87 #endif
88 
89 void m0_arch_backtrace(void)
90 {
91 #ifdef HAVE_BACKTRACE
92  void *trace[BACKTRACE_DEPTH_MAX];
93  int nr;
94 
95  nr = backtrace(trace, ARRAY_SIZE(trace));
96  backtrace_symbols_fd(trace, nr, STDERR_FILENO);
97 #endif
98 #ifdef ENABLE_DETAILED_BACKTRACE
99  arch_backtrace_detailed();
100 #endif
101 }
102 
111 M0_INTERNAL void m0_arch_panic(const struct m0_panic_ctx *c, va_list ap)
112 {
113  const struct m0_build_info *bi = m0_build_info_get();
114 
115  fprintf(stderr,
116  "Motr panic: %s at %s() %s:%i (errno: %i) (last failed: %s)"
117  " [git: %s] pid: %u %s\n",
118  c->pc_expr, c->pc_func, c->pc_file, c->pc_lineno, errno,
119  m0_failed_condition ?: "none", bi->bi_git_describe,
120  (unsigned)getpid(), m0_trace_file_path_get());
121  if (c->pc_fmt != NULL) {
122  fprintf(stderr, "Motr panic reason: ");
123  vfprintf(stderr, c->pc_fmt, ap);
124  fprintf(stderr, "\n");
125  }
126  fflush(stderr);
127 
130 
131  abort();
132 }
133 
134 M0_INTERNAL void m0_debugger_invoke(void)
135 {
136  const char *debugger = m0_debugger_args[0];
137 
138  if (debugger == NULL) {
139  ; /* nothing */
140  } else if (!strcmp(debugger, "wait")) {
141  fprintf(stderr, "Motr pid %u waits for debugger.\n", getpid());
142  fflush(stderr);
143  while (1)
144  sleep(1);
145  } else {
146  int rc;
147 
148  rc = fork();
149  if (rc > 0) {
150  /* parent */
151  volatile bool stop = true;
152 
153  while (stop) {
154  ;
155  }
156  } else if (rc == 0) {
157  /* child */
158  rc = execvp(m0_debugger_args[0], m0_debugger_args);
159  M0_IMPOSSIBLE("execvp() failed with rc=%d errno=%d",
160  rc, errno);
161  }
162  }
163 }
164 
166 #undef M0_TRACE_SUBSYSTEM
167 
168 /*
169  * Local variables:
170  * c-indentation-style: "K&R"
171  * c-basic-offset: 8
172  * tab-width: 8
173  * fill-column: 80
174  * scroll-step: 1
175  * End:
176  */
177 /*
178  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
179  */
static size_t nr
Definition: dump.c:1505
#define NULL
Definition: misc.h:38
M0_INTERNAL const char * m0_trace_file_path_get(void)
Definition: ktrace.c:72
M0_INTERNAL const char * m0_failed_condition
Definition: misc.c:224
const struct m0_build_info * m0_build_info_get(void)
Definition: version.c:61
static struct m0_addb2_callback c
Definition: consumer.c:41
M0_INTERNAL void m0_debugger_invoke(void)
Definition: kassert.c:67
M0_INTERNAL void m0_arch_backtrace(void)
Definition: kassert.c:40
const char * bi_git_describe
Definition: version.h:35
M0_EXTERN char * m0_debugger_args[4]
Definition: uassert.c:50
static int stop
Definition: rwlock.c:56
M0_INTERNAL void m0_arch_panic(const struct m0_panic_ctx *ctx, va_list ap) __attribute__((noreturn))
Definition: kassert.c:45
int32_t rc
Definition: trigger_fop.h:47
#define ARRAY_SIZE(a)
Definition: misc.h:45
#define M0_IMPOSSIBLE(fmt,...)