1c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov/*
2c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * Copyright (C) 2013 The Android Open Source Project
3c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov *
4c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * Licensed under the Apache License, Version 2.0 (the "License");
5c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * you may not use this file except in compliance with the License.
6c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * You may obtain a copy of the License at
7c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov *
8c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov *      http://www.apache.org/licenses/LICENSE-2.0
9c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov *
10c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * Unless required by applicable law or agreed to in writing, software
11c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * distributed under the License is distributed on an "AS IS" BASIS,
12c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * See the License for the specific language governing permissions and
14c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * limitations under the License.
15c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov */
16c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
17c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov/*
18c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * Contributed by: Intel Corporation
19c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov */
20c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
21c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov#include <stdio.h>
22c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov#include <signal.h>
23c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov#include <stdlib.h>
24c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov#include <string.h>
25c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov#include <unwind.h>
26c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
27c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov#define noinline __attribute__((__noinline__))
28c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov#define unused __attribute__((__unused__))
29c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
30c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikovstatic noinline _Unwind_Reason_Code stop_fn(int a unused,
31c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov    _Unwind_Action action,
32c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov    _Unwind_Exception_Class b unused, struct _Unwind_Exception* c unused,
33c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov    struct _Unwind_Context* d unused, void* e unused) {
34c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov  if ((action & _UA_END_OF_STACK) != 0) {
35c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov    // We reached the end of the stack without executing foo_cleanup. Test failed.
36c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov    abort();
37c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov  }
38c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov  return _URC_NO_REASON;
39c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov}
40c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
41c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikovstatic void noinline foo_cleanup(char* param unused) {
42c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov  exit(42);
43c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov}
44c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
45c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikovstatic void noinline do_crash() {
46c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov  char* ptr = NULL;
47c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov  *ptr = 0; // Deliberately cause a SIGSEGV.
48c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov}
49c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
50c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikovstatic void noinline foo() {
51c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov  char c1 __attribute__((cleanup(foo_cleanup)));
52c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov  do_crash();
53c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov}
54c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
55c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov// It's SEGSEGV handler. We start forced stack unwinding here.
56c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov// If libgcc don't find dso for signal frame stack unwinding will be finished.
57c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov// libgcc pass to stop_fn _UA_END_OF_STACK flag.
58c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov// Test pass condition: stack unwinding through signal frame and foo1_handler execution.
59c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikovstatic void noinline sigsegv_handler(int param unused) {
60c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov  struct _Unwind_Exception* exception = (struct _Unwind_Exception*) malloc(sizeof(*exception));
61c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov  memset(&exception->exception_class, 0, sizeof(exception->exception_class));
62c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov  exception->exception_cleanup = 0;
63c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov  _Unwind_ForcedUnwind(exception, stop_fn, 0);
64c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov}
65c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
66c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikovvoid do_test() {
67c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov  signal(SIGSEGV, &sigsegv_handler);
68c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov  foo();
69c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov}
70