1 | /* |
2 | * Copyright 2013-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | #include <folly/experimental/symbolizer/StackTrace.h> |
17 | |
18 | // Must be first to ensure that UNW_LOCAL_ONLY is defined |
19 | #define UNW_LOCAL_ONLY 1 |
20 | #include <libunwind.h> |
21 | |
22 | namespace folly { |
23 | namespace symbolizer { |
24 | |
25 | ssize_t getStackTrace(uintptr_t* addresses, size_t maxAddresses) { |
26 | static_assert( |
27 | sizeof(uintptr_t) == sizeof(void*), "uintptr_t / pointer size mismatch" ); |
28 | // The libunwind documentation says that unw_backtrace is async-signal-safe |
29 | // but, as of libunwind 1.0.1, it isn't (tdep_trace allocates memory on |
30 | // x86_64) |
31 | int r = unw_backtrace(reinterpret_cast<void**>(addresses), maxAddresses); |
32 | return r < 0 ? -1 : r; |
33 | } |
34 | |
35 | namespace { |
36 | inline bool getFrameInfo(unw_cursor_t* cursor, uintptr_t& ip) { |
37 | unw_word_t uip; |
38 | if (unw_get_reg(cursor, UNW_REG_IP, &uip) < 0) { |
39 | return false; |
40 | } |
41 | int r = unw_is_signal_frame(cursor); |
42 | if (r < 0) { |
43 | return false; |
44 | } |
45 | // Use previous instruction in normal (call) frames (because the |
46 | // return address might not be in the same function for noreturn functions) |
47 | // but not in signal frames. |
48 | ip = uip - (r == 0); |
49 | return true; |
50 | } |
51 | } // namespace |
52 | |
53 | ssize_t getStackTraceSafe(uintptr_t* addresses, size_t maxAddresses) { |
54 | if (maxAddresses == 0) { |
55 | return 0; |
56 | } |
57 | unw_context_t context; |
58 | if (unw_getcontext(&context) < 0) { |
59 | return -1; |
60 | } |
61 | unw_cursor_t cursor; |
62 | if (unw_init_local(&cursor, &context) < 0) { |
63 | return -1; |
64 | } |
65 | if (!getFrameInfo(&cursor, *addresses)) { |
66 | return -1; |
67 | } |
68 | ++addresses; |
69 | size_t count = 1; |
70 | for (; count != maxAddresses; ++count, ++addresses) { |
71 | int r = unw_step(&cursor); |
72 | if (r < 0) { |
73 | return -1; |
74 | } |
75 | if (r == 0) { |
76 | break; |
77 | } |
78 | if (!getFrameInfo(&cursor, *addresses)) { |
79 | return -1; |
80 | } |
81 | } |
82 | return count; |
83 | } |
84 | } // namespace symbolizer |
85 | } // namespace folly |
86 | |