1 //===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer ------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This utility works much like "addr2line". It is able of transforming 10 // tuples (module name, module offset) to code locations (function name, 11 // file, line number, column number). It is targeted for compiler-rt tools 12 // (especially AddressSanitizer and ThreadSanitizer) that can use it 13 // to symbolize stack traces in their error reports. 14 // 15 //===----------------------------------------------------------------------===// 16 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/DebugInfo/Symbolize/DIPrinter.h" 19 #include "llvm/DebugInfo/Symbolize/Symbolize.h" 20 #include "llvm/Support/COM.h" 21 #include "llvm/Support/CommandLine.h" 22 #include "llvm/Support/Debug.h" 23 #include "llvm/Support/FileSystem.h" 24 #include "llvm/Support/InitLLVM.h" 25 #include "llvm/Support/Path.h" 26 #include "llvm/Support/raw_ostream.h" 27 #include <cstdio> 28 #include <cstring> 29 #include <string> 30 31 using namespace llvm; 32 using namespace symbolize; 33 34 static cl::opt<bool> 35 ClUseSymbolTable("use-symbol-table", cl::init(true), 36 cl::desc("Prefer names in symbol table to names " 37 "in debug info")); 38 39 static cl::opt<FunctionNameKind> ClPrintFunctions( 40 "functions", cl::init(FunctionNameKind::LinkageName), 41 cl::desc("Print function name for a given address"), cl::ValueOptional, 42 cl::values(clEnumValN(FunctionNameKind::None, "none", "omit function name"), 43 clEnumValN(FunctionNameKind::ShortName, "short", 44 "print short function name"), 45 clEnumValN(FunctionNameKind::LinkageName, "linkage", 46 "print function linkage name"), 47 // Sentinel value for unspecified value. 48 clEnumValN(FunctionNameKind::LinkageName, "", ""))); 49 static cl::alias ClPrintFunctionsShort("f", cl::desc("Alias for -functions"), 50 cl::NotHidden, cl::Grouping, 51 cl::aliasopt(ClPrintFunctions)); 52 53 static cl::opt<bool> 54 ClUseRelativeAddress("relative-address", cl::init(false), 55 cl::desc("Interpret addresses as relative addresses"), 56 cl::ReallyHidden); 57 58 static cl::opt<bool> ClUntagAddresses( 59 "untag-addresses", cl::init(true), 60 cl::desc("Remove memory tags from addresses before symbolization")); 61 62 static cl::opt<bool> 63 ClPrintInlining("inlining", cl::init(true), 64 cl::desc("Print all inlined frames for a given address")); 65 static cl::alias 66 ClPrintInliningAliasI("i", cl::desc("Alias for -inlining"), 67 cl::NotHidden, cl::aliasopt(ClPrintInlining), 68 cl::Grouping); 69 static cl::alias 70 ClPrintInliningAliasInlines("inlines", cl::desc("Alias for -inlining"), 71 cl::NotHidden, cl::aliasopt(ClPrintInlining)); 72 73 // -basenames, -s 74 static cl::opt<bool> ClBasenames("basenames", cl::init(false), 75 cl::desc("Strip directory names from paths")); 76 static cl::alias ClBasenamesShort("s", cl::desc("Alias for -basenames"), 77 cl::NotHidden, cl::aliasopt(ClBasenames)); 78 79 // -demangle, -C, -no-demangle 80 static cl::opt<bool> 81 ClDemangle("demangle", cl::init(true), cl::desc("Demangle function names")); 82 static cl::alias 83 ClDemangleShort("C", cl::desc("Alias for -demangle"), 84 cl::NotHidden, cl::aliasopt(ClDemangle), cl::Grouping); 85 static cl::opt<bool> 86 ClNoDemangle("no-demangle", cl::init(false), 87 cl::desc("Don't demangle function names")); 88 89 static cl::opt<std::string> ClDefaultArch("default-arch", cl::init(""), 90 cl::desc("Default architecture " 91 "(for multi-arch objects)")); 92 93 // -obj, -exe, -e 94 static cl::opt<std::string> 95 ClBinaryName("obj", cl::init(""), 96 cl::desc("Path to object file to be symbolized (if not provided, " 97 "object file should be specified for each input line)")); 98 static cl::alias 99 ClBinaryNameAliasExe("exe", cl::desc("Alias for -obj"), 100 cl::NotHidden, cl::aliasopt(ClBinaryName)); 101 static cl::alias ClBinaryNameAliasE("e", cl::desc("Alias for -obj"), 102 cl::NotHidden, cl::Grouping, cl::Prefix, 103 cl::aliasopt(ClBinaryName)); 104 105 static cl::opt<std::string> 106 ClDwpName("dwp", cl::init(""), 107 cl::desc("Path to DWP file to be use for any split CUs")); 108 109 static cl::list<std::string> 110 ClDsymHint("dsym-hint", cl::ZeroOrMore, 111 cl::desc("Path to .dSYM bundles to search for debug info for the " 112 "object files")); 113 114 // -print-address, -addresses, -a 115 static cl::opt<bool> 116 ClPrintAddress("print-address", cl::init(false), 117 cl::desc("Show address before line information")); 118 static cl::alias 119 ClPrintAddressAliasAddresses("addresses", cl::desc("Alias for -print-address"), 120 cl::NotHidden, cl::aliasopt(ClPrintAddress)); 121 static cl::alias 122 ClPrintAddressAliasA("a", cl::desc("Alias for -print-address"), 123 cl::NotHidden, cl::aliasopt(ClPrintAddress), cl::Grouping); 124 125 // -pretty-print, -p 126 static cl::opt<bool> 127 ClPrettyPrint("pretty-print", cl::init(false), 128 cl::desc("Make the output more human friendly")); 129 static cl::alias ClPrettyPrintShort("p", cl::desc("Alias for -pretty-print"), 130 cl::NotHidden, 131 cl::aliasopt(ClPrettyPrint), cl::Grouping); 132 133 static cl::opt<int> ClPrintSourceContextLines( 134 "print-source-context-lines", cl::init(0), 135 cl::desc("Print N number of source file context")); 136 137 static cl::opt<bool> ClVerbose("verbose", cl::init(false), 138 cl::desc("Print verbose line info")); 139 140 // -adjust-vma 141 static cl::opt<uint64_t> 142 ClAdjustVMA("adjust-vma", cl::init(0), cl::value_desc("offset"), 143 cl::desc("Add specified offset to object file addresses")); 144 145 static cl::list<std::string> ClInputAddresses(cl::Positional, 146 cl::desc("<input addresses>..."), 147 cl::ZeroOrMore); 148 149 static cl::opt<std::string> 150 ClFallbackDebugPath("fallback-debug-path", cl::init(""), 151 cl::desc("Fallback path for debug binaries.")); 152 153 static cl::opt<DIPrinter::OutputStyle> 154 ClOutputStyle("output-style", cl::init(DIPrinter::OutputStyle::LLVM), 155 cl::desc("Specify print style"), 156 cl::values(clEnumValN(DIPrinter::OutputStyle::LLVM, "LLVM", 157 "LLVM default style"), 158 clEnumValN(DIPrinter::OutputStyle::GNU, "GNU", 159 "GNU addr2line style"))); 160 161 static cl::extrahelp 162 HelpResponse("\nPass @FILE as argument to read options from FILE.\n"); 163 164 template<typename T> 165 static bool error(Expected<T> &ResOrErr) { 166 if (ResOrErr) 167 return false; 168 logAllUnhandledErrors(ResOrErr.takeError(), errs(), 169 "LLVMSymbolizer: error reading file: "); 170 return true; 171 } 172 173 enum class Command { 174 Code, 175 Data, 176 Frame, 177 }; 178 179 static bool parseCommand(StringRef InputString, Command &Cmd, 180 std::string &ModuleName, uint64_t &ModuleOffset) { 181 const char kDelimiters[] = " \n\r"; 182 ModuleName = ""; 183 if (InputString.consume_front("CODE ")) { 184 Cmd = Command::Code; 185 } else if (InputString.consume_front("DATA ")) { 186 Cmd = Command::Data; 187 } else if (InputString.consume_front("FRAME ")) { 188 Cmd = Command::Frame; 189 } else { 190 // If no cmd, assume it's CODE. 191 Cmd = Command::Code; 192 } 193 const char *pos = InputString.data(); 194 // Skip delimiters and parse input filename (if needed). 195 if (ClBinaryName.empty()) { 196 pos += strspn(pos, kDelimiters); 197 if (*pos == '"' || *pos == '\'') { 198 char quote = *pos; 199 pos++; 200 const char *end = strchr(pos, quote); 201 if (!end) 202 return false; 203 ModuleName = std::string(pos, end - pos); 204 pos = end + 1; 205 } else { 206 int name_length = strcspn(pos, kDelimiters); 207 ModuleName = std::string(pos, name_length); 208 pos += name_length; 209 } 210 } else { 211 ModuleName = ClBinaryName; 212 } 213 // Skip delimiters and parse module offset. 214 pos += strspn(pos, kDelimiters); 215 int offset_length = strcspn(pos, kDelimiters); 216 return !StringRef(pos, offset_length).getAsInteger(0, ModuleOffset); 217 } 218 219 static void symbolizeInput(StringRef InputString, LLVMSymbolizer &Symbolizer, 220 DIPrinter &Printer) { 221 Command Cmd; 222 std::string ModuleName; 223 uint64_t Offset = 0; 224 if (!parseCommand(StringRef(InputString), Cmd, ModuleName, Offset)) { 225 outs() << InputString; 226 return; 227 } 228 229 if (ClPrintAddress) { 230 outs() << "0x"; 231 outs().write_hex(Offset); 232 StringRef Delimiter = ClPrettyPrint ? ": " : "\n"; 233 outs() << Delimiter; 234 } 235 Offset -= ClAdjustVMA; 236 if (Cmd == Command::Data) { 237 auto ResOrErr = Symbolizer.symbolizeData( 238 ModuleName, {Offset, object::SectionedAddress::UndefSection}); 239 Printer << (error(ResOrErr) ? DIGlobal() : ResOrErr.get()); 240 } else if (Cmd == Command::Frame) { 241 auto ResOrErr = Symbolizer.symbolizeFrame( 242 ModuleName, {Offset, object::SectionedAddress::UndefSection}); 243 if (!error(ResOrErr)) { 244 for (DILocal Local : *ResOrErr) 245 Printer << Local; 246 if (ResOrErr->empty()) 247 outs() << "??\n"; 248 } 249 } else if (ClPrintInlining) { 250 auto ResOrErr = Symbolizer.symbolizeInlinedCode( 251 ModuleName, {Offset, object::SectionedAddress::UndefSection}); 252 Printer << (error(ResOrErr) ? DIInliningInfo() : ResOrErr.get()); 253 } else if (ClOutputStyle == DIPrinter::OutputStyle::GNU) { 254 // With ClPrintFunctions == FunctionNameKind::LinkageName (default) 255 // and ClUseSymbolTable == true (also default), Symbolizer.symbolizeCode() 256 // may override the name of an inlined function with the name of the topmost 257 // caller function in the inlining chain. This contradicts the existing 258 // behavior of addr2line. Symbolizer.symbolizeInlinedCode() overrides only 259 // the topmost function, which suits our needs better. 260 auto ResOrErr = Symbolizer.symbolizeInlinedCode( 261 ModuleName, {Offset, object::SectionedAddress::UndefSection}); 262 Printer << (error(ResOrErr) ? DILineInfo() : ResOrErr.get().getFrame(0)); 263 } else { 264 auto ResOrErr = Symbolizer.symbolizeCode( 265 ModuleName, {Offset, object::SectionedAddress::UndefSection}); 266 Printer << (error(ResOrErr) ? DILineInfo() : ResOrErr.get()); 267 } 268 if (ClOutputStyle == DIPrinter::OutputStyle::LLVM) 269 outs() << "\n"; 270 } 271 272 int main(int argc, char **argv) { 273 InitLLVM X(argc, argv); 274 275 bool IsAddr2Line = sys::path::stem(argv[0]).contains("addr2line"); 276 277 if (IsAddr2Line) { 278 ClDemangle.setInitialValue(false); 279 ClPrintFunctions.setInitialValue(FunctionNameKind::None); 280 ClPrintInlining.setInitialValue(false); 281 ClUntagAddresses.setInitialValue(false); 282 ClOutputStyle.setInitialValue(DIPrinter::OutputStyle::GNU); 283 } 284 285 llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded); 286 cl::ParseCommandLineOptions(argc, argv, IsAddr2Line ? "llvm-addr2line\n" 287 : "llvm-symbolizer\n"); 288 289 // If both --demangle and --no-demangle are specified then pick the last one. 290 if (ClNoDemangle.getPosition() > ClDemangle.getPosition()) 291 ClDemangle = !ClNoDemangle; 292 293 LLVMSymbolizer::Options Opts; 294 Opts.PrintFunctions = ClPrintFunctions; 295 Opts.UseSymbolTable = ClUseSymbolTable; 296 Opts.Demangle = ClDemangle; 297 Opts.RelativeAddresses = ClUseRelativeAddress; 298 Opts.UntagAddresses = ClUntagAddresses; 299 Opts.DefaultArch = ClDefaultArch; 300 Opts.FallbackDebugPath = ClFallbackDebugPath; 301 Opts.DWPName = ClDwpName; 302 303 for (const auto &hint : ClDsymHint) { 304 if (sys::path::extension(hint) == ".dSYM") { 305 Opts.DsymHints.push_back(hint); 306 } else { 307 errs() << "Warning: invalid dSYM hint: \"" << hint << 308 "\" (must have the '.dSYM' extension).\n"; 309 } 310 } 311 LLVMSymbolizer Symbolizer(Opts); 312 313 DIPrinter Printer(outs(), ClPrintFunctions != FunctionNameKind::None, 314 ClPrettyPrint, ClPrintSourceContextLines, ClVerbose, 315 ClBasenames, ClOutputStyle); 316 317 if (ClInputAddresses.empty()) { 318 const int kMaxInputStringLength = 1024; 319 char InputString[kMaxInputStringLength]; 320 321 while (fgets(InputString, sizeof(InputString), stdin)) { 322 symbolizeInput(InputString, Symbolizer, Printer); 323 outs().flush(); 324 } 325 } else { 326 for (StringRef Address : ClInputAddresses) 327 symbolizeInput(Address, Symbolizer, Printer); 328 } 329 330 return 0; 331 } 332