github.com/golang/gofrontend@v0.0.0-20240429183944-60f985a78526/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 __go_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    int saw_sigtramp;
    31  };
    32  
    33  /* Whether to skip a particular function name in the traceback.  This
    34     is mostly to keep the output similar to the gc output for
    35     runtime.Caller(N).
    36  
    37     See also similar code in runtime/mprof.go that strips out such
    38     functions for block/mutex/memory profiles.  */
    39  
    40  bool
    41  runtime_skipInCallback(const char *function, struct callers_data *arg)
    42  {
    43    const char *p;
    44  
    45    /* Skip thunks and recover functions.  There is no equivalent to
    46       these functions in the gc toolchain.  */
    47  
    48    p = function + __builtin_strlen (function);
    49    while (p > function && p[-1] >= '0' && p[-1] <= '9')
    50      --p;
    51    if (p - function > 7 && __builtin_strncmp (p - 7, "..thunk", 7) == 0)
    52      return true;
    53    if (p - function > 3 && __builtin_strcmp (p - 3, "..r") == 0)
    54      return true;
    55    if (p - function > 6 && __builtin_strncmp (p - 6, "..stub", 6) == 0)
    56      return true;
    57  
    58    /* Skip runtime.deferreturn and runtime.sighandler as the gc
    59       compiler has no corresponding function.  */
    60    if (p - function == sizeof ("runtime.deferreturn") - 1
    61        && __builtin_strcmp (function, "runtime.deferreturn") == 0)
    62      return true;
    63    if (p - function == sizeof ("runtime.sighandler") - 1
    64        && __builtin_strcmp (function, "runtime.sighandler") == 0)
    65      return true;
    66  
    67    /* Skip the signal handler functions that remain on the stack for us
    68       but not for gc.  */
    69    if ((p - function == sizeof ("runtime.sigtramp") - 1
    70         && __builtin_strcmp (function, "runtime.sigtramp") == 0)
    71        || (p - function == sizeof ("runtime.sigtrampgo") - 1
    72  	  && __builtin_strcmp (function, "runtime.sigtrampgo") == 0))
    73      {
    74        /* Also try to skip the signal handler function.  */
    75        if (arg != NULL)
    76  	arg->saw_sigtramp = 1;
    77        return true;
    78      }
    79  
    80    return false;
    81  }
    82  
    83  /* Callback function for backtrace_full.  Just collect the locations.
    84     Return zero to continue, non-zero to stop.  */
    85  
    86  static int
    87  callback (void *data, uintptr_t pc, const char *filename, int lineno,
    88  	  const char *function)
    89  {
    90    struct callers_data *arg = (struct callers_data *) data;
    91    Location *loc;
    92  
    93    /* Skip an unnamed function above sigtramp.  It is likely the signal
    94       handler function.  */
    95    if (arg->saw_sigtramp)
    96      {
    97        arg->saw_sigtramp = 0;
    98        if (function == NULL)
    99  	return 0;
   100      }
   101  
   102    /* Skip split stack functions.  */
   103    if (function != NULL)
   104      {
   105        const char *p;
   106  
   107        p = function;
   108        if (__builtin_strncmp (p, "___", 3) == 0)
   109  	++p;
   110        if (__builtin_strncmp (p, "__morestack", 11) == 0)
   111  	return 0;
   112      }
   113    else if (filename != NULL)
   114      {
   115        const char *p;
   116  
   117        p = strrchr (filename, '/');
   118        if (p == NULL)
   119  	p = filename;
   120        if (__builtin_strncmp (p, "/morestack.S", 12) == 0)
   121  	return 0;
   122      }
   123  
   124    if (function != NULL
   125        && !arg->keep_thunks
   126        && runtime_skipInCallback (function, arg))
   127      return 0;
   128  
   129    if (arg->skip > 0)
   130      {
   131        --arg->skip;
   132        return 0;
   133      }
   134  
   135    loc = &arg->locbuf[arg->index];
   136  
   137    /* On the call to backtrace_full the pc value was most likely
   138       decremented if there was a normal call, since the pc referred to
   139       the instruction where the call returned and not the call itself.
   140       This was done so that the line number referred to the call
   141       instruction.  To make sure the actual pc from the call stack is
   142       used, it is incremented here.
   143  
   144       In the case of a signal, the pc was not decremented by
   145       backtrace_full but still incremented here.  That doesn't really
   146       hurt anything since the line number is right and the pc refers to
   147       the same instruction.  */
   148  
   149    loc->pc = pc + 1;
   150  
   151    /* The libbacktrace library says that these strings might disappear,
   152       but with the current implementation they won't.  We can't easily
   153       allocate memory here, so for now assume that we can save a
   154       pointer to the strings.  */
   155    loc->filename = runtime_gostringnocopy ((const byte *) filename);
   156    loc->function = runtime_gostringnocopy ((const byte *) function);
   157  
   158    loc->lineno = lineno;
   159    ++arg->index;
   160  
   161    /* There is no point to tracing past certain runtime functions.
   162       Stopping the backtrace here can avoid problems on systems that
   163       don't provide proper unwind information for makecontext, such as
   164       Solaris (http://gcc.gnu.org/PR52583 comment #21).  */
   165    if (function != NULL)
   166      {
   167        if (__builtin_strcmp (function, "makecontext") == 0)
   168  	return 1;
   169        if (filename != NULL)
   170  	{
   171  	  const char *p;
   172  
   173  	  p = strrchr (filename, '/');
   174  	  if (p == NULL)
   175  	    p = filename;
   176  	  if (__builtin_strcmp (p, "/proc.c") == 0)
   177  	    {
   178  	      if (__builtin_strcmp (function, "runtime_mstart") == 0)
   179  		return 1;
   180  	    }
   181  	  else if (__builtin_strcmp (p, "/proc.go") == 0)
   182  	    {
   183  	      if (__builtin_strcmp (function, "runtime.kickoff") == 0
   184  		  || __builtin_strcmp (function, "runtime.main") == 0)
   185  		return 1;
   186  	    }
   187  	}
   188      }
   189  
   190    return arg->index >= arg->max;
   191  }
   192  
   193  /* Syminfo callback.  */
   194  
   195  void
   196  __go_syminfo_fnname_callback (void *data,
   197  			      uintptr_t pc __attribute__ ((unused)),
   198  			      const char *symname,
   199  			      uintptr_t address __attribute__ ((unused)),
   200  			      uintptr_t size __attribute__ ((unused)))
   201  {
   202    String* strptr = (String*) data;
   203  
   204    if (symname != NULL)
   205      *strptr = runtime_gostringnocopy ((const byte *) symname);
   206  }
   207  
   208  /* Error callback.  */
   209  
   210  static void
   211  error_callback (void *data __attribute__ ((unused)),
   212  		const char *msg, int errnum)
   213  {
   214    if (errnum == -1)
   215      {
   216        /* No debug info available.  Carry on as best we can.  */
   217        return;
   218      }
   219    if (errnum != 0)
   220      runtime_printf ("%s errno %d\n", msg, errnum);
   221    runtime_throw (msg);
   222  }
   223  
   224  /* Return whether we are already collecting a stack trace. This is
   225     called from the signal handler.  */
   226  
   227  bool alreadyInCallers(void)
   228    __attribute__ ((no_split_stack));
   229  bool alreadyInCallers(void)
   230    __asm__ (GOSYM_PREFIX "runtime.alreadyInCallers");
   231  
   232  bool
   233  alreadyInCallers()
   234  {
   235    return runtime_atomicload(&__go_runtime_in_callers) > 0;
   236  }
   237  
   238  /* Gather caller PC's.  */
   239  
   240  int32
   241  runtime_callers (int32 skip, Location *locbuf, int32 m, bool keep_thunks)
   242  {
   243    struct callers_data data;
   244    struct backtrace_state* state;
   245    int32 i;
   246  
   247    data.locbuf = locbuf;
   248    data.skip = skip + 1;
   249    data.index = 0;
   250    data.max = m;
   251    data.keep_thunks = keep_thunks;
   252    data.saw_sigtramp = 0;
   253    runtime_xadd (&__go_runtime_in_callers, 1);
   254    state = __go_get_backtrace_state ();
   255    backtrace_full (state, 0, callback, error_callback, &data);
   256    runtime_xadd (&__go_runtime_in_callers, -1);
   257  
   258    /* For some reason GCC sometimes loses the name of a thunk function
   259       at the top of the stack.  If we are skipping thunks, skip that
   260       one too.  */
   261    if (!keep_thunks
   262        && data.index > 2
   263        && locbuf[data.index - 2].function.len == 0
   264        && locbuf[data.index - 1].function.str != NULL
   265        && __builtin_strcmp ((const char *) locbuf[data.index - 1].function.str,
   266  			   "runtime.kickoff") == 0)
   267      {
   268        locbuf[data.index - 2] = locbuf[data.index - 1];
   269        --data.index;
   270      }
   271  
   272    /* Try to use backtrace_syminfo to fill in any missing function
   273       names.  This can happen when tracing through an object which has
   274       no debug info; backtrace_syminfo will look at the symbol table to
   275       get the name.  This should only happen when tracing through code
   276       that is not written in Go and is not part of libgo.  */
   277    for (i = 0; i < data.index; ++i)
   278      {
   279        if (locbuf[i].function.len == 0 && locbuf[i].pc != 0)
   280  	backtrace_syminfo (state, locbuf[i].pc, __go_syminfo_fnname_callback,
   281  			   error_callback, &locbuf[i].function);
   282      }
   283  
   284    return data.index;
   285  }
   286  
   287  intgo Callers (intgo, struct __go_open_array)
   288    __asm__ (GOSYM_PREFIX "runtime.Callers");
   289  
   290  intgo
   291  Callers (intgo skip, struct __go_open_array pc)
   292  {
   293    Location *locbuf;
   294    int ret;
   295    int i;
   296  
   297    if (pc.__count == 0)
   298      return 0;
   299  
   300    /* Note that calling mallocgc here assumes that we are not going to
   301       store any allocated Go pointers in the slice.  */
   302    locbuf = (Location *) runtime_mallocgc (pc.__count * sizeof (Location),
   303  					  nil, false);
   304  
   305    /* In the Go 1 release runtime.Callers has an off-by-one error,
   306       which we can not correct because it would break backward
   307       compatibility.  Normally we would add 1 to SKIP here, but we
   308       don't so that we are compatible.  */
   309    ret = runtime_callers (skip, locbuf, pc.__count, false);
   310  
   311    for (i = 0; i < ret; i++)
   312      ((uintptr *) pc.__values)[i] = locbuf[i].pc;
   313  
   314    return ret;
   315  }
   316  
   317  struct callersRaw_data
   318  {
   319    uintptr* pcbuf;
   320    int index;
   321    int max;
   322  };
   323  
   324  // Callback function for backtrace_simple.  Just collect pc's.
   325  // Return zero to continue, non-zero to stop.
   326  
   327  static int callback_raw (void *data, uintptr_t pc)
   328  {
   329    struct callersRaw_data *arg = (struct callersRaw_data *) data;
   330  
   331    /* On the call to backtrace_simple the pc value was most likely
   332       decremented if there was a normal call, since the pc referred to
   333       the instruction where the call returned and not the call itself.
   334       This was done so that the line number referred to the call
   335       instruction.  To make sure the actual pc from the call stack is
   336       used, it is incremented here.
   337  
   338       In the case of a signal, the pc was not decremented by
   339       backtrace_full but still incremented here.  That doesn't really
   340       hurt anything since the line number is right and the pc refers to
   341       the same instruction.  */
   342  
   343    arg->pcbuf[arg->index] = pc + 1;
   344    arg->index++;
   345    return arg->index >= arg->max;
   346  }
   347  
   348  /* runtime_callersRaw is similar to runtime_callers() above, but
   349     it returns raw PC values as opposed to file/func/line locations. */
   350  int32
   351  runtime_callersRaw (uintptr *pcbuf, int32 m)
   352  {
   353    struct callersRaw_data data;
   354    struct backtrace_state* state;
   355  
   356    data.pcbuf = pcbuf;
   357    data.index = 0;
   358    data.max = m;
   359    runtime_xadd (&__go_runtime_in_callers, 1);
   360    state = __go_get_backtrace_state ();
   361    backtrace_simple (state, 0, callback_raw, error_callback, &data);
   362    runtime_xadd (&__go_runtime_in_callers, -1);
   363  
   364    return data.index;
   365  }
   366  
   367  /* runtime_pcInlineCallers returns the inline stack of calls for a PC.
   368     This is like runtime_callers, but instead of doing a backtrace,
   369     just finds the information for a single PC value.  */
   370  
   371  int32 runtime_pcInlineCallers (uintptr, Location *, int32)
   372    __asm__ (GOSYM_PREFIX "runtime.pcInlineCallers");
   373  
   374  int32
   375  runtime_pcInlineCallers (uintptr pc, Location *locbuf, int32 m)
   376  {
   377    struct callers_data data;
   378    struct backtrace_state *state;
   379    int32 i;
   380  
   381    data.locbuf = locbuf;
   382    data.skip = 0;
   383    data.index = 0;
   384    data.max = m;
   385    data.keep_thunks = false;
   386    data.saw_sigtramp = 0;
   387    runtime_xadd (&__go_runtime_in_callers, 1);
   388    state = __go_get_backtrace_state ();
   389    backtrace_pcinfo (state, pc, callback, error_callback, &data);
   390    runtime_xadd (&__go_runtime_in_callers, -1);
   391  
   392    /* Try to use backtrace_syminfo to fill in missing names.  See
   393       runtime_callers.  */
   394    for (i = 0; i < data.index; ++i)
   395      {
   396        if (locbuf[i].function.len == 0 && locbuf[i].pc != 0)
   397  	backtrace_syminfo (state, locbuf[i].pc, __go_syminfo_fnname_callback,
   398  			   error_callback, &locbuf[i].function);
   399      }
   400  
   401    return data.index;
   402  }