]> git.proxmox.com Git - mirror_ovs.git/blobdiff - lib/backtrace.c
Revert "dpif-netdev: includes microsecond delta in meter bucket calculation".
[mirror_ovs.git] / lib / backtrace.c
index 42ab8c48b70b59524c054530385f14c060b75cf7..2853d5ff150df0784213a97093223b072ae3e98d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  */
 
 #include <config.h>
-#include "backtrace.h"
 #include <errno.h>
+#include <fcntl.h>
 #include <inttypes.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include "compiler.h"
+#include <string.h>
+#include <unistd.h>
+
+#include "backtrace.h"
+#include "openvswitch/vlog.h"
+#include "util.h"
 
-#define THIS_MODULE VLM_backtrace
-#include "vlog.h"
+VLOG_DEFINE_THIS_MODULE(backtrace);
 
-static uintptr_t UNUSED
-get_max_stack(void)
+#ifdef HAVE_BACKTRACE
+#include <execinfo.h>
+void
+backtrace_capture(struct backtrace *b)
 {
-    static const char file_name[] = "/proc/self/maps";
-    char line[1024];
-    int line_number;
-    FILE *f;
-
-    f = fopen(file_name, "r");
-    if (f == NULL) {
-        VLOG_WARN("opening %s failed: %s", file_name, strerror(errno));
-        return -1;
-    }
+    void *frames[BACKTRACE_MAX_FRAMES];
+    int i;
 
-    for (line_number = 1; fgets(line, sizeof line, f); line_number++) {
-        if (strstr(line, "[stack]")) {
-            uintptr_t end;
-            if (sscanf(line, "%*x-%"SCNxPTR, &end) != 1) {
-                VLOG_WARN("%s:%d: parse error", file_name, line_number);
-                continue;
-            }
-            fclose(f);
-            return end;
-        }
+    b->n_frames = backtrace(frames, BACKTRACE_MAX_FRAMES);
+    for (i = 0; i < b->n_frames; i++) {
+        b->frames[i] = (uintptr_t) frames[i];
     }
-    fclose(f);
-
-    VLOG_WARN("%s: no stack found", file_name);
-    return -1;
 }
 
-static uintptr_t
-stack_high(void)
+#else
+void
+backtrace_capture(struct backtrace *backtrace)
 {
-    static uintptr_t high;
-    if (!high) {
-        high = get_max_stack();
-    }
-    return high;
+    backtrace->n_frames = 0;
 }
+#endif
 
-static uintptr_t
-stack_low(void)
+static char *
+backtrace_format(const struct backtrace *b, struct ds *ds)
 {
-#ifdef __i386__
-    uintptr_t low;
-    asm("movl %%esp,%0" : "=g" (low));
-    return low;
-#else
-    /* This causes a warning in GCC that cannot be disabled, so use it only on
-     * non-x86. */
-    int dummy;
-    return (uintptr_t) &dummy;
-#endif
+    if (b->n_frames) {
+        int i;
+
+        ds_put_cstr(ds, " (backtrace:");
+        for (i = 0; i < b->n_frames; i++) {
+            ds_put_format(ds, " 0x%08"PRIxPTR, b->frames[i]);
+        }
+        ds_put_cstr(ds, ")");
+    }
+
+    return ds_cstr(ds);
 }
 
-static bool
-in_stack(void *p)
+void
+log_backtrace_at(const char *msg, const char *where)
 {
-    uintptr_t address = (uintptr_t) p;
-    return address >= stack_low() && address < stack_high();
+    struct backtrace b;
+    struct ds ds = DS_EMPTY_INITIALIZER;
+
+    backtrace_capture(&b);
+    if (msg) {
+        ds_put_format(&ds, "%s ", msg);
+    }
+
+    ds_put_cstr(&ds, where);
+    VLOG_ERR("%s", backtrace_format(&b, &ds));
+
+    ds_destroy(&ds);
 }
 
+#ifdef HAVE_UNWIND
 void
-backtrace_capture(struct backtrace *backtrace)
-{
-    void **frame;
-    size_t n;
-
-    n = 0;
-    for (frame = __builtin_frame_address(1);
-         frame != NULL && in_stack(frame) && frame[0] != NULL
-             && n < BACKTRACE_MAX_FRAMES;
-         frame = frame[0])
-    {
-        backtrace->frames[n++] = (uintptr_t) frame[1];
+log_received_backtrace(int fd) {
+    int byte_read;
+    struct unw_backtrace backtrace[UNW_MAX_DEPTH];
+
+    VLOG_WARN("%s fd %d", __func__, fd);
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+    memset(backtrace, 0, UNW_MAX_BUF);
+
+    byte_read = read(fd, backtrace, UNW_MAX_BUF);
+    if (byte_read < 0) {
+        VLOG_ERR("Read fd %d failed: %s", fd,
+                 ovs_strerror(errno));
+    } else if (byte_read > 0) {
+        VLOG_WARN("SIGSEGV detected, backtrace:");
+        for (int i = 0; i < UNW_MAX_DEPTH; i++) {
+            if (backtrace[i].func[0] == 0) {
+                break;
+            }
+            VLOG_WARN("0x%016"PRIxPTR" <%s+0x%"PRIxPTR">\n",
+                      backtrace[i].ip,
+                      backtrace[i].func,
+                      backtrace[i].offset);
+        }
     }
-    backtrace->n_frames = n;
 }
+#else /* !HAVE_UNWIND */
+void
+log_received_backtrace(int daemonize_fd OVS_UNUSED) {
+    VLOG_WARN("Backtrace using libunwind not supported.");
+}
+#endif /* HAVE_UNWIND */