@@ -253,6 +253,122 @@ static bool printSymbolizedStackTrace(StringRef Argv0, void **StackTrace,
253253 return true ;
254254}
255255
256+ #if ENABLE_DEBUGLOC_ORIGIN_TRACKING
257+ void sys::symbolizeAddresses (AddressSet &Addresses,
258+ SymbolizedAddressMap &SymbolizedAddresses) {
259+ assert (!DisableSymbolicationFlag && !getenv (DisableSymbolizationEnv) &&
260+ " Debugify origin stacktraces require symbolization to be enabled." );
261+
262+ // Convert Set of Addresses to ordered list.
263+ SmallVector<void *, 0 > AddressList (Addresses.begin (), Addresses.end ());
264+ if (AddressList.empty ())
265+ return ;
266+ int NumAddresses = AddressList.size ();
267+ llvm::sort (AddressList);
268+
269+ // Use llvm-symbolizer tool to symbolize the stack traces. First look for it
270+ // alongside our binary, then in $PATH.
271+ ErrorOr<std::string> LLVMSymbolizerPathOrErr = std::error_code ();
272+ if (const char *Path = getenv (LLVMSymbolizerPathEnv)) {
273+ LLVMSymbolizerPathOrErr = sys::findProgramByName (Path);
274+ }
275+ if (!LLVMSymbolizerPathOrErr)
276+ LLVMSymbolizerPathOrErr = sys::findProgramByName (" llvm-symbolizer" );
277+ assert (!!LLVMSymbolizerPathOrErr &&
278+ " Debugify origin stacktraces require llvm-symbolizer." );
279+ const std::string &LLVMSymbolizerPath = *LLVMSymbolizerPathOrErr;
280+
281+ // Try to guess the main executable name, since we don't have argv0 available
282+ // here.
283+ std::string MainExecutableName = sys::fs::getMainExecutable (nullptr , nullptr );
284+
285+ BumpPtrAllocator Allocator;
286+ StringSaver StrPool (Allocator);
287+ std::vector<const char *> Modules (NumAddresses, nullptr );
288+ std::vector<intptr_t > Offsets (NumAddresses, 0 );
289+ if (!findModulesAndOffsets (AddressList.data (), NumAddresses, Modules.data (),
290+ Offsets.data (), MainExecutableName.c_str (),
291+ StrPool))
292+ return ;
293+ int InputFD;
294+ SmallString<32 > InputFile, OutputFile;
295+ sys::fs::createTemporaryFile (" symbolizer-input" , " " , InputFD, InputFile);
296+ sys::fs::createTemporaryFile (" symbolizer-output" , " " , OutputFile);
297+ FileRemover InputRemover (InputFile.c_str ());
298+ FileRemover OutputRemover (OutputFile.c_str ());
299+
300+ {
301+ raw_fd_ostream Input (InputFD, true );
302+ for (int i = 0 ; i < NumAddresses; i++) {
303+ if (Modules[i])
304+ Input << Modules[i] << " " << (void *)Offsets[i] << " \n " ;
305+ }
306+ }
307+
308+ std::optional<StringRef> Redirects[] = {InputFile.str (), OutputFile.str (),
309+ StringRef (" " )};
310+ StringRef Args[] = {" llvm-symbolizer" , " --functions=linkage" , " --inlining" ,
311+ #ifdef _WIN32
312+ // Pass --relative-address on Windows so that we don't
313+ // have to add ImageBase from PE file.
314+ // FIXME: Make this the default for llvm-symbolizer.
315+ " --relative-address" ,
316+ #endif
317+ " --demangle" };
318+ int RunResult =
319+ sys::ExecuteAndWait (LLVMSymbolizerPath, Args, std::nullopt , Redirects);
320+ if (RunResult != 0 )
321+ return ;
322+
323+ // This report format is based on the sanitizer stack trace printer. See
324+ // sanitizer_stacktrace_printer.cc in compiler-rt.
325+ auto OutputBuf = MemoryBuffer::getFile (OutputFile.c_str ());
326+ if (!OutputBuf)
327+ return ;
328+ StringRef Output = OutputBuf.get ()->getBuffer ();
329+ SmallVector<StringRef, 32 > Lines;
330+ Output.split (Lines, " \n " );
331+ auto CurLine = Lines.begin ();
332+ for (int i = 0 ; i < NumAddresses; i++) {
333+ assert (!SymbolizedAddresses.contains (AddressList[i]));
334+ std::string &SymbolizedAddr = SymbolizedAddresses[AddressList[i]];
335+ raw_string_ostream OS (SymbolizedAddr);
336+ if (!Modules[i]) {
337+ OS << format_ptr (AddressList[i]) << ' \n ' ;
338+ continue ;
339+ }
340+ // Read pairs of lines (function name and file/line info) until we
341+ // encounter empty line.
342+ for (bool IsFirst = true ;; IsFirst = false ) {
343+ if (CurLine == Lines.end ())
344+ return ;
345+ StringRef FunctionName = *CurLine++;
346+ if (FunctionName.empty ())
347+ break ;
348+ // Add indentation for lines after the first; we use 3 spaces, because
349+ // currently that aligns with the expected indentation that will be added
350+ // to the first line by Debugify.
351+ if (!IsFirst)
352+ OS << " " ;
353+ OS << format_ptr (AddressList[i]) << ' ' ;
354+ if (!FunctionName.starts_with (" ??" ))
355+ OS << FunctionName << ' ' ;
356+ if (CurLine == Lines.end ()) {
357+ OS << ' \n ' ;
358+ return ;
359+ }
360+ StringRef FileLineInfo = *CurLine++;
361+ if (!FileLineInfo.starts_with (" ??" ))
362+ OS << FileLineInfo;
363+ else
364+ OS << " (" << Modules[i] << ' +' << format_hex (Offsets[i], 0 ) << " )" ;
365+ OS << ' \n ' ;
366+ }
367+ }
368+ return ;
369+ }
370+ #endif
371+
256372static bool printMarkupContext (raw_ostream &OS, const char *MainExecutableName);
257373
258374LLVM_ATTRIBUTE_USED
0 commit comments