summaryrefslogtreecommitdiff
path: root/libgo/runtime/go-callers.c
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/runtime/go-callers.c')
-rw-r--r--libgo/runtime/go-callers.c54
1 files changed, 50 insertions, 4 deletions
diff --git a/libgo/runtime/go-callers.c b/libgo/runtime/go-callers.c
index ae411d9c83..b5ab3be647 100644
--- a/libgo/runtime/go-callers.c
+++ b/libgo/runtime/go-callers.c
@@ -26,6 +26,7 @@ struct callers_data
int skip;
int index;
int max;
+ int keep_thunks;
};
/* Callback function for backtrace_full. Just collect the locations.
@@ -63,7 +64,7 @@ callback (void *data, uintptr_t pc, const char *filename, int lineno,
/* Skip thunks and recover functions. There is no equivalent to
these functions in the gc toolchain, so returning them here means
significantly different results for runtime.Caller(N). */
- if (function != NULL)
+ if (function != NULL && !arg->keep_thunks)
{
const char *p;
@@ -82,7 +83,20 @@ callback (void *data, uintptr_t pc, const char *filename, int lineno,
}
loc = &arg->locbuf[arg->index];
- loc->pc = pc;
+
+ /* On the call to backtrace_full the pc value was most likely
+ decremented if there was a normal call, since the pc referred to
+ the instruction where the call returned and not the call itself.
+ This was done so that the line number referred to the call
+ instruction. To make sure the actual pc from the call stack is
+ used, it is incremented here.
+
+ In the case of a signal, the pc was not decremented by
+ backtrace_full but still incremented here. That doesn't really
+ hurt anything since the line number is right and the pc refers to
+ the same instruction. */
+
+ loc->pc = pc + 1;
/* The libbacktrace library says that these strings might disappear,
but with the current implementation they won't. We can't easily
@@ -93,6 +107,32 @@ callback (void *data, uintptr_t pc, const char *filename, int lineno,
loc->lineno = lineno;
++arg->index;
+
+ /* There is no point to tracing past certain runtime functions.
+ Stopping the backtrace here can avoid problems on systems that
+ don't provide proper unwind information for makecontext, such as
+ Solaris (http://gcc.gnu.org/PR52583 comment #21). */
+ if (function != NULL)
+ {
+ if (__builtin_strcmp (function, "makecontext") == 0)
+ return 1;
+ if (filename != NULL)
+ {
+ const char *p;
+
+ p = strrchr (filename, '/');
+ if (p == NULL)
+ p = filename;
+ if (__builtin_strcmp (p, "/proc.c") == 0)
+ {
+ if (__builtin_strcmp (function, "kickoff") == 0
+ || __builtin_strcmp (function, "runtime_mstart") == 0
+ || __builtin_strcmp (function, "runtime_main") == 0)
+ return 1;
+ }
+ }
+ }
+
return arg->index >= arg->max;
}
@@ -102,6 +142,11 @@ static void
error_callback (void *data __attribute__ ((unused)),
const char *msg, int errnum)
{
+ if (errnum == -1)
+ {
+ /* No debug info available. Carry on as best we can. */
+ return;
+ }
if (errnum != 0)
runtime_printf ("%s errno %d\n", msg, errnum);
runtime_throw (msg);
@@ -110,7 +155,7 @@ error_callback (void *data __attribute__ ((unused)),
/* Gather caller PC's. */
int32
-runtime_callers (int32 skip, Location *locbuf, int32 m)
+runtime_callers (int32 skip, Location *locbuf, int32 m, bool keep_thunks)
{
struct callers_data data;
@@ -118,6 +163,7 @@ runtime_callers (int32 skip, Location *locbuf, int32 m)
data.skip = skip + 1;
data.index = 0;
data.max = m;
+ data.keep_thunks = keep_thunks;
runtime_xadd (&runtime_in_callers, 1);
backtrace_full (__go_get_backtrace_state (), 0, callback, error_callback,
&data);
@@ -141,7 +187,7 @@ Callers (int skip, struct __go_open_array pc)
which we can not correct because it would break backward
compatibility. Normally we would add 1 to SKIP here, but we
don't so that we are compatible. */
- ret = runtime_callers (skip, locbuf, pc.__count);
+ ret = runtime_callers (skip, locbuf, pc.__count, false);
for (i = 0; i < ret; i++)
((uintptr *) pc.__values)[i] = locbuf[i].pc;