(root)/
gcc-13.2.0/
libgfortran/
runtime/
backtrace.c
       1  /* Copyright (C) 2006-2023 Free Software Foundation, Inc.
       2     Contributed by François-Xavier Coudert
       3  
       4  This file is part of the GNU Fortran runtime library (libgfortran).
       5  
       6  Libgfortran is free software; you can redistribute it and/or modify
       7  it under the terms of the GNU General Public License as published by
       8  the Free Software Foundation; either version 3, or (at your option)
       9  any later version.
      10  
      11  Libgfortran is distributed in the hope that it will be useful,
      12  but WITHOUT ANY WARRANTY; without even the implied warranty of
      13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14  GNU General Public License for more details.
      15  
      16  Under Section 7 of GPL version 3, you are granted additional
      17  permissions described in the GCC Runtime Library Exception, version
      18  3.1, as published by the Free Software Foundation.
      19  
      20  You should have received a copy of the GNU General Public License and
      21  a copy of the GCC Runtime Library Exception along with this program;
      22  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      23  <http://www.gnu.org/licenses/>.  */
      24  
      25  #include "libgfortran.h"
      26  
      27  #include <gthr.h>
      28  
      29  #include <string.h>
      30  #include <errno.h>
      31  
      32  #ifdef HAVE_UNISTD_H
      33  #include <unistd.h>
      34  #endif
      35  
      36  #include "backtrace-supported.h"
      37  #include "backtrace.h"
      38  
      39  
      40  /* Store our own state while backtracing.  */
      41  struct mystate
      42  {
      43    int frame;
      44    bool try_simple;
      45    bool in_signal_handler;
      46  };
      47  
      48  
      49  /* Does a function name have "_gfortran_" or "_gfortrani_" prefix, possibly
      50     with additional underscore(s) at the beginning?  Cannot use strncmp()
      51     because we might be called from a signal handler.  */
      52  
      53  static int
      54  has_gfortran_prefix (const char *s)
      55  {
      56    if (!s)
      57      return 0;
      58  
      59    while (*s == '_')
      60      s++;
      61  
      62    return (s[0] == 'g' && s[1] == 'f' && s[2] == 'o' && s[3] == 'r'
      63  	  && s[4] == 't' && s[5] == 'r' && s[6] == 'a' && s[7] == 'n'
      64  	  && (s[8] == '_' || (s[8] == 'i' && s[9] == '_')));
      65  }
      66  
      67  static void
      68  error_callback (void *data, const char *msg, int errnum)
      69  {
      70    struct mystate *state = (struct mystate *) data;
      71    struct iovec iov[5];
      72  #define ERRHDR "\nCould not print backtrace: "
      73  
      74    if (errnum < 0)
      75      {
      76        state->try_simple = true;
      77        return;
      78      }
      79    else if (errnum == 0)
      80      {
      81        iov[0].iov_base = (char*) ERRHDR;
      82        iov[0].iov_len = strlen (ERRHDR);
      83        iov[1].iov_base = (char*) msg;
      84        iov[1].iov_len = strlen (msg);
      85        iov[2].iov_base = (char*) "\n";
      86        iov[2].iov_len = 1;
      87        estr_writev (iov, 3);
      88      }
      89    else
      90      {
      91        char errbuf[256];
      92        if (state->in_signal_handler)
      93  	{
      94  	  iov[0].iov_base = (char*) ERRHDR;
      95  	  iov[0].iov_len = strlen (ERRHDR);
      96  	  iov[1].iov_base = (char*) msg;
      97  	  iov[1].iov_len = strlen (msg);
      98  	  iov[2].iov_base = (char*) ", errno: ";
      99  	  iov[2].iov_len = strlen (iov[2].iov_base);
     100  	  /* Async-signal-safe function, errnum must be positive.  */
     101  	  const char *p = gfc_itoa (errnum, errbuf, sizeof (errbuf));
     102  	  iov[3].iov_base = (char*) p;
     103  	  iov[3].iov_len = strlen (p);
     104  	  iov[4].iov_base = (char*) "\n";
     105  	  iov[4].iov_len = 1;
     106  	  estr_writev (iov, 5);
     107  	}
     108        else
     109  	st_printf (ERRHDR "%s: %s\n", msg,
     110  		  gf_strerror (errnum, errbuf, sizeof (errbuf)));
     111      }
     112  }
     113  
     114  static int
     115  simple_callback (void *data, uintptr_t pc)
     116  {
     117    struct mystate *state = (struct mystate *) data;
     118    st_printf ("#%d  0x%lx\n", state->frame, (unsigned long) pc);
     119    (state->frame)++;
     120    return 0;
     121  }
     122  
     123  static int
     124  full_callback (void *data, uintptr_t pc, const char *filename,
     125  	       int lineno, const char *function)
     126  {
     127    struct mystate *state = (struct mystate *) data;
     128  
     129    if (has_gfortran_prefix (function))
     130      return 0;
     131  
     132    st_printf ("#%d  0x%lx in %s\n", state->frame,
     133  	     (unsigned long) pc, function == NULL ? "???" : function);
     134    if (filename || lineno != 0)
     135      st_printf ("\tat %s:%d\n", filename == NULL ? "???" : filename, lineno);
     136    (state->frame)++;
     137  
     138    if (function != NULL && strcmp (function, "main") == 0)
     139      return 1;
     140  
     141    return 0;
     142  }
     143  
     144  
     145  /* Display the backtrace.  */
     146  
     147  void
     148  show_backtrace (bool in_signal_handler)
     149  {
     150    /* Note that libbacktrace allows the state to be accessed from
     151       multiple threads, so we don't need to use a TLS variable for the
     152       state here.  */
     153    static struct backtrace_state *lbstate_saved;
     154    struct backtrace_state *lbstate;
     155    struct mystate state = { 0, false, in_signal_handler };
     156  
     157    lbstate = __atomic_load_n (&lbstate_saved, __ATOMIC_RELAXED);
     158    if (!lbstate)
     159      {
     160        lbstate = backtrace_create_state (NULL, __gthread_active_p (),
     161  					error_callback, NULL);
     162        if (lbstate)
     163  	__atomic_store_n (&lbstate_saved, lbstate, __ATOMIC_RELAXED);
     164        else
     165  	return;
     166      }
     167  
     168    if (!BACKTRACE_SUPPORTED || (in_signal_handler && BACKTRACE_USES_MALLOC))
     169      {
     170        /* If symbolic backtrace is not supported on this target, or would
     171  	 require malloc() and we are in a signal handler, go with a
     172  	 simple backtrace.  */
     173  
     174        backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
     175      }
     176    else
     177      {
     178        /* libbacktrace uses mmap, which is safe to call from a signal handler
     179  	 (in practice, if not in theory).  Thus we can generate a symbolic
     180  	 backtrace, if debug symbols are available.  */
     181  
     182        backtrace_full (lbstate, 0, full_callback, error_callback, &state);
     183        if (state.try_simple)
     184  	backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
     185      }
     186  }
     187  
     188  
     189  
     190  /* Function called by the front-end translating the BACKTRACE intrinsic.  */
     191  
     192  extern void backtrace (void);
     193  export_proto (backtrace);
     194  
     195  void
     196  backtrace (void)
     197  {
     198    show_backtrace (false);
     199  }
     200