(root)/
gcc-13.2.0/
libbacktrace/
btest.c
       1  /* btest.c -- Test for libbacktrace library
       2     Copyright (C) 2012-2023 Free Software Foundation, Inc.
       3     Written by Ian Lance Taylor, Google.
       4  
       5  Redistribution and use in source and binary forms, with or without
       6  modification, are permitted provided that the following conditions are
       7  met:
       8  
       9      (1) Redistributions of source code must retain the above copyright
      10      notice, this list of conditions and the following disclaimer.
      11  
      12      (2) Redistributions in binary form must reproduce the above copyright
      13      notice, this list of conditions and the following disclaimer in
      14      the documentation and/or other materials provided with the
      15      distribution.
      16  
      17      (3) The name of the author may not be used to
      18      endorse or promote products derived from this software without
      19      specific prior written permission.
      20  
      21  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      22  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
      23  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      24  DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
      25  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      26  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      27  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
      29  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
      30  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      31  POSSIBILITY OF SUCH DAMAGE.  */
      32  
      33  /* This program tests the externally visible interfaces of the
      34     libbacktrace library.  */
      35  
      36  #include <assert.h>
      37  #include <stdio.h>
      38  #include <stdlib.h>
      39  #include <string.h>
      40  #include <unistd.h>
      41  #include <sys/stat.h>
      42  
      43  #include "filenames.h"
      44  
      45  #include "backtrace.h"
      46  #include "backtrace-supported.h"
      47  
      48  #include "testlib.h"
      49  
      50  /* Test the backtrace function with non-inlined functions.  */
      51  
      52  static int test1 (void) __attribute__ ((noinline, noclone, unused));
      53  static int f2 (int) __attribute__ ((noinline, noclone));
      54  static int f3 (int, int) __attribute__ ((noinline, noclone));
      55  
      56  static int
      57  test1 (void)
      58  {
      59    /* Returning a value here and elsewhere avoids a tailcall which
      60       would mess up the backtrace.  */
      61    return f2 (__LINE__) + 1;
      62  }
      63  
      64  static int
      65  f2 (int f1line)
      66  {
      67    return f3 (f1line, __LINE__) + 2;
      68  }
      69  
      70  static int
      71  f3 (int f1line, int f2line)
      72  {
      73    struct info all[20];
      74    struct bdata data;
      75    int f3line;
      76    int i;
      77  
      78    data.all = &all[0];
      79    data.index = 0;
      80    data.max = 20;
      81    data.failed = 0;
      82  
      83    f3line = __LINE__ + 1;
      84    i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
      85  
      86    if (i != 0)
      87      {
      88        fprintf (stderr, "test1: unexpected return value %d\n", i);
      89        data.failed = 1;
      90      }
      91  
      92    if (data.index < 3)
      93      {
      94        fprintf (stderr,
      95  	       "test1: not enough frames; got %zu, expected at least 3\n",
      96  	       data.index);
      97        data.failed = 1;
      98      }
      99  
     100    check ("test1", 0, all, f3line, "f3", "btest.c", &data.failed);
     101    check ("test1", 1, all, f2line, "f2", "btest.c", &data.failed);
     102    check ("test1", 2, all, f1line, "test1", "btest.c", &data.failed);
     103  
     104    printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
     105  
     106    if (data.failed)
     107      ++failures;
     108  
     109    return failures;
     110  }
     111  
     112  /* Test the backtrace function with inlined functions.  */
     113  
     114  static inline int test2 (void) __attribute__ ((always_inline, unused));
     115  static inline int f12 (int) __attribute__ ((always_inline));
     116  static inline int f13 (int, int) __attribute__ ((always_inline));
     117  
     118  static inline int
     119  test2 (void)
     120  {
     121    return f12 (__LINE__) + 1;
     122  }
     123  
     124  static inline int
     125  f12 (int f1line)
     126  {
     127    return f13 (f1line, __LINE__) + 2;
     128  }
     129  
     130  static inline int
     131  f13 (int f1line, int f2line)
     132  {
     133    struct info all[20];
     134    struct bdata data;
     135    int f3line;
     136    int i;
     137  
     138    data.all = &all[0];
     139    data.index = 0;
     140    data.max = 20;
     141    data.failed = 0;
     142  
     143    f3line = __LINE__ + 1;
     144    i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
     145  
     146    if (i != 0)
     147      {
     148        fprintf (stderr, "test2: unexpected return value %d\n", i);
     149        data.failed = 1;
     150      }
     151  
     152    check ("test2", 0, all, f3line, "f13", "btest.c", &data.failed);
     153    check ("test2", 1, all, f2line, "f12", "btest.c", &data.failed);
     154    check ("test2", 2, all, f1line, "test2", "btest.c", &data.failed);
     155  
     156    printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS");
     157  
     158    if (data.failed)
     159      ++failures;
     160  
     161    return failures;
     162  }
     163  
     164  /* Test the backtrace_simple function with non-inlined functions.  */
     165  
     166  static int test3 (void) __attribute__ ((noinline, noclone, unused));
     167  static int f22 (int) __attribute__ ((noinline, noclone));
     168  static int f23 (int, int) __attribute__ ((noinline, noclone));
     169  
     170  static int
     171  test3 (void)
     172  {
     173    return f22 (__LINE__) + 1;
     174  }
     175  
     176  static int
     177  f22 (int f1line)
     178  {
     179    return f23 (f1line, __LINE__) + 2;
     180  }
     181  
     182  static int
     183  f23 (int f1line, int f2line)
     184  {
     185    uintptr_t addrs[20];
     186    struct sdata data;
     187    int f3line;
     188    int i;
     189  
     190    data.addrs = &addrs[0];
     191    data.index = 0;
     192    data.max = 20;
     193    data.failed = 0;
     194  
     195    f3line = __LINE__ + 1;
     196    i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
     197  
     198    if (i != 0)
     199      {
     200        fprintf (stderr, "test3: unexpected return value %d\n", i);
     201        data.failed = 1;
     202      }
     203  
     204    if (!data.failed)
     205      {
     206        struct info all[20];
     207        struct bdata bdata;
     208        int j;
     209  
     210        bdata.all = &all[0];
     211        bdata.index = 0;
     212        bdata.max = 20;
     213        bdata.failed = 0;
     214  
     215        for (j = 0; j < 3; ++j)
     216  	{
     217  	  i = backtrace_pcinfo (state, addrs[j], callback_one,
     218  				error_callback_one, &bdata);
     219  	  if (i != 0)
     220  	    {
     221  	      fprintf (stderr,
     222  		       ("test3: unexpected return value "
     223  			"from backtrace_pcinfo %d\n"),
     224  		       i);
     225  	      bdata.failed = 1;
     226  	    }
     227  	  if (!bdata.failed && bdata.index != (size_t) (j + 1))
     228  	    {
     229  	      fprintf (stderr,
     230  		       ("wrong number of calls from backtrace_pcinfo "
     231  			"got %u expected %d\n"),
     232  		       (unsigned int) bdata.index, j + 1);
     233  	      bdata.failed = 1;
     234  	    }
     235  	}
     236  
     237        check ("test3", 0, all, f3line, "f23", "btest.c", &bdata.failed);
     238        check ("test3", 1, all, f2line, "f22", "btest.c", &bdata.failed);
     239        check ("test3", 2, all, f1line, "test3", "btest.c", &bdata.failed);
     240  
     241        if (bdata.failed)
     242  	data.failed = 1;
     243  
     244        for (j = 0; j < 3; ++j)
     245  	{
     246  	  struct symdata symdata;
     247  
     248  	  symdata.name = NULL;
     249  	  symdata.val = 0;
     250  	  symdata.size = 0;
     251  	  symdata.failed = 0;
     252  
     253  	  i = backtrace_syminfo (state, addrs[j], callback_three,
     254  				 error_callback_three, &symdata);
     255  	  if (i == 0)
     256  	    {
     257  	      fprintf (stderr,
     258  		       ("test3: [%d]: unexpected return value "
     259  			"from backtrace_syminfo %d\n"),
     260  		       j, i);
     261  	      symdata.failed = 1;
     262  	    }
     263  
     264  	  if (!symdata.failed)
     265  	    {
     266  	      const char *expected;
     267  
     268  	      switch (j)
     269  		{
     270  		case 0:
     271  		  expected = "f23";
     272  		  break;
     273  		case 1:
     274  		  expected = "f22";
     275  		  break;
     276  		case 2:
     277  		  expected = "test3";
     278  		  break;
     279  		default:
     280  		  assert (0);
     281  		}
     282  
     283  	      if (symdata.name == NULL)
     284  		{
     285  		  fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j);
     286  		  symdata.failed = 1;
     287  		}
     288  	      /* Use strncmp, not strcmp, because GCC might create a
     289  		 clone.  */
     290  	      else if (strncmp (symdata.name, expected, strlen (expected))
     291  		       != 0)
     292  		{
     293  		  fprintf (stderr,
     294  			   ("test3: [%d]: unexpected syminfo name "
     295  			    "got %s expected %s\n"),
     296  			   j, symdata.name, expected);
     297  		  symdata.failed = 1;
     298  		}
     299  	    }
     300  
     301  	  if (symdata.failed)
     302  	    data.failed = 1;
     303  	}
     304      }
     305  
     306    printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS");
     307  
     308    if (data.failed)
     309      ++failures;
     310  
     311    return failures;
     312  }
     313  
     314  /* Test the backtrace_simple function with inlined functions.  */
     315  
     316  static inline int test4 (void) __attribute__ ((always_inline, unused));
     317  static inline int f32 (int) __attribute__ ((always_inline));
     318  static inline int f33 (int, int) __attribute__ ((always_inline));
     319  
     320  static inline int
     321  test4 (void)
     322  {
     323    return f32 (__LINE__) + 1;
     324  }
     325  
     326  static inline int
     327  f32 (int f1line)
     328  {
     329    return f33 (f1line, __LINE__) + 2;
     330  }
     331  
     332  static inline int
     333  f33 (int f1line, int f2line)
     334  {
     335    uintptr_t addrs[20];
     336    struct sdata data;
     337    int f3line;
     338    int i;
     339  
     340    data.addrs = &addrs[0];
     341    data.index = 0;
     342    data.max = 20;
     343    data.failed = 0;
     344  
     345    f3line = __LINE__ + 1;
     346    i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
     347  
     348    if (i != 0)
     349      {
     350        fprintf (stderr, "test3: unexpected return value %d\n", i);
     351        data.failed = 1;
     352      }
     353  
     354    if (!data.failed)
     355      {
     356        struct info all[20];
     357        struct bdata bdata;
     358  
     359        bdata.all = &all[0];
     360        bdata.index = 0;
     361        bdata.max = 20;
     362        bdata.failed = 0;
     363  
     364        i = backtrace_pcinfo (state, addrs[0], callback_one, error_callback_one,
     365  			    &bdata);
     366        if (i != 0)
     367  	{
     368  	  fprintf (stderr,
     369  		   ("test4: unexpected return value "
     370  		    "from backtrace_pcinfo %d\n"),
     371  		   i);
     372  	  bdata.failed = 1;
     373  	}
     374  
     375        check ("test4", 0, all, f3line, "f33", "btest.c", &bdata.failed);
     376        check ("test4", 1, all, f2line, "f32", "btest.c", &bdata.failed);
     377        check ("test4", 2, all, f1line, "test4", "btest.c", &bdata.failed);
     378  
     379        if (bdata.failed)
     380  	data.failed = 1;
     381      }
     382  
     383    printf ("%s: backtrace_simple inline\n", data.failed ? "FAIL" : "PASS");
     384  
     385    if (data.failed)
     386      ++failures;
     387  
     388    return failures;
     389  }
     390  
     391  static int test5 (void) __attribute__ ((unused));
     392  
     393  int global = 1;
     394  
     395  static int
     396  test5 (void)
     397  {
     398    struct symdata symdata;
     399    int i;
     400    uintptr_t addr = (uintptr_t) &global;
     401  
     402    if (sizeof (global) > 1)
     403      addr += 1;
     404  
     405    symdata.name = NULL;
     406    symdata.val = 0;
     407    symdata.size = 0;
     408    symdata.failed = 0;
     409  
     410    i = backtrace_syminfo (state, addr, callback_three,
     411  			 error_callback_three, &symdata);
     412    if (i == 0)
     413      {
     414        fprintf (stderr,
     415  	       "test5: unexpected return value from backtrace_syminfo %d\n",
     416  	       i);
     417        symdata.failed = 1;
     418      }
     419  
     420    if (!symdata.failed)
     421      {
     422        if (symdata.name == NULL)
     423  	{
     424  	  fprintf (stderr, "test5: NULL syminfo name\n");
     425  	  symdata.failed = 1;
     426  	}
     427        else if (!(strncmp (symdata.name, "global", 6) == 0
     428  		 && (symdata.name[6] == '\0'|| symdata.name[6] == '.')))
     429  	{
     430  	  fprintf (stderr,
     431  		   "test5: unexpected syminfo name got %s expected %s\n",
     432  		   symdata.name, "global");
     433  	  symdata.failed = 1;
     434  	}
     435        else if (symdata.val != (uintptr_t) &global)
     436  	{
     437  	  fprintf (stderr,
     438  		   "test5: unexpected syminfo value got %lx expected %lx\n",
     439  		   (unsigned long) symdata.val,
     440  		   (unsigned long) (uintptr_t) &global);
     441  	  symdata.failed = 1;
     442  	}
     443        else if (symdata.size != sizeof (global))
     444  	{
     445  	  fprintf (stderr,
     446  		   "test5: unexpected syminfo size got %lx expected %lx\n",
     447  		   (unsigned long) symdata.size,
     448  		   (unsigned long) sizeof (global));
     449  	  symdata.failed = 1;
     450  	}
     451      }
     452  
     453    printf ("%s: backtrace_syminfo variable\n",
     454  	  symdata.failed ? "FAIL" : "PASS");
     455  
     456    if (symdata.failed)
     457      ++failures;
     458  
     459    return failures;
     460  }
     461  
     462  #define MIN_DESCRIPTOR 3
     463  #define MAX_DESCRIPTOR 10
     464  
     465  static int fstat_status[MAX_DESCRIPTOR];
     466  
     467  /* Check files that are available.  */
     468  
     469  static void
     470  check_available_files (void)
     471  {
     472    struct stat s;
     473    for (unsigned i = MIN_DESCRIPTOR; i < MAX_DESCRIPTOR; i++)
     474      fstat_status[i] = fstat (i, &s);
     475  }
     476  
     477  /* Check that are no files left open.  */
     478  
     479  static void
     480  check_open_files (void)
     481  {
     482    for (unsigned i = MIN_DESCRIPTOR; i < MAX_DESCRIPTOR; i++)
     483      {
     484        if (fstat_status[i] != 0 && close (i) == 0)
     485  	{
     486  	  fprintf (stderr,
     487  		   "ERROR: descriptor %d still open after tests complete\n",
     488  		   i);
     489  	  ++failures;
     490  	}
     491      }
     492  }
     493  
     494  /* Run all the tests.  */
     495  
     496  int
     497  main (int argc ATTRIBUTE_UNUSED, char **argv)
     498  {
     499    check_available_files ();
     500  
     501    state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
     502  				  error_callback_create, NULL);
     503  
     504  #if BACKTRACE_SUPPORTED
     505    test1 ();
     506    test2 ();
     507    test3 ();
     508    test4 ();
     509  #if BACKTRACE_SUPPORTS_DATA
     510    test5 ();
     511  #endif
     512  #endif
     513  
     514    check_open_files ();
     515  
     516    exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
     517  }