StackTrace.cpp 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  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. // Must be first to ensure that UNW_LOCAL_ONLY is defined
  18. #define UNW_LOCAL_ONLY 1
  19. #include <libunwind.h>
  20. namespace folly {
  21. namespace symbolizer {
  22. ssize_t getStackTrace(uintptr_t* addresses, size_t maxAddresses) {
  23. static_assert(
  24. sizeof(uintptr_t) == sizeof(void*), "uintptr_t / pointer size mismatch");
  25. // The libunwind documentation says that unw_backtrace is async-signal-safe
  26. // but, as of libunwind 1.0.1, it isn't (tdep_trace allocates memory on
  27. // x86_64)
  28. int r = unw_backtrace(reinterpret_cast<void**>(addresses), maxAddresses);
  29. return r < 0 ? -1 : r;
  30. }
  31. namespace {
  32. inline bool getFrameInfo(unw_cursor_t* cursor, uintptr_t& ip) {
  33. unw_word_t uip;
  34. if (unw_get_reg(cursor, UNW_REG_IP, &uip) < 0) {
  35. return false;
  36. }
  37. int r = unw_is_signal_frame(cursor);
  38. if (r < 0) {
  39. return false;
  40. }
  41. // Use previous instruction in normal (call) frames (because the
  42. // return address might not be in the same function for noreturn functions)
  43. // but not in signal frames.
  44. ip = uip - (r == 0);
  45. return true;
  46. }
  47. } // namespace
  48. ssize_t getStackTraceSafe(uintptr_t* addresses, size_t maxAddresses) {
  49. if (maxAddresses == 0) {
  50. return 0;
  51. }
  52. unw_context_t context;
  53. if (unw_getcontext(&context) < 0) {
  54. return -1;
  55. }
  56. unw_cursor_t cursor;
  57. if (unw_init_local(&cursor, &context) < 0) {
  58. return -1;
  59. }
  60. if (!getFrameInfo(&cursor, *addresses)) {
  61. return -1;
  62. }
  63. ++addresses;
  64. size_t count = 1;
  65. for (; count != maxAddresses; ++count, ++addresses) {
  66. int r = unw_step(&cursor);
  67. if (r < 0) {
  68. return -1;
  69. }
  70. if (r == 0) {
  71. break;
  72. }
  73. if (!getFrameInfo(&cursor, *addresses)) {
  74. return -1;
  75. }
  76. }
  77. return count;
  78. }
  79. } // namespace symbolizer
  80. } // namespace folly