Import from old repository commit 61ef2b42a9c4ba8e1600f15bb0236765edc2ad45.
[cascardo/ovs.git] / lib / backtrace.c
1 /*
2  * Copyright (c) 2008, 2009 Nicira Networks.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <config.h>
18 #include "backtrace.h"
19 #include <errno.h>
20 #include <inttypes.h>
21 #include <stdbool.h>
22 #include <stdio.h>
23 #include "compiler.h"
24
25 #define THIS_MODULE VLM_backtrace
26 #include "vlog.h"
27
28 static uintptr_t UNUSED
29 get_max_stack(void)
30 {
31     static const char file_name[] = "/proc/self/maps";
32     char line[1024];
33     int line_number;
34     FILE *f;
35
36     f = fopen(file_name, "r");
37     if (f == NULL) {
38         VLOG_WARN("opening %s failed: %s", file_name, strerror(errno));
39         return -1;
40     }
41
42     for (line_number = 1; fgets(line, sizeof line, f); line_number++) {
43         if (strstr(line, "[stack]")) {
44             uintptr_t end;
45             if (sscanf(line, "%*"SCNxPTR"-%"SCNxPTR, &end) != 1) {
46                 VLOG_WARN("%s:%d: parse error", file_name, line_number);
47                 continue;
48             }
49             fclose(f);
50             return end;
51         }
52     }
53     fclose(f);
54
55     VLOG_WARN("%s: no stack found", file_name);
56     return -1;
57 }
58
59 static uintptr_t
60 stack_high(void)
61 {
62     static uintptr_t high;
63     if (!high) {
64         high = get_max_stack();
65     }
66     return high;
67 }
68
69 static uintptr_t
70 stack_low(void)
71 {
72 #ifdef __i386__
73     uintptr_t low;
74     asm("movl %%esp,%0" : "=g" (low));
75     return low;
76 #else
77     /* This causes a warning in GCC that cannot be disabled, so use it only on
78      * non-x86. */
79     int dummy;
80     return (uintptr_t) &dummy;
81 #endif
82 }
83
84 static bool
85 in_stack(void *p)
86 {
87     uintptr_t address = (uintptr_t) p;
88     return address >= stack_low() && address < stack_high();
89 }
90
91 void
92 backtrace_capture(struct backtrace *backtrace)
93 {
94     void **frame;
95     size_t n;
96
97     n = 0;
98     for (frame = __builtin_frame_address(1);
99          frame != NULL && in_stack(frame) && frame[0] != NULL
100              && n < BACKTRACE_MAX_FRAMES;
101          frame = frame[0])
102     {
103         backtrace->frames[n++] = (uintptr_t) frame[1];
104     }
105     backtrace->n_frames = n;
106 }