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