| // Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| #ifndef RUNTIME_VM_CODEVIEW_H_ | |
| #define RUNTIME_VM_CODEVIEW_H_ | |
| #include "platform/globals.h" | |
| #if defined(DART_PRECOMPILER) | |
| #include "platform/coff.h" | |
| #include "vm/allocation.h" | |
| #include "vm/growable_array.h" | |
| #include "vm/object.h" | |
| #include "vm/zone.h" | |
| namespace dart { | |
| class CoffWriter; | |
| class DebugInfoStream; | |
| // Translates the Dart debug metadata into Microsoft CodeView records embedded | |
| // in .debug$S (symbols + line numbers) and .debug$T (types). The output is | |
| // designed so that `link.exe /DEBUG` synthesizes a Microsoft .pdb compatible | |
| // with WinDbg / Visual Studio. | |
| // | |
| // Owned by CoffWriter; appends bytes and relocations directly into the | |
| // CoffWriter's .debug$S / .debug$T sections. | |
| class CodeViewBuilder : public ZoneObject { | |
| public: | |
| CodeViewBuilder(Zone* zone, | |
| CoffWriter* writer, | |
| DebugInfoStream* debug_s, | |
| DebugInfoStream* debug_t); | |
| // Populate the .debug$S and .debug$T sections. Caller (CoffWriter::Finalize) | |
| // must have created both sections before calling. | |
| void Build(); | |
| private: | |
| // Per-function CodeView metadata. | |
| struct FunctionInfo { | |
| const char* name = nullptr; | |
| intptr_t label = 0; // VM-internal label registered with debug info/Coff | |
| uint32_t func_id_type = 0; // LF_FUNC_ID type index | |
| }; | |
| // .debug$T helpers. | |
| void EmitTypeRecords(); | |
| // .debug$S helpers. | |
| void EmitObjectAndCompileSymbolsSubsection(); | |
| void EmitFunctionSymbolsSubsection(const FunctionInfo& fn, const Code& code); | |
| void EmitLinesSubsection(const FunctionInfo& fn, const Code& code); | |
| void EmitFileChecksumsSubsection(); | |
| void EmitStringTableSubsection(); | |
| void GatherFunctions(); | |
| void ComputeScriptTables(); | |
| void EmitOneFunctionSymbol(const FunctionInfo& fn, const Code& code); | |
| // Returns a zone-owned, NUL-terminated path string for `script`, honoring | |
| // --resolve-dwarf-paths and the obfuscation trie. | |
| const char* ResolvedScriptUri(const Script& script); | |
| Zone* const zone_; | |
| // CodeViewBuilder is allocated and used synchronously by | |
| // CoffWriter::EmitCodeView() during CoffWriter::Finalize(). The CoffWriter | |
| // and the debug streams owned by its .debug$S/.debug$T Sections therefore | |
| // remain valid for the builder's lifetime, before the sections are laid out | |
| // and written. | |
| CoffWriter* const writer_; | |
| DebugInfoStream* const debugS_; | |
| DebugInfoStream* const debugT_; | |
| ZoneGrowableArray<FunctionInfo>* functions_; | |
| // Parallel arrays indexed by debug script index. Computed | |
| // by ComputeScriptTables() so EmitLines can stamp checksum-offsets directly | |
| // into CV_LINE_BLOCK headers. | |
| ZoneGrowableArray<uint32_t>* script_string_offsets_; | |
| ZoneGrowableArray<uint32_t>* script_checksum_offsets_; | |
| // The next available LF_* type index (CodeView starts user types at 0x1000). | |
| uint32_t next_type_index_ = 0x1000; | |
| uint32_t arglist_type_ = 0; | |
| uint32_t procedure_type_ = 0; | |
| DISALLOW_COPY_AND_ASSIGN(CodeViewBuilder); | |
| }; | |
| } // namespace dart | |
| #endif // DART_PRECOMPILER | |
| #endif // RUNTIME_VM_CODEVIEW_H_ |