xref: /dragonfly/contrib/gcc-8.0/libbacktrace/fileline.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
1 /* fileline.c -- Get file and line number information in a backtrace.
2    Copyright (C) 2012-2018 Free Software Foundation, Inc.
3    Written by Ian Lance Taylor, Google.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8 
9     (1) Redistributions of source code must retain the above copyright
10     notice, this list of conditions and the following disclaimer.
11 
12     (2) Redistributions in binary form must reproduce the above copyright
13     notice, this list of conditions and the following disclaimer in
14     the documentation and/or other materials provided with the
15     distribution.
16 
17     (3) The name of the author may not be used to
18     endorse or promote products derived from this software without
19     specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.  */
32 
33 #include "config.h"
34 
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 
42 #include "backtrace.h"
43 #include "internal.h"
44 
45 #ifndef HAVE_GETEXECNAME
46 #define getexecname() NULL
47 #endif
48 
49 /* Initialize the fileline information from the executable.  Returns 1
50    on success, 0 on failure.  */
51 
52 static int
fileline_initialize(struct backtrace_state * state,backtrace_error_callback error_callback,void * data)53 fileline_initialize (struct backtrace_state *state,
54                          backtrace_error_callback error_callback, void *data)
55 {
56   int failed;
57   fileline fileline_fn;
58   int pass;
59   int called_error_callback;
60   int descriptor;
61   const char *filename;
62   char buf[64];
63 
64   if (!state->threaded)
65     failed = state->fileline_initialization_failed;
66   else
67     failed = backtrace_atomic_load_int (&state->fileline_initialization_failed);
68 
69   if (failed)
70     {
71       error_callback (data, "failed to read executable information", -1);
72       return 0;
73     }
74 
75   if (!state->threaded)
76     fileline_fn = state->fileline_fn;
77   else
78     fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
79   if (fileline_fn != NULL)
80     return 1;
81 
82   /* We have not initialized the information.  Do it now.  */
83 
84   descriptor = -1;
85   called_error_callback = 0;
86   for (pass = 0; pass < 5; ++pass)
87     {
88       int does_not_exist;
89 
90       switch (pass)
91           {
92           case 0:
93             filename = state->filename;
94             break;
95           case 1:
96             filename = getexecname ();
97             break;
98           case 2:
99             filename = "/proc/self/exe";
100             break;
101           case 3:
102             filename = "/proc/curproc/file";
103             break;
104           case 4:
105             snprintf (buf, sizeof (buf), "/proc/%ld/object/a.out",
106                         (long) getpid ());
107             filename = buf;
108             break;
109           default:
110             abort ();
111           }
112 
113       if (filename == NULL)
114           continue;
115 
116       descriptor = backtrace_open (filename, error_callback, data,
117                                            &does_not_exist);
118       if (descriptor < 0 && !does_not_exist)
119           {
120             called_error_callback = 1;
121             break;
122           }
123       if (descriptor >= 0)
124           break;
125     }
126 
127   if (descriptor < 0)
128     {
129       if (!called_error_callback)
130           {
131             if (state->filename != NULL)
132               error_callback (data, state->filename, ENOENT);
133             else
134               error_callback (data,
135                                   "libbacktrace could not find executable to open",
136                                   0);
137           }
138       failed = 1;
139     }
140 
141   if (!failed)
142     {
143       if (!backtrace_initialize (state, filename, descriptor, error_callback,
144                                          data, &fileline_fn))
145           failed = 1;
146     }
147 
148   if (failed)
149     {
150       if (!state->threaded)
151           state->fileline_initialization_failed = 1;
152       else
153           backtrace_atomic_store_int (&state->fileline_initialization_failed, 1);
154       return 0;
155     }
156 
157   if (!state->threaded)
158     state->fileline_fn = fileline_fn;
159   else
160     {
161       backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn);
162 
163       /* Note that if two threads initialize at once, one of the data
164            sets may be leaked.  */
165     }
166 
167   return 1;
168 }
169 
170 /* Given a PC, find the file name, line number, and function name.  */
171 
172 int
backtrace_pcinfo(struct backtrace_state * state,uintptr_t pc,backtrace_full_callback callback,backtrace_error_callback error_callback,void * data)173 backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc,
174                       backtrace_full_callback callback,
175                       backtrace_error_callback error_callback, void *data)
176 {
177   if (!fileline_initialize (state, error_callback, data))
178     return 0;
179 
180   if (state->fileline_initialization_failed)
181     return 0;
182 
183   return state->fileline_fn (state, pc, callback, error_callback, data);
184 }
185 
186 /* Given a PC, find the symbol for it, and its value.  */
187 
188 int
backtrace_syminfo(struct backtrace_state * state,uintptr_t pc,backtrace_syminfo_callback callback,backtrace_error_callback error_callback,void * data)189 backtrace_syminfo (struct backtrace_state *state, uintptr_t pc,
190                        backtrace_syminfo_callback callback,
191                        backtrace_error_callback error_callback, void *data)
192 {
193   if (!fileline_initialize (state, error_callback, data))
194     return 0;
195 
196   if (state->fileline_initialization_failed)
197     return 0;
198 
199   state->syminfo_fn (state, pc, callback, error_callback, data);
200   return 1;
201 }
202