Prepare Open vSwitch 1.1.2 release.
[sliver-openvswitch.git] / lib / backtrace.c
1 /*
2  * Copyright (c) 2008, 2009, 2010 Nicira Networks.
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 #include "backtrace.h"
19 #include <errno.h>
20 #include <inttypes.h>
21 #include <stdbool.h>
22 #include <stdio.h>
23 #include "compiler.h"
24 #include "vlog.h"
25
26 VLOG_DEFINE_THIS_MODULE(backtrace);
27
28 static uintptr_t OVS_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, "%*x-%"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     uintptr_t low = (uintptr_t) &low;
73     return low;
74 }
75
76 static bool
77 in_stack(void *p)
78 {
79     uintptr_t address = (uintptr_t) p;
80     return address >= stack_low() && address < stack_high();
81 }
82
83 void
84 backtrace_capture(struct backtrace *backtrace)
85 {
86 #ifdef __GNUC__
87     void **frame;
88     size_t n;
89
90     n = 0;
91     for (frame = __builtin_frame_address(1);
92          frame != NULL && in_stack(frame) && frame[0] != NULL
93              && n < BACKTRACE_MAX_FRAMES;
94          frame = frame[0])
95     {
96         backtrace->frames[n++] = (uintptr_t) frame[1];
97     }
98     backtrace->n_frames = n;
99 #else
100     backtrace->n_frames = 0;
101 #endif
102 }