1/* libunwind - a platform-independent unwind library
2   Copyright (C) 2003-2004 Hewlett-Packard Co
3	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4
5This file is part of libunwind.
6
7Copyright (c) 2003 Hewlett-Packard Co.
8
9Permission is hereby granted, free of charge, to any person obtaining
10a copy of this software and associated documentation files (the
11"Software"), to deal in the Software without restriction, including
12without limitation the rights to use, copy, modify, merge, publish,
13distribute, sublicense, and/or sell copies of the Software, and to
14permit persons to whom the Software is furnished to do so, subject to
15the following conditions:
16
17The above copyright notice and this permission notice shall be
18included in all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
27
28#include "compiler.h"
29
30#include <libunwind.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <unistd.h>
35
36#include <sys/resource.h>
37#include <sys/mman.h>
38#include <sys/types.h>
39#include <sys/wait.h>
40
41#define panic(args...)				\
42	{ fprintf (stderr, args); exit (-1); }
43
44void * stack_start;
45
46#define PAGE_SIZE 4096
47
48void do_backtrace (void)
49{
50  /*
51    We make the assumption that we are able to rewind far enough
52    (steps > 5) before touching the forbidden region in the stack,
53    at which point the unwinding should stop gracefully.
54  */
55  mprotect((void*)((uintptr_t)stack_start & ~(PAGE_SIZE - 1)),
56           PAGE_SIZE, PROT_NONE);
57
58  unw_cursor_t cursor;
59  unw_word_t ip, sp;
60  unw_context_t uc;
61  int ret;
62  int steps = 0;
63
64  unw_getcontext (&uc);
65  if (unw_init_local (&cursor, &uc) < 0)
66    panic ("unw_init_local failed!\n");
67
68  do
69    {
70      unw_get_reg (&cursor, UNW_REG_IP, &ip);
71      unw_get_reg (&cursor, UNW_REG_SP, &sp);
72
73      ret = unw_step (&cursor);
74	  printf("ip=%lx, sp=%lx -> %d\n", ip, sp, ret);
75      if (ret < 0)
76	{
77	  unw_get_reg (&cursor, UNW_REG_IP, &ip);
78	}
79      steps ++;
80    }
81  while (ret > 0);
82
83  if (steps < 5)
84    {
85      printf("not enough steps: %d, need 5\n", steps);
86      exit(-1);
87    }
88  printf("success, steps: %d\n", steps);
89
90  mprotect((void*)((uintptr_t)stack_start & ~(PAGE_SIZE - 1)),
91           PAGE_SIZE, PROT_READ|PROT_WRITE);
92}
93
94void NOINLINE consume_and_run (int depth)
95{
96  unw_cursor_t cursor;
97  unw_context_t uc;
98  char string[1024];
99
100  sprintf (string, "hello %p %p\n", &cursor, &uc);
101  if (depth == 0) {
102    do_backtrace();
103  } else {
104    consume_and_run(depth - 1);
105  }
106}
107
108int
109main (int argc, char **argv UNUSED)
110{
111  int start;
112  unw_context_t uc;
113  unw_cursor_t cursor;
114
115  stack_start = &start;
116
117  /*
118    We need to make the frame at least the size protected by
119    the mprotect call so we are not forbidding access to
120    unrelated regions.
121  */
122  char string[PAGE_SIZE];
123  sprintf (string, "hello\n");
124
125  // Initialize pipe mem validate check, opens file descriptors
126  unw_getcontext(&uc);
127  if (unw_init_local (&cursor, &uc) < 0)
128    panic ("unw_init_local failed!\n");
129
130  int i;
131  for (i = 3; i < 10; i++)
132    {
133
134      pid_t childpid = fork();
135      if (!childpid)
136        {
137          /* Close fds and make sure we still work */
138          close(i);
139        }
140
141      int status;
142      if (childpid)
143        {
144          wait(&status);
145          if (WIFEXITED(status))
146              return WEXITSTATUS(status);
147          else
148            return -1;
149        }
150      else
151        {
152          consume_and_run (10);
153
154          return 0;
155        }
156    }
157
158  return 0;
159}
160