// Re-export this as clang::driver::ArgStringList.
using llvm::opt::ArgStringList;
+struct CrashReportInfo {
+ StringRef Filename;
+ StringRef VFSPath;
+
+ CrashReportInfo(StringRef Filename, StringRef VFSPath)
+ : Filename(Filename), VFSPath(VFSPath) {}
+};
+
class Job {
public:
enum JobClass {
/// \param OS - The stream to print on.
/// \param Terminator - A string to print at the end of the line.
/// \param Quote - Should separate arguments be quoted.
- /// \param CrashReport - Whether to print for inclusion in a crash report.
- virtual void Print(llvm::raw_ostream &OS, const char *Terminator,
- bool Quote, bool CrashReport = false) const = 0;
+ /// \param CrashInfo - Details for inclusion in a crash report.
+ virtual void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote,
+ CrashReportInfo *CrashInfo = nullptr) const = 0;
};
/// Command - An executable path/name and argument vector to
const llvm::opt::ArgStringList &_Arguments);
void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote,
- bool CrashReport = false) const override;
+ CrashReportInfo *CrashInfo = nullptr) const override;
virtual int Execute(const StringRef **Redirects, std::string *ErrMsg,
bool *ExecutionFailed) const;
std::unique_ptr<Command> Fallback_);
void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote,
- bool CrashReport = false) const override;
+ CrashReportInfo *CrashInfo = nullptr) const override;
int Execute(const StringRef **Redirects, std::string *ErrMsg,
bool *ExecutionFailed) const override;
virtual ~JobList() {}
void Print(llvm::raw_ostream &OS, const char *Terminator,
- bool Quote, bool CrashReport = false) const override;
+ bool Quote, CrashReportInfo *CrashInfo = nullptr) const override;
/// Add a job to the list (taking ownership).
void addJob(std::unique_ptr<Job> J) { Jobs.push_back(std::move(J)); }
CCGenDiagnostics = true;
// Save the original job command(s).
- std::string Cmd;
- llvm::raw_string_ostream OS(Cmd);
- FailingCommand.Print(OS, "\n", /*Quote*/ false, /*CrashReport*/ true);
- OS.flush();
+ Command Cmd = FailingCommand;
// Keep track of whether we produce any errors while trying to produce
// preprocessed sources.
}
// Assume associated files are based off of the first temporary file.
- const char *MainFile = TempFiles[0];
+ CrashReportInfo CrashInfo(TempFiles[0], VFS);
- std::string Script = StringRef(MainFile).rsplit('.').first.str() + ".sh";
+ std::string Script = CrashInfo.Filename.rsplit('.').first.str() + ".sh";
std::error_code EC;
llvm::raw_fd_ostream ScriptOS(Script, EC, llvm::sys::fs::F_Excl);
if (EC) {
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "Error generating run script: " + Script + " " + EC.message();
} else {
- // Replace the original filename with the preprocessed one.
- size_t I, E;
- I = Cmd.find("-main-file-name ");
- assert(I != std::string::npos && "Expected to find -main-file-name");
- I += 16;
- E = Cmd.find(" ", I);
- assert(E != std::string::npos && "-main-file-name missing argument?");
- StringRef OldFilename = StringRef(Cmd).slice(I, E);
- StringRef NewFilename = llvm::sys::path::filename(MainFile);
- I = StringRef(Cmd).rfind(OldFilename);
- E = I + OldFilename.size();
- if (E + 1 < Cmd.size() && Cmd[E] == '"')
- ++E; // Replace a trailing quote if present.
- I = Cmd.rfind(" ", I) + 1;
- Cmd.replace(I, E - I, NewFilename.data(), NewFilename.size());
- if (!VFS.empty()) {
- // Add the VFS overlay to the reproduction script.
- I += NewFilename.size();
- Cmd.insert(I, std::string(" -ivfsoverlay ") + VFS.c_str());
- }
- ScriptOS << Cmd;
+ Cmd.Print(ScriptOS, "\n", /*Quote=*/false, &CrashInfo);
Diag(clang::diag::note_drv_command_failed_diag_msg) << Script;
}
Diag(clang::diag::note_drv_command_failed_diag_msg)
}
void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
- bool CrashReport) const {
+ CrashReportInfo *CrashInfo) const {
// Always quote the exe.
OS << ' ';
PrintArg(OS, Executable, /*Quote=*/true);
Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name
}
+ StringRef MainFilename;
+ // We'll need the argument to -main-file-name to find the input file name.
+ if (CrashInfo)
+ for (size_t I = 0, E = Args.size(); I + 1 < E; ++I)
+ if (StringRef(Args[I]).equals("-main-file-name"))
+ MainFilename = Args[I + 1];
+
for (size_t i = 0, e = Args.size(); i < e; ++i) {
const char *const Arg = Args[i];
- if (CrashReport) {
+ if (CrashInfo) {
if (int Skip = skipArgs(Arg)) {
i += Skip - 1;
continue;
+ } else if (llvm::sys::path::filename(Arg) == MainFilename &&
+ (i == 0 || StringRef(Args[i - 1]) != "-main-file-name")) {
+ // Replace the input file name with the crashinfo's file name.
+ OS << ' ';
+ StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename);
+ PrintArg(OS, ShortName.str().c_str(), Quote);
+ continue;
}
}
OS << ' ';
PrintArg(OS, Arg, Quote);
- if (CrashReport && quoteNextArg(Arg) && i + 1 < e) {
+ if (CrashInfo && quoteNextArg(Arg) && i + 1 < e) {
OS << ' ';
PrintArg(OS, Args[++i], true);
}
}
+ if (CrashInfo && !CrashInfo->VFSPath.empty()) {
+ OS << ' ';
+ PrintArg(OS, "-ivfsoverlay", Quote);
+ OS << ' ';
+ PrintArg(OS, CrashInfo->VFSPath.str().c_str(), Quote);
+ }
+
if (ResponseFile != nullptr) {
OS << "\n Arguments passed via response file:\n";
writeResponseFile(OS);
Fallback(std::move(Fallback_)) {}
void FallbackCommand::Print(raw_ostream &OS, const char *Terminator,
- bool Quote, bool CrashReport) const {
- Command::Print(OS, "", Quote, CrashReport);
+ bool Quote, CrashReportInfo *CrashInfo) const {
+ Command::Print(OS, "", Quote, CrashInfo);
OS << " ||";
- Fallback->Print(OS, Terminator, Quote, CrashReport);
+ Fallback->Print(OS, Terminator, Quote, CrashInfo);
}
static bool ShouldFallback(int ExitCode) {
JobList::JobList() : Job(JobListClass) {}
void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote,
- bool CrashReport) const {
+ CrashReportInfo *CrashInfo) const {
for (const auto &Job : *this)
- Job.Print(OS, Terminator, Quote, CrashReport);
+ Job.Print(OS, Terminator, Quote, CrashInfo);
}
void JobList::clear() { Jobs.clear(); }