Merge citrix branch into master.
[cascardo/ovs.git] / lib / backtrace.c
1 /*
2  * Copyright (c) 2008, 2009 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
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, "%*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 #ifdef __i386__
73     uintptr_t low;
74     asm("movl %%esp,%0" : "=g" (low));
75     return low;
76 #elif __x86_64__
77     uintptr_t low;
78     asm("movq %%rsp,%0" : "=g" (low));
79     return low;
80 #else
81     /* This causes a warning in GCC that cannot be disabled, so use it only on
82      * non-x86. */
83     int dummy;
84     return (uintptr_t) &dummy;
85 #endif
86 }
87
88 static bool
89 in_stack(void *p)
90 {
91     uintptr_t address = (uintptr_t) p;
92     return address >= stack_low() && address < stack_high();
93 }
94
95 void
96 backtrace_capture(struct backtrace *backtrace)
97 {
98     void **frame;
99     size_t n;
100
101     n = 0;
102     for (frame = __builtin_frame_address(1);
103          frame != NULL && in_stack(frame) && frame[0] != NULL
104              && n < BACKTRACE_MAX_FRAMES;
105          frame = frame[0])
106     {
107         backtrace->frames[n++] = (uintptr_t) frame[1];
108     }
109     backtrace->n_frames = n;
110 }