github.com/axw/llgo@v0.0.0-20160805011314-95b5fe4dca20/third_party/gofrontend/libbacktrace/btest.c (about)

     1  /* btest.c -- Test for libbacktrace library
     2     Copyright (C) 2012-2015 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  
    41  #include "filenames.h"
    42  
    43  #include "backtrace.h"
    44  #include "backtrace-supported.h"
    45  
    46  /* Portable attribute syntax.  Actually some of these tests probably
    47     won't work if the attributes are not recognized.  */
    48  
    49  #ifndef GCC_VERSION
    50  # define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
    51  #endif
    52  
    53  #if (GCC_VERSION < 2007)
    54  # define __attribute__(x)
    55  #endif
    56  
    57  #ifndef ATTRIBUTE_UNUSED
    58  # define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
    59  #endif
    60  
    61  /* Used to collect backtrace info.  */
    62  
    63  struct info
    64  {
    65    char *filename;
    66    int lineno;
    67    char *function;
    68  };
    69  
    70  /* Passed to backtrace callback function.  */
    71  
    72  struct bdata
    73  {
    74    struct info *all;
    75    size_t index;
    76    size_t max;
    77    int failed;
    78  };
    79  
    80  /* Passed to backtrace_simple callback function.  */
    81  
    82  struct sdata
    83  {
    84    uintptr_t *addrs;
    85    size_t index;
    86    size_t max;
    87    int failed;
    88  };
    89  
    90  /* Passed to backtrace_syminfo callback function.  */
    91  
    92  struct symdata
    93  {
    94    const char *name;
    95    uintptr_t val, size;
    96    int failed;
    97  };
    98  
    99  /* The backtrace state.  */
   100  
   101  static void *state;
   102  
   103  /* The number of failures.  */
   104  
   105  static int failures;
   106  
   107  /* Return the base name in a path.  */
   108  
   109  static const char *
   110  base (const char *p)
   111  {
   112    const char *last;
   113    const char *s;
   114  
   115    last = NULL;
   116    for (s = p; *s != '\0'; ++s)
   117      {
   118        if (IS_DIR_SEPARATOR (*s))
   119  	last = s + 1;
   120      }
   121    return last != NULL ? last : p;
   122  }
   123  
   124  /* Check an entry in a struct info array.  */
   125  
   126  static void
   127  check (const char *name, int index, const struct info *all, int want_lineno,
   128         const char *want_function, int *failed)
   129  {
   130    if (*failed)
   131      return;
   132    if (all[index].filename == NULL || all[index].function == NULL)
   133      {
   134        fprintf (stderr, "%s: [%d]: missing file name or function name\n",
   135  	       name, index);
   136        *failed = 1;
   137        return;
   138      }
   139    if (strcmp (base (all[index].filename), "btest.c") != 0)
   140      {
   141        fprintf (stderr, "%s: [%d]: got %s expected test.c\n", name, index,
   142  	       all[index].filename);
   143        *failed = 1;
   144      }
   145    if (all[index].lineno != want_lineno)
   146      {
   147        fprintf (stderr, "%s: [%d]: got %d expected %d\n", name, index,
   148  	       all[index].lineno, want_lineno);
   149        *failed = 1;
   150      }
   151    if (strcmp (all[index].function, want_function) != 0)
   152      {
   153        fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index,
   154  	       all[index].function, want_function);
   155        *failed = 1;
   156      }
   157  }
   158  
   159  /* The backtrace callback function.  */
   160  
   161  static int
   162  callback_one (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
   163  	      const char *filename, int lineno, const char *function)
   164  {
   165    struct bdata *data = (struct bdata *) vdata;
   166    struct info *p;
   167  
   168    if (data->index >= data->max)
   169      {
   170        fprintf (stderr, "callback_one: callback called too many times\n");
   171        data->failed = 1;
   172        return 1;
   173      }
   174  
   175    p = &data->all[data->index];
   176    if (filename == NULL)
   177      p->filename = NULL;
   178    else
   179      {
   180        p->filename = strdup (filename);
   181        assert (p->filename != NULL);
   182      }
   183    p->lineno = lineno;
   184    if (function == NULL)
   185      p->function = NULL;
   186    else
   187      {
   188        p->function = strdup (function);
   189        assert (p->function != NULL);
   190      }
   191    ++data->index;
   192  
   193    return 0;
   194  }
   195  
   196  /* An error callback passed to backtrace.  */
   197  
   198  static void
   199  error_callback_one (void *vdata, const char *msg, int errnum)
   200  {
   201    struct bdata *data = (struct bdata *) vdata;
   202  
   203    fprintf (stderr, "%s", msg);
   204    if (errnum > 0)
   205      fprintf (stderr, ": %s", strerror (errnum));
   206    fprintf (stderr, "\n");
   207    data->failed = 1;
   208  }
   209  
   210  /* The backtrace_simple callback function.  */
   211  
   212  static int
   213  callback_two (void *vdata, uintptr_t pc)
   214  {
   215    struct sdata *data = (struct sdata *) vdata;
   216  
   217    if (data->index >= data->max)
   218      {
   219        fprintf (stderr, "callback_two: callback called too many times\n");
   220        data->failed = 1;
   221        return 1;
   222      }
   223  
   224    data->addrs[data->index] = pc;
   225    ++data->index;
   226  
   227    return 0;
   228  }
   229  
   230  /* An error callback passed to backtrace_simple.  */
   231  
   232  static void
   233  error_callback_two (void *vdata, const char *msg, int errnum)
   234  {
   235    struct sdata *data = (struct sdata *) vdata;
   236  
   237    fprintf (stderr, "%s", msg);
   238    if (errnum > 0)
   239      fprintf (stderr, ": %s", strerror (errnum));
   240    fprintf (stderr, "\n");
   241    data->failed = 1;
   242  }
   243  
   244  /* The backtrace_syminfo callback function.  */
   245  
   246  static void
   247  callback_three (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
   248  		const char *symname, uintptr_t symval,
   249  		uintptr_t symsize)
   250  {
   251    struct symdata *data = (struct symdata *) vdata;
   252  
   253    if (symname == NULL)
   254      data->name = NULL;
   255    else
   256      {
   257        data->name = strdup (symname);
   258        assert (data->name != NULL);
   259      }
   260    data->val = symval;
   261    data->size = symsize;
   262  }
   263  
   264  /* The backtrace_syminfo error callback function.  */
   265  
   266  static void
   267  error_callback_three (void *vdata, const char *msg, int errnum)
   268  {
   269    struct symdata *data = (struct symdata *) vdata;
   270  
   271    fprintf (stderr, "%s", msg);
   272    if (errnum > 0)
   273      fprintf (stderr, ": %s", strerror (errnum));
   274    fprintf (stderr, "\n");
   275    data->failed = 1;
   276  }
   277  
   278  /* Test the backtrace function with non-inlined functions.  */
   279  
   280  static int test1 (void) __attribute__ ((noinline, unused));
   281  static int f2 (int) __attribute__ ((noinline));
   282  static int f3 (int, int) __attribute__ ((noinline));
   283  
   284  static int
   285  test1 (void)
   286  {
   287    /* Returning a value here and elsewhere avoids a tailcall which
   288       would mess up the backtrace.  */
   289    return f2 (__LINE__) + 1;
   290  }
   291  
   292  static int
   293  f2 (int f1line)
   294  {
   295    return f3 (f1line, __LINE__) + 2;
   296  }
   297  
   298  static int
   299  f3 (int f1line, int f2line)
   300  {
   301    struct info all[20];
   302    struct bdata data;
   303    int f3line;
   304    int i;
   305  
   306    data.all = &all[0];
   307    data.index = 0;
   308    data.max = 20;
   309    data.failed = 0;
   310  
   311    f3line = __LINE__ + 1;
   312    i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
   313  
   314    if (i != 0)
   315      {
   316        fprintf (stderr, "test1: unexpected return value %d\n", i);
   317        data.failed = 1;
   318      }
   319  
   320    if (data.index < 3)
   321      {
   322        fprintf (stderr,
   323  	       "test1: not enough frames; got %zu, expected at least 3\n",
   324  	       data.index);
   325        data.failed = 1;
   326      }
   327  
   328    check ("test1", 0, all, f3line, "f3", &data.failed);
   329    check ("test1", 1, all, f2line, "f2", &data.failed);
   330    check ("test1", 2, all, f1line, "test1", &data.failed);
   331  
   332    printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
   333  
   334    if (data.failed)
   335      ++failures;
   336  
   337    return failures;
   338  }
   339  
   340  /* Test the backtrace function with inlined functions.  */
   341  
   342  static inline int test2 (void) __attribute__ ((always_inline, unused));
   343  static inline int f12 (int) __attribute__ ((always_inline));
   344  static inline int f13 (int, int) __attribute__ ((always_inline));
   345  
   346  static inline int
   347  test2 (void)
   348  {
   349    return f12 (__LINE__) + 1;
   350  }
   351  
   352  static inline int
   353  f12 (int f1line)
   354  {
   355    return f13 (f1line, __LINE__) + 2;
   356  }
   357  
   358  static inline int
   359  f13 (int f1line, int f2line)
   360  {
   361    struct info all[20];
   362    struct bdata data;
   363    int f3line;
   364    int i;
   365  
   366    data.all = &all[0];
   367    data.index = 0;
   368    data.max = 20;
   369    data.failed = 0;
   370  
   371    f3line = __LINE__ + 1;
   372    i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
   373  
   374    if (i != 0)
   375      {
   376        fprintf (stderr, "test2: unexpected return value %d\n", i);
   377        data.failed = 1;
   378      }
   379  
   380    check ("test2", 0, all, f3line, "f13", &data.failed);
   381    check ("test2", 1, all, f2line, "f12", &data.failed);
   382    check ("test2", 2, all, f1line, "test2", &data.failed);
   383  
   384    printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS");
   385  
   386    if (data.failed)
   387      ++failures;
   388  
   389    return failures;
   390  }
   391  
   392  /* Test the backtrace_simple function with non-inlined functions.  */
   393  
   394  static int test3 (void) __attribute__ ((noinline, unused));
   395  static int f22 (int) __attribute__ ((noinline));
   396  static int f23 (int, int) __attribute__ ((noinline));
   397  
   398  static int
   399  test3 (void)
   400  {
   401    return f22 (__LINE__) + 1;
   402  }
   403  
   404  static int
   405  f22 (int f1line)
   406  {
   407    return f23 (f1line, __LINE__) + 2;
   408  }
   409  
   410  static int
   411  f23 (int f1line, int f2line)
   412  {
   413    uintptr_t addrs[20];
   414    struct sdata data;
   415    int f3line;
   416    int i;
   417  
   418    data.addrs = &addrs[0];
   419    data.index = 0;
   420    data.max = 20;
   421    data.failed = 0;
   422  
   423    f3line = __LINE__ + 1;
   424    i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
   425  
   426    if (i != 0)
   427      {
   428        fprintf (stderr, "test3: unexpected return value %d\n", i);
   429        data.failed = 1;
   430      }
   431  
   432    if (!data.failed)
   433      {
   434        struct info all[20];
   435        struct bdata bdata;
   436        int j;
   437  
   438        bdata.all = &all[0];
   439        bdata.index = 0;
   440        bdata.max = 20;
   441        bdata.failed = 0;
   442  
   443        for (j = 0; j < 3; ++j)
   444  	{
   445  	  i = backtrace_pcinfo (state, addrs[j], callback_one,
   446  				error_callback_one, &bdata);
   447  	  if (i != 0)
   448  	    {
   449  	      fprintf (stderr,
   450  		       ("test3: unexpected return value "
   451  			"from backtrace_pcinfo %d\n"),
   452  		       i);
   453  	      bdata.failed = 1;
   454  	    }
   455  	  if (!bdata.failed && bdata.index != (size_t) (j + 1))
   456  	    {
   457  	      fprintf (stderr,
   458  		       ("wrong number of calls from backtrace_pcinfo "
   459  			"got %u expected %d\n"),
   460  		       (unsigned int) bdata.index, j + 1);
   461  	      bdata.failed = 1;
   462  	    }
   463  	}      
   464  
   465        check ("test3", 0, all, f3line, "f23", &bdata.failed);
   466        check ("test3", 1, all, f2line, "f22", &bdata.failed);
   467        check ("test3", 2, all, f1line, "test3", &bdata.failed);
   468  
   469        if (bdata.failed)
   470  	data.failed = 1;
   471  
   472        for (j = 0; j < 3; ++j)
   473  	{
   474  	  struct symdata symdata;
   475  
   476  	  symdata.name = NULL;
   477  	  symdata.val = 0;
   478  	  symdata.size = 0;
   479  	  symdata.failed = 0;
   480  
   481  	  i = backtrace_syminfo (state, addrs[j], callback_three,
   482  				 error_callback_three, &symdata);
   483  	  if (i == 0)
   484  	    {
   485  	      fprintf (stderr,
   486  		       ("test3: [%d]: unexpected return value "
   487  			"from backtrace_syminfo %d\n"),
   488  		       j, i);
   489  	      symdata.failed = 1;
   490  	    }
   491  
   492  	  if (!symdata.failed)
   493  	    {
   494  	      const char *expected;
   495  
   496  	      switch (j)
   497  		{
   498  		case 0:
   499  		  expected = "f23";
   500  		  break;
   501  		case 1:
   502  		  expected = "f22";
   503  		  break;
   504  		case 2:
   505  		  expected = "test3";
   506  		  break;
   507  		default:
   508  		  assert (0);
   509  		}
   510  
   511  	      if (symdata.name == NULL)
   512  		{
   513  		  fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j);
   514  		  symdata.failed = 1;
   515  		}
   516  	      /* Use strncmp, not strcmp, because GCC might create a
   517  		 clone.  */
   518  	      else if (strncmp (symdata.name, expected, strlen (expected))
   519  		       != 0)
   520  		{
   521  		  fprintf (stderr,
   522  			   ("test3: [%d]: unexpected syminfo name "
   523  			    "got %s expected %s\n"),
   524  			   j, symdata.name, expected);
   525  		  symdata.failed = 1;
   526  		}
   527  	    }
   528  
   529  	  if (symdata.failed)
   530  	    data.failed = 1;
   531  	}
   532      }
   533  
   534    printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS");
   535  
   536    if (data.failed)
   537      ++failures;
   538  
   539    return failures;
   540  }
   541  
   542  /* Test the backtrace_simple function with inlined functions.  */
   543  
   544  static inline int test4 (void) __attribute__ ((always_inline, unused));
   545  static inline int f32 (int) __attribute__ ((always_inline));
   546  static inline int f33 (int, int) __attribute__ ((always_inline));
   547  
   548  static inline int
   549  test4 (void)
   550  {
   551    return f32 (__LINE__) + 1;
   552  }
   553  
   554  static inline int
   555  f32 (int f1line)
   556  {
   557    return f33 (f1line, __LINE__) + 2;
   558  }
   559  
   560  static inline int
   561  f33 (int f1line, int f2line)
   562  {
   563    uintptr_t addrs[20];
   564    struct sdata data;
   565    int f3line;
   566    int i;
   567  
   568    data.addrs = &addrs[0];
   569    data.index = 0;
   570    data.max = 20;
   571    data.failed = 0;
   572  
   573    f3line = __LINE__ + 1;
   574    i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
   575  
   576    if (i != 0)
   577      {
   578        fprintf (stderr, "test3: unexpected return value %d\n", i);
   579        data.failed = 1;
   580      }
   581  
   582    if (!data.failed)
   583      {
   584        struct info all[20];
   585        struct bdata bdata;
   586  
   587        bdata.all = &all[0];
   588        bdata.index = 0;
   589        bdata.max = 20;
   590        bdata.failed = 0;
   591  
   592        i = backtrace_pcinfo (state, addrs[0], callback_one, error_callback_one,
   593  			    &bdata);
   594        if (i != 0)
   595  	{
   596  	  fprintf (stderr,
   597  		   ("test4: unexpected return value "
   598  		    "from backtrace_pcinfo %d\n"),
   599  		   i);
   600  	  bdata.failed = 1;
   601  	}
   602  
   603        check ("test4", 0, all, f3line, "f33", &bdata.failed);
   604        check ("test4", 1, all, f2line, "f32", &bdata.failed);
   605        check ("test4", 2, all, f1line, "test4", &bdata.failed);
   606  
   607        if (bdata.failed)
   608  	data.failed = 1;
   609      }
   610  
   611    printf ("%s: backtrace_simple inline\n", data.failed ? "FAIL" : "PASS");
   612  
   613    if (data.failed)
   614      ++failures;
   615  
   616    return failures;
   617  }
   618  
   619  int global = 1;
   620  
   621  static int
   622  test5 (void)
   623  {
   624    struct symdata symdata;
   625    int i;
   626    uintptr_t addr = (uintptr_t) &global;
   627  
   628    if (sizeof (global) > 1)
   629      addr += 1;
   630  
   631    symdata.name = NULL;
   632    symdata.val = 0;
   633    symdata.size = 0;
   634    symdata.failed = 0;
   635  
   636    i = backtrace_syminfo (state, addr, callback_three,
   637  			 error_callback_three, &symdata);
   638    if (i == 0)
   639      {
   640        fprintf (stderr,
   641  	       "test5: unexpected return value from backtrace_syminfo %d\n",
   642  	       i);
   643        symdata.failed = 1;
   644      }
   645  
   646    if (!symdata.failed)
   647      {
   648        if (symdata.name == NULL)
   649  	{
   650  	  fprintf (stderr, "test5: NULL syminfo name\n");
   651  	  symdata.failed = 1;
   652  	}
   653        else if (strcmp (symdata.name, "global") != 0)
   654  	{
   655  	  fprintf (stderr,
   656  		   "test5: unexpected syminfo name got %s expected %s\n",
   657  		   symdata.name, "global");
   658  	  symdata.failed = 1;
   659  	}
   660        else if (symdata.val != (uintptr_t) &global)
   661  	{
   662  	  fprintf (stderr,
   663  		   "test5: unexpected syminfo value got %lx expected %lx\n",
   664  		   (unsigned long) symdata.val,
   665  		   (unsigned long) (uintptr_t) &global);
   666  	  symdata.failed = 1;
   667  	}
   668        else if (symdata.size != sizeof (global))
   669  	{
   670  	  fprintf (stderr,
   671  		   "test5: unexpected syminfo size got %lx expected %lx\n",
   672  		   (unsigned long) symdata.size,
   673  		   (unsigned long) sizeof (global));
   674  	  symdata.failed = 1;
   675  	}
   676      }
   677  
   678    printf ("%s: backtrace_syminfo variable\n",
   679  	  symdata.failed ? "FAIL" : "PASS");
   680  
   681    if (symdata.failed)
   682      ++failures;
   683  
   684    return failures;
   685  }
   686  
   687  static void
   688  error_callback_create (void *data ATTRIBUTE_UNUSED, const char *msg,
   689  		       int errnum)
   690  {
   691    fprintf (stderr, "%s", msg);
   692    if (errnum > 0)
   693      fprintf (stderr, ": %s", strerror (errnum));
   694    fprintf (stderr, "\n");
   695    exit (EXIT_FAILURE);
   696  }
   697  
   698  /* Run all the tests.  */
   699  
   700  int
   701  main (int argc ATTRIBUTE_UNUSED, char **argv)
   702  {
   703    state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
   704  				  error_callback_create, NULL);
   705  
   706  #if BACKTRACE_SUPPORTED
   707    test1 ();
   708    test2 ();
   709    test3 ();
   710    test4 ();
   711    test5 ();
   712  #endif
   713  
   714    exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
   715  }