github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/runtime/go-caller.c (about)

     1  /* go-caller.c -- runtime.Caller and runtime.FuncForPC for Go.
     2  
     3     Copyright 2009 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  /* Implement runtime.Caller.  */
     8  
     9  #include <stdint.h>
    10  #include <sys/types.h>
    11  #include <sys/stat.h>
    12  #include <unistd.h>
    13  
    14  #include "backtrace.h"
    15  
    16  #include "runtime.h"
    17  
    18  /* Get the function name, file name, and line number for a PC value.
    19     We use the backtrace library to get this.  */
    20  
    21  /* Data structure to gather file/line information.  */
    22  
    23  struct caller
    24  {
    25    String fn;
    26    String file;
    27    intgo line;
    28  };
    29  
    30  /* Collect file/line information for a PC value.  If this is called
    31     more than once, due to inlined functions, we use the last call, as
    32     that is usually the most useful one.  */
    33  
    34  static int
    35  callback (void *data, uintptr_t pc __attribute__ ((unused)),
    36  	  const char *filename, int lineno, const char *function)
    37  {
    38    struct caller *c = (struct caller *) data;
    39  
    40    /* The libbacktrace library says that these strings might disappear,
    41       but with the current implementation they won't.  We can't easily
    42       allocate memory here, so for now assume that we can save a
    43       pointer to the strings.  */
    44    c->fn = runtime_gostringnocopy ((const byte *) function);
    45    c->file = runtime_gostringnocopy ((const byte *) filename);
    46    c->line = lineno;
    47  
    48    return 0;
    49  }
    50  
    51  /* The error callback for backtrace_pcinfo and backtrace_syminfo.  */
    52  
    53  static void
    54  error_callback (void *data __attribute__ ((unused)),
    55  		const char *msg, int errnum)
    56  {
    57    if (errnum == -1)
    58      return;
    59    if (errnum > 0)
    60      runtime_printf ("%s errno %d\n", msg, errnum);
    61    runtime_throw (msg);
    62  }
    63  
    64  /* The backtrace library state.  */
    65  
    66  static void *back_state;
    67  
    68  /* A lock to control creating back_state.  */
    69  
    70  static Lock back_state_lock;
    71  
    72  /* Fetch back_state, creating it if necessary.  */
    73  
    74  struct backtrace_state *
    75  __go_get_backtrace_state ()
    76  {
    77    runtime_lock (&back_state_lock);
    78    if (back_state == NULL)
    79      {
    80        const char *filename;
    81        struct stat s;
    82  
    83        filename = (const char *) runtime_progname ();
    84  
    85        /* If there is no '/' in FILENAME, it was found on PATH, and
    86  	 might not be the same as the file with the same name in the
    87  	 current directory.  */
    88        if (__builtin_strchr (filename, '/') == NULL)
    89  	filename = NULL;
    90  
    91        /* If the file is small, then it's not the real executable.
    92  	 This is specifically to deal with Docker, which uses a bogus
    93  	 argv[0] (http://gcc.gnu.org/PR61895).  It would be nice to
    94  	 have a better check for whether this file is the real
    95  	 executable.  */
    96        if (stat (filename, &s) < 0 || s.st_size < 1024)
    97  	filename = NULL;
    98  
    99        back_state = backtrace_create_state (filename, 1, error_callback, NULL);
   100      }
   101    runtime_unlock (&back_state_lock);
   102    return back_state;
   103  }
   104  
   105  /* Return function/file/line information for PC.  */
   106  
   107  _Bool
   108  __go_file_line (uintptr pc, String *fn, String *file, intgo *line)
   109  {
   110    struct caller c;
   111  
   112    runtime_memclr (&c, sizeof c);
   113    backtrace_pcinfo (__go_get_backtrace_state (), pc, callback,
   114  		    error_callback, &c);
   115    *fn = c.fn;
   116    *file = c.file;
   117    *line = c.line;
   118    return c.file.len > 0;
   119  }
   120  
   121  /* Collect symbol information.  */
   122  
   123  static void
   124  syminfo_callback (void *data, uintptr_t pc __attribute__ ((unused)),
   125  		  const char *symname __attribute__ ((unused)),
   126  		  uintptr_t address, uintptr_t size __attribute__ ((unused)))
   127  {
   128    uintptr_t *pval = (uintptr_t *) data;
   129  
   130    *pval = address;
   131  }
   132  
   133  /* Set *VAL to the value of the symbol for PC.  */
   134  
   135  static _Bool
   136  __go_symbol_value (uintptr_t pc, uintptr_t *val)
   137  {
   138    *val = 0;
   139    backtrace_syminfo (__go_get_backtrace_state (), pc, syminfo_callback,
   140  		     error_callback, val);
   141    return *val != 0;
   142  }
   143  
   144  /* The values returned by runtime.Caller.  */
   145  
   146  struct caller_ret
   147  {
   148    uintptr_t pc;
   149    String file;
   150    intgo line;
   151    _Bool ok;
   152  };
   153  
   154  struct caller_ret Caller (int n) __asm__ (GOSYM_PREFIX "runtime.Caller");
   155  
   156  Func *FuncForPC (uintptr_t) __asm__ (GOSYM_PREFIX "runtime.FuncForPC");
   157  
   158  /* Implement runtime.Caller.  */
   159  
   160  struct caller_ret
   161  Caller (int skip)
   162  {
   163    struct caller_ret ret;
   164    Location loc;
   165    int32 n;
   166  
   167    runtime_memclr (&ret, sizeof ret);
   168    n = runtime_callers (skip + 1, &loc, 1, false);
   169    if (n < 1 || loc.pc == 0)
   170      return ret;
   171    ret.pc = loc.pc;
   172    ret.file = loc.filename;
   173    ret.line = loc.lineno;
   174    ret.ok = 1;
   175    return ret;
   176  }
   177  
   178  /* Implement runtime.FuncForPC.  */
   179  
   180  Func *
   181  FuncForPC (uintptr_t pc)
   182  {
   183    Func *ret;
   184    String fn;
   185    String file;
   186    intgo line;
   187    uintptr_t val;
   188  
   189    if (!__go_file_line (pc, &fn, &file, &line))
   190      return NULL;
   191  
   192    ret = (Func *) runtime_malloc (sizeof (*ret));
   193    ret->name = fn;
   194  
   195    if (__go_symbol_value (pc, &val))
   196      ret->entry = val;
   197    else
   198      ret->entry = 0;
   199  
   200    return ret;
   201  }
   202  
   203  /* Look up the file and line information for a PC within a
   204     function.  */
   205  
   206  struct funcline_go_return
   207  {
   208    String retfile;
   209    intgo retline;
   210  };
   211  
   212  struct funcline_go_return
   213  runtime_funcline_go (Func *f, uintptr targetpc)
   214    __asm__ (GOSYM_PREFIX "runtime.funcline_go");
   215  
   216  struct funcline_go_return
   217  runtime_funcline_go (Func *f __attribute__((unused)), uintptr targetpc)
   218  {
   219    struct funcline_go_return ret;
   220    String fn;
   221  
   222    if (!__go_file_line (targetpc, &fn, &ret.retfile,  &ret.retline))
   223      runtime_memclr (&ret, sizeof ret);
   224    return ret;
   225  }
   226  
   227  /* Return the name of a function.  */
   228  String runtime_funcname_go (Func *f)
   229    __asm__ (GOSYM_PREFIX "runtime.funcname_go");
   230  
   231  String
   232  runtime_funcname_go (Func *f)
   233  {
   234    if (f == NULL)
   235      return runtime_gostringnocopy ((const byte *) "");
   236    return f->name;
   237  }
   238  
   239  /* Return the entry point of a function.  */
   240  uintptr runtime_funcentry_go(Func *f)
   241    __asm__ (GOSYM_PREFIX "runtime.funcentry_go");
   242  
   243  uintptr
   244  runtime_funcentry_go (Func *f)
   245  {
   246    return f->entry;
   247  }