Просмотр исходного кода

Add flag to dump the raw SemIR in the event of a crash. (#6558)

Geoff Romer 3 месяцев назад
Родитель
Сommit
2380be2ae1

+ 22 - 0
toolchain/check/check.cpp

@@ -9,6 +9,7 @@
 
 #include "common/check.h"
 #include "common/map.h"
+#include "common/pretty_stack_trace_function.h"
 #include "toolchain/check/check_unit.h"
 #include "toolchain/check/context.h"
 #include "toolchain/check/cpp/import.h"
@@ -417,6 +418,27 @@ auto CheckParseTrees(
             &unit, tree_and_subtrees_getters.Get(unit.sem_ir->check_ir_id()));
       }));
 
+  // Dump the raw SemIR in the event of a crash. We dump it to a separate file
+  // to keep the stack trace manageable.
+  PrettyStackTraceFunction sem_ir_dumper([&](llvm::raw_ostream& output) {
+    if (!options.sem_ir_crash_dump.empty()) {
+      output << "Dumping raw SemIR to " << options.sem_ir_crash_dump << "\n";
+      std::error_code error_code;
+      llvm::raw_fd_ostream sem_ir_dump(options.sem_ir_crash_dump, error_code);
+      if (error_code) {
+        output << "Raw SemIR dump failed: " << error_code.category().name()
+               << ":" << error_code.value() << ": " << error_code.message()
+               << "\n";
+      } else {
+        for (const auto& unit_info : unit_infos) {
+          if (unit_info.is_checked && unit_info.unit->sem_ir != nullptr) {
+            unit_info.unit->sem_ir->Print(sem_ir_dump);
+          }
+        }
+      }
+    }
+  });
+
   Map<ImportKey, UnitAndImports*> api_map =
       BuildApiMapAndDiagnosePackaging(unit_infos);
 

+ 4 - 0
toolchain/check/check.h

@@ -70,6 +70,10 @@ struct CheckParseTreesOptions {
 
   // When dumping raw SemIR, whether to include builtins.
   bool dump_raw_sem_ir_builtins = false;
+
+  // If not empty, a raw SemIR dump should be written to this path in the event
+  // of a crash.
+  llvm::StringRef sem_ir_crash_dump;
 };
 
 // Checks a group of parse trees. This will use imports to decide the order of

+ 8 - 0
toolchain/docs/adding_features.md

@@ -628,6 +628,10 @@ minimal context for how the current function is reached, we use LLVM's
 `PrettyStackTrace` to include details about the state stack. The state stack
 will be above the function stack in crash output.
 
+You can also use the `--sem-ir-crash-dump=path/to/file` flag to get a raw SemIR
+dump in the event of a crash in the check phase. This can be particularly useful
+for interpreting IDs you encounter during interactive debugging.
+
 #### Dumping objects in interactive debuggers
 
 We provide namespace-scoped `Dump` functions in several components, such as
@@ -638,6 +642,10 @@ regarding support.
 Objects which inherit from `Printable` also have `Dump` member functions, but
 these will lack contextual information.
 
+IDs are dumped in hexadecimal, so it's often convenient to set your interactive
+debugger to print integers in hexadecimal as well. In LLDB you can do this with
+`type format add --format hex int`.
+
 #### Dumping prelude files
 
 By default, prelude files are excluded from dumps by

+ 11 - 0
toolchain/driver/compile_subcommand.cpp

@@ -369,6 +369,16 @@ Whether to run the LLVM verifier on modules.
         arg_b.Default(true);
         arg_b.Set(&run_llvm_verifier);
       });
+  b.AddStringOption(
+      {
+          .name = "sem-ir-crash-dump",
+          .value_name = "PATH",
+          .help = R"""(
+Where to write a dump of the raw SemIR emitted so far, in the event of a crash
+in the check phase. If empty, the dump is not written.
+)""",
+      },
+      [&](auto& arg_b) { arg_b.Set(&sem_ir_crash_dump); });
 }
 
 static constexpr CommandLine::CommandInfo SubcommandInfo = {
@@ -1240,6 +1250,7 @@ auto CompileSubcommand::Run(DriverEnv& driver_env) -> DriverResult {
       options.raw_dump_stream = driver_env.output_stream;
       options.dump_raw_sem_ir_builtins = options_.builtin_sem_ir;
     }
+    options.sem_ir_crash_dump = options_.sem_ir_crash_dump;
   }
   Check::CheckParseTrees(check_units, cache.tree_and_subtrees_getters(),
                          driver_env.fs, options, clang_invocation);

+ 2 - 0
toolchain/driver/compile_subcommand.h

@@ -68,6 +68,8 @@ struct CompileOptions {
   bool run_llvm_verifier = true;
 
   llvm::SmallVector<llvm::StringRef> exclude_dump_file_prefixes;
+
+  llvm::StringRef sem_ir_crash_dump;
 };
 
 // Implements the compile subcommand of the driver.