volatile override
[folly.git] / folly / experimental / symbolizer / StackTrace.cpp
index b6664bd87e4c151c1c96ca81e228686ae446d0d7..863ccf5edc03e06ec392c174864a52d46f383d72 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Facebook, Inc.
+ * Copyright 2014 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * limitations under the License.
  */
 
+#include <folly/experimental/symbolizer/StackTrace.h>
+
 // Must be first to ensure that UNW_LOCAL_ONLY is defined
 #define UNW_LOCAL_ONLY 1
 #include <libunwind.h>
 
-#include "folly/experimental/symbolizer/StackTrace.h"
-
 namespace folly { namespace symbolizer {
 
 ssize_t getStackTrace(uintptr_t* addresses, size_t maxAddresses) {
   static_assert(sizeof(uintptr_t) == sizeof(void*),
                 "uinptr_t / pointer size mismatch");
+  // The libunwind documentation says that unw_backtrace is async-signal-safe
+  // but, as of libunwind 1.0.1, it isn't (tdep_trace allocates memory on
+  // x86_64)
   int r = unw_backtrace(reinterpret_cast<void**>(addresses), maxAddresses);
   return r < 0 ? -1 : r;
 }
 
-}}  // namespaces
+namespace {
+inline bool getFrameInfo(unw_cursor_t* cursor, uintptr_t& ip) {
+  unw_word_t uip;
+  if (unw_get_reg(cursor, UNW_REG_IP, &uip) < 0) {
+    return false;
+  }
+  int r = unw_is_signal_frame(cursor);
+  if (r < 0) {
+    return false;
+  }
+  // Use previous instruction in normal (call) frames (because the
+  // return address might not be in the same function for noreturn functions)
+  // but not in signal frames.
+  ip = uip - (r == 0);
+  return true;
+}
+}  // namespace
 
+ssize_t getStackTraceSafe(uintptr_t* addresses, size_t maxAddresses) {
+  if (maxAddresses == 0) {
+    return 0;
+  }
+  unw_context_t context;
+  if (unw_getcontext(&context) < 0) {
+    return -1;
+  }
+  unw_cursor_t cursor;
+  if (unw_init_local(&cursor, &context) < 0) {
+    return -1;
+  }
+  if (!getFrameInfo(&cursor, *addresses)) {
+    return -1;
+  }
+  ++addresses;
+  ssize_t count = 1;
+  for (; count != maxAddresses; ++count, ++addresses) {
+    int r = unw_step(&cursor);
+    if (r < 0) {
+      return -1;
+    }
+    if (r == 0) {
+      break;
+    }
+    if (!getFrameInfo(&cursor, *addresses)) {
+      return -1;
+    }
+  }
+  return count;
+}
+
+}}  // namespaces