Home | History | Annotate | Download | only in tests
      1 // Copyright (c) 2005, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 #include "config_for_unittests.h"
     31 #ifdef HAVE_EXECINFO_H
     32 #include <execinfo.h>
     33 #endif
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include "base/commandlineflags.h"
     37 #include "base/logging.h"
     38 #include <gperftools/stacktrace.h>
     39 
     40 namespace {
     41 
     42 // Obtain a backtrace, verify that the expected callers are present in the
     43 // backtrace, and maybe print the backtrace to stdout.
     44 
     45 // The sequence of functions whose return addresses we expect to see in the
     46 // backtrace.
     47 const int BACKTRACE_STEPS = 6;
     48 
     49 struct AddressRange {
     50   const void *start, *end;
     51 };
     52 
     53 // Expected function [start,end] range.
     54 AddressRange expected_range[BACKTRACE_STEPS];
     55 
     56 #if __GNUC__
     57 // Using GCC extension: address of a label can be taken with '&&label'.
     58 // Start should be a label somewhere before recursive call, end somewhere
     59 // after it.
     60 #define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange)           \
     61   do {                                                                   \
     62     (prange)->start = &&start_label;                                     \
     63     (prange)->end = &&end_label;                                         \
     64     CHECK_LT((prange)->start, (prange)->end);                            \
     65   } while (0)
     66 // This macro expands into "unmovable" code (opaque to GCC), and that
     67 // prevents GCC from moving a_label up or down in the code.
     68 // Without it, there is no code following the 'end' label, and GCC
     69 // (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before
     70 // the recursive call.
     71 #define DECLARE_ADDRESS_LABEL(a_label)                                   \
     72   a_label: do { __asm__ __volatile__(""); } while (0)
     73 // Gcc 4.4.0 may split function into multiple chunks, and the chunk
     74 // performing recursive call may end up later in the code then the return
     75 // instruction (this actually happens with FDO).
     76 // Adjust function range from __builtin_return_address.
     77 #define ADJUST_ADDRESS_RANGE_FROM_RA(prange)                             \
     78   do {                                                                   \
     79     void *ra = __builtin_return_address(0);                              \
     80     CHECK_LT((prange)->start, ra);                                       \
     81     if (ra > (prange)->end) {                                            \
     82       printf("Adjusting range from %p..%p to %p..%p\n",                  \
     83              (prange)->start, (prange)->end,                             \
     84              (prange)->start, ra);                                       \
     85       (prange)->end = ra;                                                \
     86     }                                                                    \
     87   } while (0)
     88 #else
     89 // Assume the Check* functions below are not longer than 256 bytes.
     90 #define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange)           \
     91   do {                                                                   \
     92     (prange)->start = reinterpret_cast<const void *>(&fn);               \
     93     (prange)->end = reinterpret_cast<const char *>(&fn) + 256;           \
     94   } while (0)
     95 #define DECLARE_ADDRESS_LABEL(a_label) do { } while (0)
     96 #define ADJUST_ADDRESS_RANGE_FROM_RA(prange) do { } while (0)
     97 #endif  // __GNUC__
     98 
     99 //-----------------------------------------------------------------------//
    100 
    101 void CheckRetAddrIsInFunction(void *ret_addr, const AddressRange &range)
    102 {
    103   CHECK_GE(ret_addr, range.start);
    104   CHECK_LE(ret_addr, range.end);
    105 }
    106 
    107 //-----------------------------------------------------------------------//
    108 
    109 void ATTRIBUTE_NOINLINE CheckStackTrace(int);
    110 void ATTRIBUTE_NOINLINE CheckStackTraceLeaf(void) {
    111   const int STACK_LEN = 10;
    112   void *stack[STACK_LEN];
    113   int size;
    114 
    115   ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]);
    116   INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
    117   DECLARE_ADDRESS_LABEL(start);
    118   size = GetStackTrace(stack, STACK_LEN, 0);
    119   printf("Obtained %d stack frames.\n", size);
    120   CHECK_GE(size, 1);
    121   CHECK_LE(size, STACK_LEN);
    122 
    123 #ifdef HAVE_EXECINFO_H
    124   {
    125     char **strings = backtrace_symbols(stack, size);
    126     printf("Obtained %d stack frames.\n", size);
    127     for (int i = 0; i < size; i++)
    128       printf("%s %p\n", strings[i], stack[i]);
    129     printf("CheckStackTrace() addr: %p\n", &CheckStackTrace);
    130     free(strings);
    131   }
    132 #endif
    133 
    134   for (int i = 0; i < BACKTRACE_STEPS; i++) {
    135     printf("Backtrace %d: expected: %p..%p  actual: %p ... ",
    136            i, expected_range[i].start, expected_range[i].end, stack[i]);
    137     fflush(stdout);
    138     CheckRetAddrIsInFunction(stack[i], expected_range[i]);
    139     printf("OK\n");
    140   }
    141   DECLARE_ADDRESS_LABEL(end);
    142 }
    143 
    144 //-----------------------------------------------------------------------//
    145 
    146 /* Dummy functions to make the backtrace more interesting. */
    147 void ATTRIBUTE_NOINLINE CheckStackTrace4(int i) {
    148   ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[2]);
    149   INIT_ADDRESS_RANGE(CheckStackTrace4, start, end, &expected_range[1]);
    150   DECLARE_ADDRESS_LABEL(start);
    151   for (int j = i; j >= 0; j--)
    152     CheckStackTraceLeaf();
    153   DECLARE_ADDRESS_LABEL(end);
    154 }
    155 void ATTRIBUTE_NOINLINE CheckStackTrace3(int i) {
    156   ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[3]);
    157   INIT_ADDRESS_RANGE(CheckStackTrace3, start, end, &expected_range[2]);
    158   DECLARE_ADDRESS_LABEL(start);
    159   for (int j = i; j >= 0; j--)
    160     CheckStackTrace4(j);
    161   DECLARE_ADDRESS_LABEL(end);
    162 }
    163 void ATTRIBUTE_NOINLINE CheckStackTrace2(int i) {
    164   ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[4]);
    165   INIT_ADDRESS_RANGE(CheckStackTrace2, start, end, &expected_range[3]);
    166   DECLARE_ADDRESS_LABEL(start);
    167   for (int j = i; j >= 0; j--)
    168     CheckStackTrace3(j);
    169   DECLARE_ADDRESS_LABEL(end);
    170 }
    171 void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
    172   ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[5]);
    173   INIT_ADDRESS_RANGE(CheckStackTrace1, start, end, &expected_range[4]);
    174   DECLARE_ADDRESS_LABEL(start);
    175   for (int j = i; j >= 0; j--)
    176     CheckStackTrace2(j);
    177   DECLARE_ADDRESS_LABEL(end);
    178 }
    179 void ATTRIBUTE_NOINLINE CheckStackTrace(int i) {
    180   INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
    181   DECLARE_ADDRESS_LABEL(start);
    182   for (int j = i; j >= 0; j--)
    183     CheckStackTrace1(j);
    184   DECLARE_ADDRESS_LABEL(end);
    185 }
    186 
    187 }  // namespace
    188 //-----------------------------------------------------------------------//
    189 
    190 int main(int argc, char ** argv) {
    191   CheckStackTrace(0);
    192   printf("PASS\n");
    193   return 0;
    194 }
    195