/*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2016 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.
*/
-#ifndef FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_
-#define FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_
+#pragma once
+#include <array>
#include <cstdint>
+#include <memory>
#include <string>
-#include <unordered_map>
-#include "folly/FBString.h"
-#include "folly/Range.h"
-#include "folly/experimental/symbolizer/Elf.h"
-#include "folly/experimental/symbolizer/Dwarf.h"
-#include "folly/experimental/symbolizer/StackTrace.h"
+#include <folly/FBString.h>
+#include <folly/Range.h>
+#include <folly/String.h>
+#include <folly/io/IOBuf.h>
+#include <folly/experimental/symbolizer/Elf.h>
+#include <folly/experimental/symbolizer/ElfCache.h>
+#include <folly/experimental/symbolizer/Dwarf.h>
+#include <folly/experimental/symbolizer/StackTrace.h>
namespace folly {
namespace symbolizer {
+class Symbolizer;
+
/**
* Frame information: symbol name and location.
- *
- * Note that both name and location are references in the Symbolizer object,
- * which must outlive this SymbolizedFrame object.
*/
struct SymbolizedFrame {
- SymbolizedFrame() : found(false) { }
- bool isSignalFrame;
- bool found;
- StringPiece name;
+ SymbolizedFrame() { }
+
+ void set(const std::shared_ptr<ElfFile>& file,
+ uintptr_t address,
+ Dwarf::LocationInfoMode mode);
+
+ void clear() { *this = SymbolizedFrame(); }
+
+ bool found = false;
+ const char* name = nullptr;
Dwarf::LocationInfo location;
+
+ /**
+ * Demangle the name and return it. Not async-signal-safe; allocates memory.
+ */
+ fbstring demangledName() const {
+ return name ? demangle(name) : fbstring();
+ }
+
+ private:
+ std::shared_ptr<ElfFile> file_;
};
template <size_t N>
struct FrameArray {
- FrameArray() : frameCount(0) { }
+ FrameArray() { }
- size_t frameCount;
+ size_t frameCount = 0;
uintptr_t addresses[N];
SymbolizedFrame frames[N];
};
}
} // namespace detail
+// Always inline these functions; they don't do much, and unittests rely
+// on them never showing up in a stack trace.
+template <size_t N>
+FOLLY_ALWAYS_INLINE bool getStackTrace(FrameArray<N>& fa);
+
template <size_t N>
-bool getStackTrace(FrameArray<N>& fa) {
+inline bool getStackTrace(FrameArray<N>& fa) {
return detail::fixFrameArray(fa, getStackTrace(fa.addresses, N));
}
+template <size_t N>
+FOLLY_ALWAYS_INLINE bool getStackTraceSafe(FrameArray<N>& fa);
template <size_t N>
-bool getStackTraceSafe(FrameArray<N>& fa) {
+inline bool getStackTraceSafe(FrameArray<N>& fa) {
return detail::fixFrameArray(fa, getStackTraceSafe(fa.addresses, N));
}
class Symbolizer {
public:
- Symbolizer() : fileCount_(0) { }
+ static constexpr Dwarf::LocationInfoMode kDefaultLocationInfoMode =
+ Dwarf::LocationInfoMode::FAST;
+
+ explicit Symbolizer(Dwarf::LocationInfoMode mode = kDefaultLocationInfoMode)
+ : Symbolizer(nullptr, mode) {}
+
+ explicit Symbolizer(ElfCacheBase* cache,
+ Dwarf::LocationInfoMode mode = kDefaultLocationInfoMode);
/**
* Symbolize given addresses.
}
private:
- // We can't allocate memory, so we'll preallocate room.
- // "1023 shared libraries should be enough for everyone"
- static constexpr size_t kMaxFiles = 1024;
- size_t fileCount_;
- ElfFile files_[kMaxFiles];
+ ElfCacheBase* const cache_;
+ const Dwarf::LocationInfoMode mode_;
+};
+
+/**
+ * Format one address in the way it's usually printed by SymbolizePrinter.
+ * Async-signal-safe.
+ */
+class AddressFormatter {
+ public:
+ AddressFormatter();
+
+ /**
+ * Format the address. Returns an internal buffer.
+ */
+ StringPiece format(uintptr_t address);
+
+ private:
+ static constexpr char bufTemplate[] = " @ 0000000000000000";
+ char buf_[sizeof(bufTemplate)];
};
/**
const SymbolizedFrame* frames,
size_t frameCount);
+ /**
+ * Print a string, no endling newline.
+ */
+ void print(StringPiece sp) { doPrint(sp); }
+
/**
* Print multiple addresses on separate lines, skipping the first
* skip addresses.
// Colorize output only if output is printed to a TTY (ANSI escape code)
COLOR_IF_TTY = 1 << 3,
+
+ // Skip frame address information
+ NO_FRAME_ADDRESS = 1 << 4,
};
- enum Color { DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, WHITE, PURPLE };
+ // NOTE: enum values used as indexes in kColorMap.
+ enum Color { DEFAULT, RED, GREEN, YELLOW, BLUE, CYAN, WHITE, PURPLE, NUM };
void color(Color c);
protected:
private:
void printTerse(uintptr_t address, const SymbolizedFrame& frame);
virtual void doPrint(StringPiece sp) = 0;
+
+ static constexpr std::array<const char*, Color::NUM> kColorMap = {{
+ "\x1B[0m",
+ "\x1B[31m",
+ "\x1B[32m",
+ "\x1B[33m",
+ "\x1B[34m",
+ "\x1B[36m",
+ "\x1B[37m",
+ "\x1B[35m",
+ }};
};
/**
*/
class FDSymbolizePrinter : public SymbolizePrinter {
public:
- explicit FDSymbolizePrinter(int fd, int options=0);
+ explicit FDSymbolizePrinter(int fd, int options=0,
+ size_t bufferSize=0);
+ ~FDSymbolizePrinter();
+ void flush();
private:
void doPrint(StringPiece sp) override;
- int fd_;
+
+ const int fd_;
+ std::unique_ptr<IOBuf> buffer_;
};
/**
explicit FILESymbolizePrinter(FILE* file, int options=0);
private:
void doPrint(StringPiece sp) override;
- FILE* file_;
+ FILE* const file_ = nullptr;
};
/**
} // namespace symbolizer
} // namespace folly
-
-#endif /* FOLLY_EXPERIMENTAL_SYMBOLIZER_SYMBOLIZER_H_ */