xref: /netbsd-src/external/gpl3/gcc.old/dist/libbacktrace/fileline.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
136ac495dSmrg /* fileline.c -- Get file and line number information in a backtrace.
2*8feb0f0bSmrg    Copyright (C) 2012-2020 Free Software Foundation, Inc.
336ac495dSmrg    Written by Ian Lance Taylor, Google.
436ac495dSmrg 
536ac495dSmrg Redistribution and use in source and binary forms, with or without
636ac495dSmrg modification, are permitted provided that the following conditions are
736ac495dSmrg met:
836ac495dSmrg 
936ac495dSmrg     (1) Redistributions of source code must retain the above copyright
1036ac495dSmrg     notice, this list of conditions and the following disclaimer.
1136ac495dSmrg 
1236ac495dSmrg     (2) Redistributions in binary form must reproduce the above copyright
1336ac495dSmrg     notice, this list of conditions and the following disclaimer in
1436ac495dSmrg     the documentation and/or other materials provided with the
1536ac495dSmrg     distribution.
1636ac495dSmrg 
1736ac495dSmrg     (3) The name of the author may not be used to
1836ac495dSmrg     endorse or promote products derived from this software without
1936ac495dSmrg     specific prior written permission.
2036ac495dSmrg 
2136ac495dSmrg THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2236ac495dSmrg IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2336ac495dSmrg WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2436ac495dSmrg DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
2536ac495dSmrg INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2636ac495dSmrg (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2736ac495dSmrg SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2836ac495dSmrg HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2936ac495dSmrg STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
3036ac495dSmrg IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3136ac495dSmrg POSSIBILITY OF SUCH DAMAGE.  */
3236ac495dSmrg 
3336ac495dSmrg #include "config.h"
3436ac495dSmrg 
3536ac495dSmrg #include <sys/types.h>
3636ac495dSmrg #include <sys/stat.h>
3736ac495dSmrg #include <errno.h>
3836ac495dSmrg #include <fcntl.h>
3936ac495dSmrg #include <stdlib.h>
40a2dc1f3fSmrg #include <unistd.h>
4136ac495dSmrg 
4236ac495dSmrg #include "backtrace.h"
4336ac495dSmrg #include "internal.h"
4436ac495dSmrg 
4536ac495dSmrg #ifndef HAVE_GETEXECNAME
4636ac495dSmrg #define getexecname() NULL
4736ac495dSmrg #endif
4836ac495dSmrg 
4936ac495dSmrg /* Initialize the fileline information from the executable.  Returns 1
5036ac495dSmrg    on success, 0 on failure.  */
5136ac495dSmrg 
5236ac495dSmrg static int
fileline_initialize(struct backtrace_state * state,backtrace_error_callback error_callback,void * data)5336ac495dSmrg fileline_initialize (struct backtrace_state *state,
5436ac495dSmrg 		     backtrace_error_callback error_callback, void *data)
5536ac495dSmrg {
5636ac495dSmrg   int failed;
5736ac495dSmrg   fileline fileline_fn;
5836ac495dSmrg   int pass;
5936ac495dSmrg   int called_error_callback;
6036ac495dSmrg   int descriptor;
61a2dc1f3fSmrg   const char *filename;
62a2dc1f3fSmrg   char buf[64];
6336ac495dSmrg 
6436ac495dSmrg   if (!state->threaded)
6536ac495dSmrg     failed = state->fileline_initialization_failed;
6636ac495dSmrg   else
6736ac495dSmrg     failed = backtrace_atomic_load_int (&state->fileline_initialization_failed);
6836ac495dSmrg 
6936ac495dSmrg   if (failed)
7036ac495dSmrg     {
7136ac495dSmrg       error_callback (data, "failed to read executable information", -1);
7236ac495dSmrg       return 0;
7336ac495dSmrg     }
7436ac495dSmrg 
7536ac495dSmrg   if (!state->threaded)
7636ac495dSmrg     fileline_fn = state->fileline_fn;
7736ac495dSmrg   else
7836ac495dSmrg     fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
7936ac495dSmrg   if (fileline_fn != NULL)
8036ac495dSmrg     return 1;
8136ac495dSmrg 
8236ac495dSmrg   /* We have not initialized the information.  Do it now.  */
8336ac495dSmrg 
8436ac495dSmrg   descriptor = -1;
8536ac495dSmrg   called_error_callback = 0;
86a2dc1f3fSmrg   for (pass = 0; pass < 5; ++pass)
8736ac495dSmrg     {
8836ac495dSmrg       int does_not_exist;
8936ac495dSmrg 
9036ac495dSmrg       switch (pass)
9136ac495dSmrg 	{
9236ac495dSmrg 	case 0:
9336ac495dSmrg 	  filename = state->filename;
9436ac495dSmrg 	  break;
9536ac495dSmrg 	case 1:
9636ac495dSmrg 	  filename = getexecname ();
9736ac495dSmrg 	  break;
9836ac495dSmrg 	case 2:
9936ac495dSmrg 	  filename = "/proc/self/exe";
10036ac495dSmrg 	  break;
10136ac495dSmrg 	case 3:
10236ac495dSmrg 	  filename = "/proc/curproc/file";
10336ac495dSmrg 	  break;
104a2dc1f3fSmrg 	case 4:
105a2dc1f3fSmrg 	  snprintf (buf, sizeof (buf), "/proc/%ld/object/a.out",
106a2dc1f3fSmrg 		    (long) getpid ());
107a2dc1f3fSmrg 	  filename = buf;
108a2dc1f3fSmrg 	  break;
10936ac495dSmrg 	default:
11036ac495dSmrg 	  abort ();
11136ac495dSmrg 	}
11236ac495dSmrg 
11336ac495dSmrg       if (filename == NULL)
11436ac495dSmrg 	continue;
11536ac495dSmrg 
11636ac495dSmrg       descriptor = backtrace_open (filename, error_callback, data,
11736ac495dSmrg 				   &does_not_exist);
11836ac495dSmrg       if (descriptor < 0 && !does_not_exist)
11936ac495dSmrg 	{
12036ac495dSmrg 	  called_error_callback = 1;
12136ac495dSmrg 	  break;
12236ac495dSmrg 	}
12336ac495dSmrg       if (descriptor >= 0)
12436ac495dSmrg 	break;
12536ac495dSmrg     }
12636ac495dSmrg 
12736ac495dSmrg   if (descriptor < 0)
12836ac495dSmrg     {
12936ac495dSmrg       if (!called_error_callback)
13036ac495dSmrg 	{
13136ac495dSmrg 	  if (state->filename != NULL)
13236ac495dSmrg 	    error_callback (data, state->filename, ENOENT);
13336ac495dSmrg 	  else
13436ac495dSmrg 	    error_callback (data,
13536ac495dSmrg 			    "libbacktrace could not find executable to open",
13636ac495dSmrg 			    0);
13736ac495dSmrg 	}
13836ac495dSmrg       failed = 1;
13936ac495dSmrg     }
14036ac495dSmrg 
14136ac495dSmrg   if (!failed)
14236ac495dSmrg     {
143a2dc1f3fSmrg       if (!backtrace_initialize (state, filename, descriptor, error_callback,
144a2dc1f3fSmrg 				 data, &fileline_fn))
14536ac495dSmrg 	failed = 1;
14636ac495dSmrg     }
14736ac495dSmrg 
14836ac495dSmrg   if (failed)
14936ac495dSmrg     {
15036ac495dSmrg       if (!state->threaded)
15136ac495dSmrg 	state->fileline_initialization_failed = 1;
15236ac495dSmrg       else
15336ac495dSmrg 	backtrace_atomic_store_int (&state->fileline_initialization_failed, 1);
15436ac495dSmrg       return 0;
15536ac495dSmrg     }
15636ac495dSmrg 
15736ac495dSmrg   if (!state->threaded)
15836ac495dSmrg     state->fileline_fn = fileline_fn;
15936ac495dSmrg   else
16036ac495dSmrg     {
16136ac495dSmrg       backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn);
16236ac495dSmrg 
16336ac495dSmrg       /* Note that if two threads initialize at once, one of the data
16436ac495dSmrg 	 sets may be leaked.  */
16536ac495dSmrg     }
16636ac495dSmrg 
16736ac495dSmrg   return 1;
16836ac495dSmrg }
16936ac495dSmrg 
17036ac495dSmrg /* Given a PC, find the file name, line number, and function name.  */
17136ac495dSmrg 
17236ac495dSmrg int
backtrace_pcinfo(struct backtrace_state * state,uintptr_t pc,backtrace_full_callback callback,backtrace_error_callback error_callback,void * data)17336ac495dSmrg backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc,
17436ac495dSmrg 		  backtrace_full_callback callback,
17536ac495dSmrg 		  backtrace_error_callback error_callback, void *data)
17636ac495dSmrg {
17736ac495dSmrg   if (!fileline_initialize (state, error_callback, data))
17836ac495dSmrg     return 0;
17936ac495dSmrg 
18036ac495dSmrg   if (state->fileline_initialization_failed)
18136ac495dSmrg     return 0;
18236ac495dSmrg 
18336ac495dSmrg   return state->fileline_fn (state, pc, callback, error_callback, data);
18436ac495dSmrg }
18536ac495dSmrg 
18636ac495dSmrg /* Given a PC, find the symbol for it, and its value.  */
18736ac495dSmrg 
18836ac495dSmrg int
backtrace_syminfo(struct backtrace_state * state,uintptr_t pc,backtrace_syminfo_callback callback,backtrace_error_callback error_callback,void * data)18936ac495dSmrg backtrace_syminfo (struct backtrace_state *state, uintptr_t pc,
19036ac495dSmrg 		   backtrace_syminfo_callback callback,
19136ac495dSmrg 		   backtrace_error_callback error_callback, void *data)
19236ac495dSmrg {
19336ac495dSmrg   if (!fileline_initialize (state, error_callback, data))
19436ac495dSmrg     return 0;
19536ac495dSmrg 
19636ac495dSmrg   if (state->fileline_initialization_failed)
19736ac495dSmrg     return 0;
19836ac495dSmrg 
19936ac495dSmrg   state->syminfo_fn (state, pc, callback, error_callback, data);
20036ac495dSmrg   return 1;
20136ac495dSmrg }
202