15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2005, Google Inc.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Redistribution and use in source and binary forms, with or without
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modification, are permitted provided that the following conditions are
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// met:
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Redistributions of source code must retain the above copyright
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice, this list of conditions and the following disclaimer.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Redistributions in binary form must reproduce the above
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// copyright notice, this list of conditions and the following disclaimer
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the documentation and/or other materials provided with the
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// distribution.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Neither the name of Google Inc. nor the names of its
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// contributors may be used to endorse or promote products derived from
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this software without specific prior written permission.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "config_for_unittests.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_EXECINFO_H
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <execinfo.h>
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/commandlineflags.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gperftools/stacktrace.h>
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Obtain a backtrace, verify that the expected callers are present in the
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// backtrace, and maybe print the backtrace to stdout.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The sequence of functions whose return addresses we expect to see in the
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// backtrace.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int BACKTRACE_STEPS = 6;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct AddressRange {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const void *start, *end;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Expected function [start,end] range.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AddressRange expected_range[BACKTRACE_STEPS];
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if __GNUC__
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Using GCC extension: address of a label can be taken with '&&label'.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Start should be a label somewhere before recursive call, end somewhere
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// after it.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange)           \
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {                                                                   \
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (prange)->start = &&start_label;                                     \
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (prange)->end = &&end_label;                                         \
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK_LT((prange)->start, (prange)->end);                            \
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } while (0)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This macro expands into "unmovable" code (opaque to GCC), and that
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// prevents GCC from moving a_label up or down in the code.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Without it, there is no code following the 'end' label, and GCC
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the recursive call.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define DECLARE_ADDRESS_LABEL(a_label)                                   \
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  a_label: do { __asm__ __volatile__(""); } while (0)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Gcc 4.4.0 may split function into multiple chunks, and the chunk
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// performing recursive call may end up later in the code then the return
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// instruction (this actually happens with FDO).
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Adjust function range from __builtin_return_address.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ADJUST_ADDRESS_RANGE_FROM_RA(prange)                             \
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {                                                                   \
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void *ra = __builtin_return_address(0);                              \
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK_LT((prange)->start, ra);                                       \
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ra > (prange)->end) {                                            \
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf("Adjusting range from %p..%p to %p..%p\n",                  \
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             (prange)->start, (prange)->end,                             \
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             (prange)->start, ra);                                       \
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (prange)->end = ra;                                                \
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }                                                                    \
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } while (0)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Assume the Check* functions below are not longer than 256 bytes.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange)           \
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {                                                                   \
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (prange)->start = reinterpret_cast<const void *>(&fn);               \
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (prange)->end = reinterpret_cast<const char *>(&fn) + 256;           \
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } while (0)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define DECLARE_ADDRESS_LABEL(a_label) do { } while (0)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) do { } while (0)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // __GNUC__
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//-----------------------------------------------------------------------//
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CheckRetAddrIsInFunction(void *ret_addr, const AddressRange &range)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_GE(ret_addr, range.start);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_LE(ret_addr, range.end);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//-----------------------------------------------------------------------//
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ATTRIBUTE_NOINLINE CheckStackTrace(int);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ATTRIBUTE_NOINLINE CheckStackTraceLeaf(void) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int STACK_LEN = 10;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *stack[STACK_LEN];
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int size;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DECLARE_ADDRESS_LABEL(start);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size = GetStackTrace(stack, STACK_LEN, 0);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printf("Obtained %d stack frames.\n", size);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_GE(size, 1);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_LE(size, STACK_LEN);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_EXECINFO_H
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char **strings = backtrace_symbols(stack, size);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf("Obtained %d stack frames.\n", size);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < size; i++)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf("%s %p\n", strings[i], stack[i]);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf("CheckStackTrace() addr: %p\n", &CheckStackTrace);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free(strings);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < BACKTRACE_STEPS; i++) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf("Backtrace %d: expected: %p..%p  actual: %p ... ",
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           i, expected_range[i].start, expected_range[i].end, stack[i]);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fflush(stdout);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CheckRetAddrIsInFunction(stack[i], expected_range[i]);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf("OK\n");
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DECLARE_ADDRESS_LABEL(end);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//-----------------------------------------------------------------------//
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Dummy functions to make the backtrace more interesting. */
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ATTRIBUTE_NOINLINE CheckStackTrace4(int i) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[2]);
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INIT_ADDRESS_RANGE(CheckStackTrace4, start, end, &expected_range[1]);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DECLARE_ADDRESS_LABEL(start);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int j = i; j >= 0; j--)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CheckStackTraceLeaf();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DECLARE_ADDRESS_LABEL(end);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ATTRIBUTE_NOINLINE CheckStackTrace3(int i) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[3]);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INIT_ADDRESS_RANGE(CheckStackTrace3, start, end, &expected_range[2]);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DECLARE_ADDRESS_LABEL(start);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int j = i; j >= 0; j--)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CheckStackTrace4(j);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DECLARE_ADDRESS_LABEL(end);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ATTRIBUTE_NOINLINE CheckStackTrace2(int i) {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[4]);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INIT_ADDRESS_RANGE(CheckStackTrace2, start, end, &expected_range[3]);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DECLARE_ADDRESS_LABEL(start);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int j = i; j >= 0; j--)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CheckStackTrace3(j);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DECLARE_ADDRESS_LABEL(end);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[5]);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INIT_ADDRESS_RANGE(CheckStackTrace1, start, end, &expected_range[4]);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DECLARE_ADDRESS_LABEL(start);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int j = i; j >= 0; j--)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CheckStackTrace2(j);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DECLARE_ADDRESS_LABEL(end);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ATTRIBUTE_NOINLINE CheckStackTrace(int i) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DECLARE_ADDRESS_LABEL(start);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int j = i; j >= 0; j--)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CheckStackTrace1(j);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DECLARE_ADDRESS_LABEL(end);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//-----------------------------------------------------------------------//
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int main(int argc, char ** argv) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckStackTrace(0);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printf("PASS\n");
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
195