blob: 2da35f930d025967f5eebd3d4b98a5fd30acb3eb [file] [log] [blame]
Alexey Samsonovea83baf2013-01-22 14:21:19 +00001//===-- LLVMSymbolize.cpp -------------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Implementation for LLVM symbolization library.
11//
12//===----------------------------------------------------------------------===//
13
Alexey Samsonov57f88372015-10-26 17:56:12 +000014#include "llvm/DebugInfo/Symbolize/Symbolize.h"
15
Alexey Samsonov8df3a072015-10-29 22:21:37 +000016#include "SymbolizableObjectFile.h"
17
Alexey Samsonovdd71c5b2013-03-19 15:33:18 +000018#include "llvm/ADT/STLExtras.h"
Alexey Samsonova591ae62013-08-26 18:12:03 +000019#include "llvm/Config/config.h"
Zachary Turner6489d7b2015-04-23 17:37:47 +000020#include "llvm/DebugInfo/DWARF/DWARFContext.h"
Zachary Turner20dbd0d2015-04-27 17:19:51 +000021#include "llvm/DebugInfo/PDB/PDB.h"
22#include "llvm/DebugInfo/PDB/PDBContext.h"
Alexey Samsonova5f07682014-02-26 13:10:01 +000023#include "llvm/Object/ELFObjectFile.h"
Alexey Samsonovea83baf2013-01-22 14:21:19 +000024#include "llvm/Object/MachO.h"
Reid Klecknerc25c7942015-08-10 21:47:11 +000025#include "llvm/Support/COFF.h"
Alexey Samsonovea83baf2013-01-22 14:21:19 +000026#include "llvm/Support/Casting.h"
Alexey Samsonov3e9997f2013-08-14 17:09:30 +000027#include "llvm/Support/Compression.h"
28#include "llvm/Support/DataExtractor.h"
Rafael Espindola2a826e42014-06-13 17:20:48 +000029#include "llvm/Support/Errc.h"
Alexey Samsonov5239d582013-06-04 07:57:38 +000030#include "llvm/Support/FileSystem.h"
Alexey Samsonov3e9997f2013-08-14 17:09:30 +000031#include "llvm/Support/MemoryBuffer.h"
Alexey Samsonovea83baf2013-01-22 14:21:19 +000032#include "llvm/Support/Path.h"
Alexey Samsonovea83baf2013-01-22 14:21:19 +000033#include <sstream>
Alexey Samsonova591ae62013-08-26 18:12:03 +000034#include <stdlib.h>
Alexey Samsonovea83baf2013-01-22 14:21:19 +000035
Zachary Turnerc007aa42015-05-06 22:26:30 +000036#if defined(_MSC_VER)
37#include <Windows.h>
38#include <DbgHelp.h>
Leny Kholodovbebb27b2015-07-02 14:34:57 +000039#pragma comment(lib, "dbghelp.lib")
Reid Klecknerc25c7942015-08-10 21:47:11 +000040
41// Windows.h conflicts with our COFF header definitions.
42#ifdef IMAGE_FILE_MACHINE_I386
43#undef IMAGE_FILE_MACHINE_I386
44#endif
Zachary Turnerc007aa42015-05-06 22:26:30 +000045#endif
46
Alexey Samsonovea83baf2013-01-22 14:21:19 +000047namespace llvm {
48namespace symbolize {
49
Alexey Samsonov57f88372015-10-26 17:56:12 +000050// FIXME: Move this to llvm-symbolizer tool.
Rafael Espindola4453e42942014-06-13 03:07:50 +000051static bool error(std::error_code ec) {
Alexey Samsonovd5d7bb52013-02-15 08:54:47 +000052 if (!ec)
53 return false;
Dmitry Vyukovef8fb722013-02-14 13:06:18 +000054 errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n";
55 return true;
56}
57
Alexey Samsonovea83baf2013-01-22 14:21:19 +000058
Alexey Samsonovd6cef102013-02-04 15:55:26 +000059const char LLVMSymbolizer::kBadString[] = "??";
Alexey Samsonovea83baf2013-01-22 14:21:19 +000060
61std::string LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
62 uint64_t ModuleOffset) {
Alexey Samsonov8df3a072015-10-29 22:21:37 +000063 SymbolizableModule *Info = getOrCreateModuleInfo(ModuleName);
Craig Toppere6cb63e2014-04-25 04:24:47 +000064 if (!Info)
Reid Klecknerc25c7942015-08-10 21:47:11 +000065 return printDILineInfo(DILineInfo(), Info);
Reid Klecknere94fef72015-10-09 00:15:01 +000066
67 // If the user is giving us relative addresses, add the preferred base of the
68 // object to the offset before we do the query. It's what DIContext expects.
69 if (Opts.RelativeAddresses)
70 ModuleOffset += Info->getModulePreferredBase();
71
Alexey Samsonovea83baf2013-01-22 14:21:19 +000072 if (Opts.PrintInlining) {
Alexey Samsonov0fb64512015-10-26 22:34:56 +000073 DIInliningInfo InlinedContext = Info->symbolizeInlinedCode(
74 ModuleOffset, Opts.PrintFunctions, Opts.UseSymbolTable);
Alexey Samsonovea83baf2013-01-22 14:21:19 +000075 uint32_t FramesNum = InlinedContext.getNumberOfFrames();
76 assert(FramesNum > 0);
77 std::string Result;
78 for (uint32_t i = 0; i < FramesNum; i++) {
79 DILineInfo LineInfo = InlinedContext.getFrame(i);
Reid Klecknerc25c7942015-08-10 21:47:11 +000080 Result += printDILineInfo(LineInfo, Info);
Alexey Samsonovea83baf2013-01-22 14:21:19 +000081 }
82 return Result;
83 }
Alexey Samsonov0fb64512015-10-26 22:34:56 +000084 DILineInfo LineInfo = Info->symbolizeCode(ModuleOffset, Opts.PrintFunctions,
85 Opts.UseSymbolTable);
Reid Klecknerc25c7942015-08-10 21:47:11 +000086 return printDILineInfo(LineInfo, Info);
Alexey Samsonovea83baf2013-01-22 14:21:19 +000087}
88
89std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
90 uint64_t ModuleOffset) {
91 std::string Name = kBadString;
92 uint64_t Start = 0;
93 uint64_t Size = 0;
94 if (Opts.UseSymbolTable) {
Alexey Samsonov8df3a072015-10-29 22:21:37 +000095 if (SymbolizableModule *Info = getOrCreateModuleInfo(ModuleName)) {
96 // If the user is giving us relative addresses, add the preferred base of
97 // the object to the offset before we do the query. It's what DIContext
98 // expects.
Reid Klecknere94fef72015-10-09 00:15:01 +000099 if (Opts.RelativeAddresses)
100 ModuleOffset += Info->getModulePreferredBase();
Alexey Samsonov601beb72013-06-28 12:06:25 +0000101 if (Info->symbolizeData(ModuleOffset, Name, Start, Size) && Opts.Demangle)
Reid Klecknerc25c7942015-08-10 21:47:11 +0000102 Name = DemangleName(Name, Info);
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000103 }
104 }
105 std::stringstream ss;
106 ss << Name << "\n" << Start << " " << Size << "\n";
107 return ss.str();
108}
109
Dmitry Vyukove8504e22013-03-19 10:24:42 +0000110void LLVMSymbolizer::flush() {
Alexey Samsonov7a952e52015-10-26 19:41:23 +0000111 Modules.clear();
Alexander Potapenko7aaf5142014-10-17 00:50:19 +0000112 ObjectPairForPathArch.clear();
Alexey Samsonovfe3a5d92013-06-28 15:08:29 +0000113 ObjectFileForArch.clear();
Dmitry Vyukove8504e22013-03-19 10:24:42 +0000114}
115
Alexander Potapenko7aaf5142014-10-17 00:50:19 +0000116// For Path="/path/to/foo" and Basename="foo" assume that debug info is in
117// /path/to/foo.dSYM/Contents/Resources/DWARF/foo.
118// For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in
119// /path/to/bar.dSYM/Contents/Resources/DWARF/foo.
120static
121std::string getDarwinDWARFResourceForPath(
122 const std::string &Path, const std::string &Basename) {
123 SmallString<16> ResourceName = StringRef(Path);
124 if (sys::path::extension(Path) != ".dSYM") {
125 ResourceName += ".dSYM";
126 }
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000127 sys::path::append(ResourceName, "Contents", "Resources", "DWARF");
128 sys::path::append(ResourceName, Basename);
129 return ResourceName.str();
130}
131
Alexey Samsonov3e9997f2013-08-14 17:09:30 +0000132static bool checkFileCRC(StringRef Path, uint32_t CRCHash) {
Rafael Espindolaadf21f22014-07-06 17:43:13 +0000133 ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
134 MemoryBuffer::getFileOrSTDIN(Path);
135 if (!MB)
Alexey Samsonov3e9997f2013-08-14 17:09:30 +0000136 return false;
Rafael Espindolaadf21f22014-07-06 17:43:13 +0000137 return !zlib::isAvailable() || CRCHash == zlib::crc32(MB.get()->getBuffer());
Alexey Samsonov3e9997f2013-08-14 17:09:30 +0000138}
139
140static bool findDebugBinary(const std::string &OrigPath,
141 const std::string &DebuglinkName, uint32_t CRCHash,
142 std::string &Result) {
Alexey Samsonova591ae62013-08-26 18:12:03 +0000143 std::string OrigRealPath = OrigPath;
144#if defined(HAVE_REALPATH)
Craig Toppere6cb63e2014-04-25 04:24:47 +0000145 if (char *RP = realpath(OrigPath.c_str(), nullptr)) {
Alexey Samsonova591ae62013-08-26 18:12:03 +0000146 OrigRealPath = RP;
147 free(RP);
148 }
149#endif
150 SmallString<16> OrigDir(OrigRealPath);
Alexey Samsonov3e9997f2013-08-14 17:09:30 +0000151 llvm::sys::path::remove_filename(OrigDir);
152 SmallString<16> DebugPath = OrigDir;
153 // Try /path/to/original_binary/debuglink_name
154 llvm::sys::path::append(DebugPath, DebuglinkName);
155 if (checkFileCRC(DebugPath, CRCHash)) {
156 Result = DebugPath.str();
157 return true;
158 }
159 // Try /path/to/original_binary/.debug/debuglink_name
Alexey Samsonova591ae62013-08-26 18:12:03 +0000160 DebugPath = OrigRealPath;
Alexey Samsonov3e9997f2013-08-14 17:09:30 +0000161 llvm::sys::path::append(DebugPath, ".debug", DebuglinkName);
162 if (checkFileCRC(DebugPath, CRCHash)) {
163 Result = DebugPath.str();
164 return true;
165 }
166 // Try /usr/lib/debug/path/to/original_binary/debuglink_name
167 DebugPath = "/usr/lib/debug";
168 llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir),
169 DebuglinkName);
170 if (checkFileCRC(DebugPath, CRCHash)) {
171 Result = DebugPath.str();
172 return true;
173 }
174 return false;
175}
176
Alexander Potapenko7aaf5142014-10-17 00:50:19 +0000177static bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName,
Alexey Samsonov3e9997f2013-08-14 17:09:30 +0000178 uint32_t &CRCHash) {
Alexey Samsonov3e9997f2013-08-14 17:09:30 +0000179 if (!Obj)
180 return false;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000181 for (const SectionRef &Section : Obj->sections()) {
Alexey Samsonov3e9997f2013-08-14 17:09:30 +0000182 StringRef Name;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000183 Section.getName(Name);
Alexey Samsonov3e9997f2013-08-14 17:09:30 +0000184 Name = Name.substr(Name.find_first_not_of("._"));
185 if (Name == "gnu_debuglink") {
186 StringRef Data;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000187 Section.getContents(Data);
Alexey Samsonov3e9997f2013-08-14 17:09:30 +0000188 DataExtractor DE(Data, Obj->isLittleEndian(), 0);
189 uint32_t Offset = 0;
190 if (const char *DebugNameStr = DE.getCStr(&Offset)) {
191 // 4-byte align the offset.
192 Offset = (Offset + 3) & ~0x3;
193 if (DE.isValidOffsetForDataOfSize(Offset, 4)) {
194 DebugName = DebugNameStr;
195 CRCHash = DE.getU32(&Offset);
196 return true;
197 }
198 }
199 break;
200 }
201 }
202 return false;
203}
204
Alexander Potapenko7aaf5142014-10-17 00:50:19 +0000205static
206bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj,
207 const MachOObjectFile *Obj) {
208 ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid();
209 ArrayRef<uint8_t> bin_uuid = Obj->getUuid();
210 if (dbg_uuid.empty() || bin_uuid.empty())
211 return false;
212 return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size());
213}
214
215ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
216 const MachOObjectFile *MachExeObj, const std::string &ArchName) {
217 // On Darwin we may find DWARF in separate object file in
218 // resource directory.
219 std::vector<std::string> DsymPaths;
220 StringRef Filename = sys::path::filename(ExePath);
221 DsymPaths.push_back(getDarwinDWARFResourceForPath(ExePath, Filename));
222 for (const auto &Path : Opts.DsymHints) {
223 DsymPaths.push_back(getDarwinDWARFResourceForPath(Path, Filename));
224 }
225 for (const auto &path : DsymPaths) {
226 ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(path);
227 std::error_code EC = BinaryOrErr.getError();
228 if (EC != errc::no_such_file_or_directory && !error(EC)) {
229 OwningBinary<Binary> B = std::move(BinaryOrErr.get());
230 ObjectFile *DbgObj =
Lang Hamesf04de6e2014-10-31 21:37:49 +0000231 getObjectFileFromBinary(B.getBinary(), ArchName);
Alexander Potapenko7aaf5142014-10-17 00:50:19 +0000232 const MachOObjectFile *MachDbgObj =
233 dyn_cast<const MachOObjectFile>(DbgObj);
234 if (!MachDbgObj) continue;
235 if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj)) {
Rafael Espindola48af1c22014-08-19 18:44:46 +0000236 addOwningBinary(std::move(B));
Alexander Potapenko7aaf5142014-10-17 00:50:19 +0000237 return DbgObj;
Alexey Samsonov2ca65362013-06-28 08:15:40 +0000238 }
239 }
Alexander Potapenko7aaf5142014-10-17 00:50:19 +0000240 }
241 return nullptr;
242}
243
244LLVMSymbolizer::ObjectPair
245LLVMSymbolizer::getOrCreateObjects(const std::string &Path,
246 const std::string &ArchName) {
247 const auto &I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName));
248 if (I != ObjectPairForPathArch.end())
249 return I->second;
250 ObjectFile *Obj = nullptr;
251 ObjectFile *DbgObj = nullptr;
252 ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(Path);
253 if (!error(BinaryOrErr.getError())) {
254 OwningBinary<Binary> &B = BinaryOrErr.get();
Lang Hamesf04de6e2014-10-31 21:37:49 +0000255 Obj = getObjectFileFromBinary(B.getBinary(), ArchName);
Alexander Potapenko7aaf5142014-10-17 00:50:19 +0000256 if (!Obj) {
257 ObjectPair Res = std::make_pair(nullptr, nullptr);
258 ObjectPairForPathArch[std::make_pair(Path, ArchName)] = Res;
259 return Res;
260 }
261 addOwningBinary(std::move(B));
262 if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj))
263 DbgObj = lookUpDsymFile(Path, MachObj, ArchName);
Alexey Samsonov3e9997f2013-08-14 17:09:30 +0000264 // Try to locate the debug binary using .gnu_debuglink section.
Alexander Potapenko7aaf5142014-10-17 00:50:19 +0000265 if (!DbgObj) {
Alexey Samsonov3e9997f2013-08-14 17:09:30 +0000266 std::string DebuglinkName;
267 uint32_t CRCHash;
268 std::string DebugBinaryPath;
Alexander Potapenko7aaf5142014-10-17 00:50:19 +0000269 if (getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash) &&
Rafael Espindola63da2952014-01-15 19:37:43 +0000270 findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath)) {
271 BinaryOrErr = createBinary(DebugBinaryPath);
272 if (!error(BinaryOrErr.getError())) {
Rafael Espindola48af1c22014-08-19 18:44:46 +0000273 OwningBinary<Binary> B = std::move(BinaryOrErr.get());
Lang Hamesf04de6e2014-10-31 21:37:49 +0000274 DbgObj = getObjectFileFromBinary(B.getBinary(), ArchName);
Rafael Espindola48af1c22014-08-19 18:44:46 +0000275 addOwningBinary(std::move(B));
Rafael Espindola63da2952014-01-15 19:37:43 +0000276 }
Alexey Samsonov3e9997f2013-08-14 17:09:30 +0000277 }
278 }
Alexey Samsonov2ca65362013-06-28 08:15:40 +0000279 }
Alexander Potapenko7aaf5142014-10-17 00:50:19 +0000280 if (!DbgObj)
281 DbgObj = Obj;
282 ObjectPair Res = std::make_pair(Obj, DbgObj);
283 ObjectPairForPathArch[std::make_pair(Path, ArchName)] = Res;
Alexey Samsonov2ca65362013-06-28 08:15:40 +0000284 return Res;
285}
286
287ObjectFile *
Alexander Potapenko7aaf5142014-10-17 00:50:19 +0000288LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin,
289 const std::string &ArchName) {
Craig Toppere6cb63e2014-04-25 04:24:47 +0000290 if (!Bin)
291 return nullptr;
292 ObjectFile *Res = nullptr;
Alexey Samsonov2ca65362013-06-28 08:15:40 +0000293 if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) {
Alexander Potapenko45bfe372014-10-14 13:40:44 +0000294 const auto &I = ObjectFileForArch.find(
Alexey Samsonov2ca65362013-06-28 08:15:40 +0000295 std::make_pair(UB, ArchName));
296 if (I != ObjectFileForArch.end())
297 return I->second;
Rafael Espindola4f7932b2014-06-23 20:41:02 +0000298 ErrorOr<std::unique_ptr<ObjectFile>> ParsedObj =
Frederic Rissebc162a2015-06-22 21:33:24 +0000299 UB->getObjectForArch(ArchName);
Rafael Espindola4f7932b2014-06-23 20:41:02 +0000300 if (ParsedObj) {
301 Res = ParsedObj.get().get();
302 ParsedBinariesAndObjects.push_back(std::move(ParsedObj.get()));
Alexey Samsonov2ca65362013-06-28 08:15:40 +0000303 }
304 ObjectFileForArch[std::make_pair(UB, ArchName)] = Res;
305 } else if (Bin->isObject()) {
306 Res = cast<ObjectFile>(Bin);
307 }
308 return Res;
309}
310
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000311SymbolizableModule *
Alexey Samsonovd5d7bb52013-02-15 08:54:47 +0000312LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
Alexander Potapenko45bfe372014-10-14 13:40:44 +0000313 const auto &I = Modules.find(ModuleName);
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000314 if (I != Modules.end())
Alexey Samsonov7a952e52015-10-26 19:41:23 +0000315 return I->second.get();
Alexey Samsonov2ca65362013-06-28 08:15:40 +0000316 std::string BinaryName = ModuleName;
317 std::string ArchName = Opts.DefaultArch;
Alexey Samsonovb119b462013-07-17 06:45:36 +0000318 size_t ColonPos = ModuleName.find_last_of(':');
319 // Verify that substring after colon form a valid arch name.
Alexey Samsonov2ca65362013-06-28 08:15:40 +0000320 if (ColonPos != std::string::npos) {
Alexey Samsonovb119b462013-07-17 06:45:36 +0000321 std::string ArchStr = ModuleName.substr(ColonPos + 1);
NAKAMURA Takumi8ee89c62013-07-17 06:53:51 +0000322 if (Triple(ArchStr).getArch() != Triple::UnknownArch) {
Alexey Samsonovb119b462013-07-17 06:45:36 +0000323 BinaryName = ModuleName.substr(0, ColonPos);
324 ArchName = ArchStr;
325 }
Alexey Samsonov2ca65362013-06-28 08:15:40 +0000326 }
Alexander Potapenko7aaf5142014-10-17 00:50:19 +0000327 ObjectPair Objects = getOrCreateObjects(BinaryName, ArchName);
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000328
Alexander Potapenko7aaf5142014-10-17 00:50:19 +0000329 if (!Objects.first) {
Alexey Samsonov2ca65362013-06-28 08:15:40 +0000330 // Failed to find valid object file.
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000331 Modules.insert(std::make_pair(ModuleName, nullptr));
Craig Toppere6cb63e2014-04-25 04:24:47 +0000332 return nullptr;
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000333 }
Alexey Samsonov7a952e52015-10-26 19:41:23 +0000334 std::unique_ptr<DIContext> Context;
Zachary Turner20dbd0d2015-04-27 17:19:51 +0000335 if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) {
336 // If this is a COFF object, assume it contains PDB debug information. If
337 // we don't find any we will fall back to the DWARF case.
338 std::unique_ptr<IPDBSession> Session;
339 PDB_ErrorCode Error = loadDataForEXE(PDB_ReaderType::DIA,
340 Objects.first->getFileName(), Session);
Zachary Turnerc007aa42015-05-06 22:26:30 +0000341 if (Error == PDB_ErrorCode::Success) {
Alexey Samsonov7a952e52015-10-26 19:41:23 +0000342 Context.reset(new PDBContext(*CoffObject, std::move(Session)));
Zachary Turnerc007aa42015-05-06 22:26:30 +0000343 }
Zachary Turner20dbd0d2015-04-27 17:19:51 +0000344 }
345 if (!Context)
Alexey Samsonov7a952e52015-10-26 19:41:23 +0000346 Context.reset(new DWARFContextInMemory(*Objects.second));
Alexey Samsonov2ca65362013-06-28 08:15:40 +0000347 assert(Context);
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000348 auto ErrOrInfo =
349 SymbolizableObjectFile::create(Objects.first, std::move(Context));
350 if (error(ErrOrInfo.getError())) {
351 Modules.insert(std::make_pair(ModuleName, nullptr));
352 return nullptr;
353 }
354 SymbolizableModule *Res = ErrOrInfo.get().get();
355 Modules.insert(std::make_pair(ModuleName, std::move(ErrOrInfo.get())));
Alexey Samsonov7a952e52015-10-26 19:41:23 +0000356 return Res;
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000357}
358
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000359std::string
360LLVMSymbolizer::printDILineInfo(DILineInfo LineInfo,
361 const SymbolizableModule *ModInfo) const {
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000362 // By default, DILineInfo contains "<invalid>" for function/filename it
363 // cannot fetch. We replace it to "??" to make our output closer to addr2line.
364 static const std::string kDILineInfoBadString = "<invalid>";
365 std::stringstream Result;
Alexey Samsonovcd014722014-05-17 00:07:48 +0000366 if (Opts.PrintFunctions != FunctionNameKind::None) {
Alexey Samsonovd0109992014-04-18 21:36:39 +0000367 std::string FunctionName = LineInfo.FunctionName;
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000368 if (FunctionName == kDILineInfoBadString)
369 FunctionName = kBadString;
Alexey Samsonov601beb72013-06-28 12:06:25 +0000370 else if (Opts.Demangle)
Reid Klecknerc25c7942015-08-10 21:47:11 +0000371 FunctionName = DemangleName(FunctionName, ModInfo);
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000372 Result << FunctionName << "\n";
373 }
Alexey Samsonovd0109992014-04-18 21:36:39 +0000374 std::string Filename = LineInfo.FileName;
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000375 if (Filename == kDILineInfoBadString)
376 Filename = kBadString;
Alexey Samsonovd0109992014-04-18 21:36:39 +0000377 Result << Filename << ":" << LineInfo.Line << ":" << LineInfo.Column << "\n";
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000378 return Result.str();
379}
380
Reid Klecknerc25c7942015-08-10 21:47:11 +0000381// Undo these various manglings for Win32 extern "C" functions:
382// cdecl - _foo
383// stdcall - _foo@12
384// fastcall - @foo@12
385// vectorcall - foo@@12
386// These are all different linkage names for 'foo'.
387static StringRef demanglePE32ExternCFunc(StringRef SymbolName) {
388 // Remove any '_' or '@' prefix.
389 char Front = SymbolName.empty() ? '\0' : SymbolName[0];
390 if (Front == '_' || Front == '@')
391 SymbolName = SymbolName.drop_front();
392
393 // Remove any '@[0-9]+' suffix.
394 if (Front != '?') {
395 size_t AtPos = SymbolName.rfind('@');
396 if (AtPos != StringRef::npos &&
397 std::all_of(SymbolName.begin() + AtPos + 1, SymbolName.end(),
398 [](char C) { return C >= '0' && C <= '9'; })) {
399 SymbolName = SymbolName.substr(0, AtPos);
400 }
401 }
402
403 // Remove any ending '@' for vectorcall.
404 if (SymbolName.endswith("@"))
405 SymbolName = SymbolName.drop_back();
406
407 return SymbolName;
408}
409
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000410#if !defined(_MSC_VER)
411// Assume that __cxa_demangle is provided by libcxxabi (except for Windows).
412extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer,
413 size_t *length, int *status);
414#endif
415
Reid Klecknerc25c7942015-08-10 21:47:11 +0000416std::string LLVMSymbolizer::DemangleName(const std::string &Name,
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000417 const SymbolizableModule *ModInfo) {
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000418#if !defined(_MSC_VER)
Ed Masteef6fed72014-01-16 17:25:12 +0000419 // We can spoil names of symbols with C linkage, so use an heuristic
420 // approach to check if the name should be demangled.
Reid Klecknerc25c7942015-08-10 21:47:11 +0000421 if (Name.substr(0, 2) == "_Z") {
422 int status = 0;
423 char *DemangledName = __cxa_demangle(Name.c_str(), nullptr, nullptr, &status);
424 if (status != 0)
425 return Name;
426 std::string Result = DemangledName;
427 free(DemangledName);
428 return Result;
429 }
Alexey Samsonov601beb72013-06-28 12:06:25 +0000430#else
Reid Klecknerc25c7942015-08-10 21:47:11 +0000431 if (!Name.empty() && Name.front() == '?') {
432 // Only do MSVC C++ demangling on symbols starting with '?'.
433 char DemangledName[1024] = {0};
434 DWORD result = ::UnDecorateSymbolName(
435 Name.c_str(), DemangledName, 1023,
436 UNDNAME_NO_ACCESS_SPECIFIERS | // Strip public, private, protected
437 UNDNAME_NO_ALLOCATION_LANGUAGE | // Strip __thiscall, __stdcall, etc
438 UNDNAME_NO_THROW_SIGNATURES | // Strip throw() specifications
439 UNDNAME_NO_MEMBER_TYPE | // Strip virtual, static, etc specifiers
440 UNDNAME_NO_MS_KEYWORDS | // Strip all MS extension keywords
441 UNDNAME_NO_FUNCTION_RETURNS); // Strip function return types
442 return (result == 0) ? Name : std::string(DemangledName);
443 }
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000444#endif
Reid Klecknerc25c7942015-08-10 21:47:11 +0000445 if (ModInfo->isWin32Module())
446 return std::string(demanglePE32ExternCFunc(Name));
447 return Name;
Alexey Samsonovea83baf2013-01-22 14:21:19 +0000448}
449
Alexey Samsonovd5d7bb52013-02-15 08:54:47 +0000450} // namespace symbolize
451} // namespace llvm