Global replace of Nicira Networks.
[sliver-openvswitch.git] / lib / backtrace.c
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
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
17 #include <config.h>
18
19 #include "backtrace.h"
20
21 #include <errno.h>
22 #include <inttypes.h>
23 #include <stdbool.h>
24 #include <stdio.h>
25
26 #include "compiler.h"
27 #include "vlog.h"
28
29 VLOG_DEFINE_THIS_MODULE(backtrace);
30
31 #ifdef HAVE_BACKTRACE
32 #include <execinfo.h>
33 void
34 backtrace_capture(struct backtrace *b)
35 {
36     void *frames[BACKTRACE_MAX_FRAMES];
37     int i;
38
39     b->n_frames = backtrace(frames, BACKTRACE_MAX_FRAMES);
40     for (i = 0; i < b->n_frames; i++) {
41         b->frames[i] = (uintptr_t) frames[i];
42     }
43 }
44 #elif __GNUC__
45 static uintptr_t
46 get_max_stack(void)
47 {
48     static const char file_name[] = "/proc/self/maps";
49     char line[1024];
50     int line_number;
51     FILE *f;
52
53     f = fopen(file_name, "r");
54     if (f == NULL) {
55         VLOG_WARN("opening %s failed: %s", file_name, strerror(errno));
56         return -1;
57     }
58
59     for (line_number = 1; fgets(line, sizeof line, f); line_number++) {
60         if (strstr(line, "[stack]")) {
61             uintptr_t end;
62             if (sscanf(line, "%*x-%"SCNxPTR, &end) != 1) {
63                 VLOG_WARN("%s:%d: parse error", file_name, line_number);
64                 continue;
65             }
66             fclose(f);
67             return end;
68         }
69     }
70     fclose(f);
71
72     VLOG_WARN("%s: no stack found", file_name);
73     return -1;
74 }
75
76 static uintptr_t
77 stack_high(void)
78 {
79     static uintptr_t high;
80     if (!high) {
81         high = get_max_stack();
82     }
83     return high;
84 }
85
86 static uintptr_t
87 stack_low(void)
88 {
89     uintptr_t low = (uintptr_t) &low;
90     return low;
91 }
92
93 static bool
94 in_stack(void *p)
95 {
96     uintptr_t address = (uintptr_t) p;
97     return address >= stack_low() && address < stack_high();
98 }
99
100 void
101 backtrace_capture(struct backtrace *backtrace)
102 {
103     void **frame;
104     size_t n;
105
106     n = 0;
107     for (frame = __builtin_frame_address(1);
108          frame != NULL && in_stack(frame) && frame[0] != NULL
109              && n < BACKTRACE_MAX_FRAMES;
110          frame = frame[0])
111     {
112         backtrace->frames[n++] = (uintptr_t) frame[1];
113     }
114     backtrace->n_frames = n;
115 }
116 #else  /* !HAVE_BACKTRACE && !__GNUC__ */
117 void
118 backtrace_capture(struct backtrace *backtrace)
119 {
120     backtrace->n_frames = 0;
121 }
122 #endif