126 lines
2.8 KiB
C
126 lines
2.8 KiB
C
/* go-callers.c -- get callers for Go.
|
|
|
|
Copyright 2012 The Go Authors. All rights reserved.
|
|
Use of this source code is governed by a BSD-style
|
|
license that can be found in the LICENSE file. */
|
|
|
|
#include "config.h"
|
|
|
|
#include "backtrace.h"
|
|
|
|
#include "runtime.h"
|
|
#include "array.h"
|
|
|
|
/* Argument passed to callback function. */
|
|
|
|
struct callers_data
|
|
{
|
|
Location *locbuf;
|
|
int skip;
|
|
int index;
|
|
int max;
|
|
};
|
|
|
|
/* Callback function for backtrace_full. Just collect the locations.
|
|
Return zero to continue, non-zero to stop. */
|
|
|
|
static int
|
|
callback (void *data, uintptr_t pc, const char *filename, int lineno,
|
|
const char *function)
|
|
{
|
|
struct callers_data *arg = (struct callers_data *) data;
|
|
Location *loc;
|
|
|
|
/* Skip split stack functions. */
|
|
if (function != NULL)
|
|
{
|
|
const char *p;
|
|
|
|
p = function;
|
|
if (__builtin_strncmp (p, "___", 3) == 0)
|
|
++p;
|
|
if (__builtin_strncmp (p, "__morestack_", 12) == 0)
|
|
return 0;
|
|
}
|
|
else if (filename != NULL)
|
|
{
|
|
const char *p;
|
|
|
|
p = strrchr (filename, '/');
|
|
if (p == NULL)
|
|
p = filename;
|
|
if (__builtin_strncmp (p, "/morestack.S", 12) == 0)
|
|
return 0;
|
|
}
|
|
|
|
if (arg->skip > 0)
|
|
{
|
|
--arg->skip;
|
|
return 0;
|
|
}
|
|
|
|
loc = &arg->locbuf[arg->index];
|
|
loc->pc = pc;
|
|
|
|
/* The libbacktrace library says that these strings might disappear,
|
|
but with the current implementation they won't. We can't easily
|
|
allocate memory here, so for now assume that we can save a
|
|
pointer to the strings. */
|
|
loc->filename = runtime_gostringnocopy ((const byte *) filename);
|
|
loc->function = runtime_gostringnocopy ((const byte *) function);
|
|
|
|
loc->lineno = lineno;
|
|
++arg->index;
|
|
return arg->index >= arg->max;
|
|
}
|
|
|
|
/* Error callback. */
|
|
|
|
static void
|
|
error_callback (void *data __attribute__ ((unused)),
|
|
const char *msg, int errnum)
|
|
{
|
|
if (errnum != 0)
|
|
runtime_printf ("%s errno %d\n", msg, errnum);
|
|
runtime_throw (msg);
|
|
}
|
|
|
|
/* Gather caller PC's. */
|
|
|
|
int32
|
|
runtime_callers (int32 skip, Location *locbuf, int32 m)
|
|
{
|
|
struct callers_data data;
|
|
|
|
data.locbuf = locbuf;
|
|
data.skip = skip + 1;
|
|
data.index = 0;
|
|
data.max = m;
|
|
backtrace_full (__go_get_backtrace_state (), 0, callback, error_callback,
|
|
&data);
|
|
return data.index;
|
|
}
|
|
|
|
int Callers (int, struct __go_open_array)
|
|
__asm__ (GOSYM_PREFIX "runtime.Callers");
|
|
|
|
int
|
|
Callers (int skip, struct __go_open_array pc)
|
|
{
|
|
Location *locbuf;
|
|
int ret;
|
|
int i;
|
|
|
|
locbuf = (Location *) runtime_mal (pc.__count * sizeof (Location));
|
|
|
|
/* In the Go 1 release runtime.Callers has an off-by-one error,
|
|
which we can not correct because it would break backward
|
|
compatibility. Adjust SKIP here to be compatible. */
|
|
ret = runtime_callers (skip - 1, locbuf, pc.__count);
|
|
|
|
for (i = 0; i < ret; i++)
|
|
((uintptr *) pc.__values)[i] = locbuf[i].pc;
|
|
|
|
return ret;
|
|
}
|