github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/third_party/gofrontend/libgo/runtime/go-callers.c (about)

     1  /* go-callers.c -- get callers for Go.
     2  
     3     Copyright 2012 The Go Authors. All rights reserved.
     4     Use of this source code is governed by a BSD-style
     5     license that can be found in the LICENSE file.  */
     6  
     7  #include "config.h"
     8  
     9  #include "backtrace.h"
    10  
    11  #include "runtime.h"
    12  #include "array.h"
    13  
    14  /* This is set to non-zero when calling backtrace_full.  This is used
    15     to avoid getting hanging on a recursive lock in dl_iterate_phdr on
    16     older versions of glibc when a SIGPROF signal arrives while
    17     collecting a backtrace.  */
    18  
    19  uint32 runtime_in_callers;
    20  
    21  /* Argument passed to callback function.  */
    22  
    23  struct callers_data
    24  {
    25    Location *locbuf;
    26    int skip;
    27    int index;
    28    int max;
    29    int keep_thunks;
    30  };
    31  
    32  /* Callback function for backtrace_full.  Just collect the locations.
    33     Return zero to continue, non-zero to stop.  */
    34  
    35  static int
    36  callback (void *data, uintptr_t pc, const char *filename, int lineno,
    37  	  const char *function)
    38  {
    39    struct callers_data *arg = (struct callers_data *) data;
    40    Location *loc;
    41  
    42    /* Skip split stack functions.  */
    43    if (function != NULL)
    44      {
    45        const char *p;
    46  
    47        p = function;
    48        if (__builtin_strncmp (p, "___", 3) == 0)
    49  	++p;
    50        if (__builtin_strncmp (p, "__morestack_", 12) == 0)
    51  	return 0;
    52      }
    53    else if (filename != NULL)
    54      {
    55        const char *p;
    56  
    57        p = strrchr (filename, '/');
    58        if (p == NULL)
    59  	p = filename;
    60        if (__builtin_strncmp (p, "/morestack.S", 12) == 0)
    61  	return 0;
    62      }
    63  
    64    /* Skip thunks and recover functions.  There is no equivalent to
    65       these functions in the gc toolchain, so returning them here means
    66       significantly different results for runtime.Caller(N).  */
    67    if (function != NULL && !arg->keep_thunks)
    68      {
    69        const char *p;
    70  
    71        p = __builtin_strchr (function, '.');
    72        if (p != NULL && __builtin_strncmp (p + 1, "$thunk", 6) == 0)
    73  	return 0;
    74        p = __builtin_strrchr (function, '$');
    75        if (p != NULL && __builtin_strcmp(p, "$recover") == 0)
    76  	return 0;
    77      }
    78  
    79    if (arg->skip > 0)
    80      {
    81        --arg->skip;
    82        return 0;
    83      }
    84  
    85    loc = &arg->locbuf[arg->index];
    86    loc->pc = pc;
    87  
    88    /* The libbacktrace library says that these strings might disappear,
    89       but with the current implementation they won't.  We can't easily
    90       allocate memory here, so for now assume that we can save a
    91       pointer to the strings.  */
    92    loc->filename = runtime_gostringnocopy ((const byte *) filename);
    93    loc->function = runtime_gostringnocopy ((const byte *) function);
    94  
    95    loc->lineno = lineno;
    96    ++arg->index;
    97  
    98    /* There is no point to tracing past certain runtime functions.
    99       Stopping the backtrace here can avoid problems on systems that
   100       don't provide proper unwind information for makecontext, such as
   101       Solaris (http://gcc.gnu.org/PR52583 comment #21).  */
   102    if (function != NULL)
   103      {
   104        if (__builtin_strcmp (function, "makecontext") == 0)
   105  	return 1;
   106        if (filename != NULL)
   107  	{
   108  	  const char *p;
   109  
   110  	  p = strrchr (filename, '/');
   111  	  if (p == NULL)
   112  	    p = filename;
   113  	  if (__builtin_strcmp (p, "/proc.c") == 0)
   114  	    {
   115  	      if (__builtin_strcmp (function, "kickoff") == 0
   116  		  || __builtin_strcmp (function, "runtime_mstart") == 0
   117  		  || __builtin_strcmp (function, "runtime_main") == 0)
   118  		return 1;
   119  	    }
   120  	}
   121      }
   122  
   123    return arg->index >= arg->max;
   124  }
   125  
   126  /* Error callback.  */
   127  
   128  static void
   129  error_callback (void *data __attribute__ ((unused)),
   130  		const char *msg, int errnum)
   131  {
   132    if (errnum == -1)
   133      {
   134        /* No debug info available.  Carry on as best we can.  */
   135        return;
   136      }
   137    if (errnum != 0)
   138      runtime_printf ("%s errno %d\n", msg, errnum);
   139    runtime_throw (msg);
   140  }
   141  
   142  /* Gather caller PC's.  */
   143  
   144  int32
   145  runtime_callers (int32 skip, Location *locbuf, int32 m, bool keep_thunks)
   146  {
   147    struct callers_data data;
   148  
   149    data.locbuf = locbuf;
   150    data.skip = skip + 1;
   151    data.index = 0;
   152    data.max = m;
   153    data.keep_thunks = keep_thunks;
   154    runtime_xadd (&runtime_in_callers, 1);
   155    backtrace_full (__go_get_backtrace_state (), 0, callback, error_callback,
   156  		  &data);
   157    runtime_xadd (&runtime_in_callers, -1);
   158    return data.index;
   159  }
   160  
   161  int Callers (int, struct __go_open_array)
   162    __asm__ (GOSYM_PREFIX "runtime.Callers");
   163  
   164  int
   165  Callers (int skip, struct __go_open_array pc)
   166  {
   167    Location *locbuf;
   168    int ret;
   169    int i;
   170  
   171    locbuf = (Location *) runtime_mal (pc.__count * sizeof (Location));
   172  
   173    /* In the Go 1 release runtime.Callers has an off-by-one error,
   174       which we can not correct because it would break backward
   175       compatibility.  Normally we would add 1 to SKIP here, but we
   176       don't so that we are compatible.  */
   177    ret = runtime_callers (skip, locbuf, pc.__count, false);
   178  
   179    for (i = 0; i < ret; i++)
   180      ((uintptr *) pc.__values)[i] = locbuf[i].pc;
   181  
   182    return ret;
   183  }