github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/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  
    87    /* On the call to backtrace_full the pc value was most likely
    88       decremented if there was a normal call, since the pc referred to
    89       the instruction where the call returned and not the call itself.
    90       This was done so that the line number referred to the call
    91       instruction.  To make sure the actual pc from the call stack is
    92       used, it is incremented here.
    93  
    94       In the case of a signal, the pc was not decremented by
    95       backtrace_full but still incremented here.  That doesn't really
    96       hurt anything since the line number is right and the pc refers to
    97       the same instruction.  */
    98  
    99    loc->pc = pc + 1;
   100  
   101    /* The libbacktrace library says that these strings might disappear,
   102       but with the current implementation they won't.  We can't easily
   103       allocate memory here, so for now assume that we can save a
   104       pointer to the strings.  */
   105    loc->filename = runtime_gostringnocopy ((const byte *) filename);
   106    loc->function = runtime_gostringnocopy ((const byte *) function);
   107  
   108    loc->lineno = lineno;
   109    ++arg->index;
   110  
   111    /* There is no point to tracing past certain runtime functions.
   112       Stopping the backtrace here can avoid problems on systems that
   113       don't provide proper unwind information for makecontext, such as
   114       Solaris (http://gcc.gnu.org/PR52583 comment #21).  */
   115    if (function != NULL)
   116      {
   117        if (__builtin_strcmp (function, "makecontext") == 0)
   118  	return 1;
   119        if (filename != NULL)
   120  	{
   121  	  const char *p;
   122  
   123  	  p = strrchr (filename, '/');
   124  	  if (p == NULL)
   125  	    p = filename;
   126  	  if (__builtin_strcmp (p, "/proc.c") == 0)
   127  	    {
   128  	      if (__builtin_strcmp (function, "kickoff") == 0
   129  		  || __builtin_strcmp (function, "runtime_mstart") == 0
   130  		  || __builtin_strcmp (function, "runtime_main") == 0)
   131  		return 1;
   132  	    }
   133  	}
   134      }
   135  
   136    return arg->index >= arg->max;
   137  }
   138  
   139  /* Error callback.  */
   140  
   141  static void
   142  error_callback (void *data __attribute__ ((unused)),
   143  		const char *msg, int errnum)
   144  {
   145    if (errnum == -1)
   146      {
   147        /* No debug info available.  Carry on as best we can.  */
   148        return;
   149      }
   150    if (errnum != 0)
   151      runtime_printf ("%s errno %d\n", msg, errnum);
   152    runtime_throw (msg);
   153  }
   154  
   155  /* Gather caller PC's.  */
   156  
   157  int32
   158  runtime_callers (int32 skip, Location *locbuf, int32 m, bool keep_thunks)
   159  {
   160    struct callers_data data;
   161  
   162    data.locbuf = locbuf;
   163    data.skip = skip + 1;
   164    data.index = 0;
   165    data.max = m;
   166    data.keep_thunks = keep_thunks;
   167    runtime_xadd (&runtime_in_callers, 1);
   168    backtrace_full (__go_get_backtrace_state (), 0, callback, error_callback,
   169  		  &data);
   170    runtime_xadd (&runtime_in_callers, -1);
   171    return data.index;
   172  }
   173  
   174  int Callers (int, struct __go_open_array)
   175    __asm__ (GOSYM_PREFIX "runtime.Callers");
   176  
   177  int
   178  Callers (int skip, struct __go_open_array pc)
   179  {
   180    Location *locbuf;
   181    int ret;
   182    int i;
   183  
   184    locbuf = (Location *) runtime_mal (pc.__count * sizeof (Location));
   185  
   186    /* In the Go 1 release runtime.Callers has an off-by-one error,
   187       which we can not correct because it would break backward
   188       compatibility.  Normally we would add 1 to SKIP here, but we
   189       don't so that we are compatible.  */
   190    ret = runtime_callers (skip, locbuf, pc.__count, false);
   191  
   192    for (i = 0; i < ret; i++)
   193      ((uintptr *) pc.__values)[i] = locbuf[i].pc;
   194  
   195    return ret;
   196  }