//
//===----------------------------------------------------------------------===//
-#include "LLVMSymbolize.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/Symbolize/DIPrinter.h"
+#include "llvm/DebugInfo/Symbolize/Symbolize.h"
+#include "llvm/Support/COM.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
static cl::opt<bool>
ClUseSymbolTable("use-symbol-table", cl::init(true),
- cl::desc("Prefer names in symbol table to names "
- "in debug info"));
+ cl::desc("Prefer names in symbol table to names "
+ "in debug info"));
+
+static cl::opt<FunctionNameKind> ClPrintFunctions(
+ "functions", cl::init(FunctionNameKind::LinkageName),
+ cl::desc("Print function name for a given address:"),
+ cl::values(clEnumValN(FunctionNameKind::None, "none", "omit function name"),
+ clEnumValN(FunctionNameKind::ShortName, "short",
+ "print short function name"),
+ clEnumValN(FunctionNameKind::LinkageName, "linkage",
+ "print function linkage name"),
+ clEnumValEnd));
+
+static cl::opt<bool>
+ ClUseRelativeAddress("relative-address", cl::init(false),
+ cl::desc("Interpret addresses as relative addresses"),
+ cl::ReallyHidden);
static cl::opt<bool>
-ClPrintFunctions("functions", cl::init(true),
- cl::desc("Print function names as well as line "
- "information for a given address"));
+ ClPrintInlining("inlining", cl::init(true),
+ cl::desc("Print all inlined frames for a given address"));
static cl::opt<bool>
-ClPrintInlining("inlining", cl::init(true),
- cl::desc("Print all inlined frames for a given address"));
+ClDemangle("demangle", cl::init(true), cl::desc("Demangle function names"));
+
+static cl::opt<std::string> ClDefaultArch("default-arch", cl::init(""),
+ cl::desc("Default architecture "
+ "(for multi-arch objects)"));
+static cl::opt<std::string>
+ClBinaryName("obj", cl::init(""),
+ cl::desc("Path to object file to be symbolized (if not provided, "
+ "object file should be specified for each input line)"));
+
+static cl::list<std::string>
+ClDsymHint("dsym-hint", cl::ZeroOrMore,
+ cl::desc("Path to .dSYM bundles to search for debug info for the "
+ "object files"));
static cl::opt<bool>
-ClDemangle("demangle", cl::init(true),
- cl::desc("Demangle function names"));
+ ClPrintAddress("print-address", cl::init(false),
+ cl::desc("Show address before line information"));
+
+static bool error(std::error_code ec) {
+ if (!ec)
+ return false;
+ errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n";
+ return true;
+}
-static bool parseCommand(bool &IsData,
- std::string &ModuleName,
+static bool parseCommand(bool &IsData, std::string &ModuleName,
uint64_t &ModuleOffset) {
const char *kDataCmd = "DATA ";
const char *kCodeCmd = "CODE ";
return false;
IsData = false;
ModuleName = "";
- std::string ModuleOffsetStr = "";
char *pos = InputString;
if (strncmp(pos, kDataCmd, strlen(kDataCmd)) == 0) {
IsData = true;
// If no cmd, assume it's CODE.
IsData = false;
}
- // FIXME: Handle case when filename is given in quotes.
- if (char *FilePath = strtok(pos, kDelimiters)) {
- ModuleName = FilePath;
- if (char *OffsetStr = strtok((char*)0, kDelimiters))
- ModuleOffsetStr = OffsetStr;
+ // Skip delimiters and parse input filename (if needed).
+ if (ClBinaryName == "") {
+ pos += strspn(pos, kDelimiters);
+ if (*pos == '"' || *pos == '\'') {
+ char quote = *pos;
+ pos++;
+ char *end = strchr(pos, quote);
+ if (!end)
+ return false;
+ ModuleName = std::string(pos, end - pos);
+ pos = end + 1;
+ } else {
+ int name_length = strcspn(pos, kDelimiters);
+ ModuleName = std::string(pos, name_length);
+ pos += name_length;
+ }
+ } else {
+ ModuleName = ClBinaryName;
}
- if (StringRef(ModuleOffsetStr).getAsInteger(0, ModuleOffset))
- return false;
- return true;
+ // Skip delimiters and parse module offset.
+ pos += strspn(pos, kDelimiters);
+ int offset_length = strcspn(pos, kDelimiters);
+ return !StringRef(pos, offset_length).getAsInteger(0, ModuleOffset);
}
int main(int argc, char **argv) {
// Print stack trace if we signal out.
sys::PrintStackTraceOnErrorSignal();
PrettyStackTraceProgram X(argc, argv);
- llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
- cl::ParseCommandLineOptions(argc, argv, "llvm symbolizer for compiler-rt\n");
- LLVMSymbolizer::Options Opts(ClUseSymbolTable, ClPrintFunctions,
- ClPrintInlining, ClDemangle);
+ llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
+
+ cl::ParseCommandLineOptions(argc, argv, "llvm-symbolizer\n");
+ LLVMSymbolizer::Options Opts(ClPrintFunctions, ClUseSymbolTable, ClDemangle,
+ ClUseRelativeAddress, ClDefaultArch);
+ for (const auto &hint : ClDsymHint) {
+ if (sys::path::extension(hint) == ".dSYM") {
+ Opts.DsymHints.push_back(hint);
+ } else {
+ errs() << "Warning: invalid dSYM hint: \"" << hint <<
+ "\" (must have the '.dSYM' extension).\n";
+ }
+ }
LLVMSymbolizer Symbolizer(Opts);
bool IsData = false;
std::string ModuleName;
uint64_t ModuleOffset;
+ DIPrinter Printer(outs(), ClPrintFunctions != FunctionNameKind::None);
+
while (parseCommand(IsData, ModuleName, ModuleOffset)) {
- std::string Result =
- IsData ? Symbolizer.symbolizeData(ModuleName, ModuleOffset)
- : Symbolizer.symbolizeCode(ModuleName, ModuleOffset);
- outs() << Result << "\n";
+ if (ClPrintAddress) {
+ outs() << "0x";
+ outs().write_hex(ModuleOffset);
+ outs() << "\n";
+ }
+ if (IsData) {
+ auto ResOrErr = Symbolizer.symbolizeData(ModuleName, ModuleOffset);
+ Printer << (error(ResOrErr.getError()) ? DIGlobal() : ResOrErr.get());
+ } else if (ClPrintInlining) {
+ auto ResOrErr = Symbolizer.symbolizeInlinedCode(ModuleName, ModuleOffset);
+ Printer << (error(ResOrErr.getError()) ? DIInliningInfo()
+ : ResOrErr.get());
+ } else {
+ auto ResOrErr = Symbolizer.symbolizeCode(ModuleName, ModuleOffset);
+ Printer << (error(ResOrErr.getError()) ? DILineInfo() : ResOrErr.get());
+ }
+ outs() << "\n";
outs().flush();
}
+
return 0;
}