15#if defined(DART_PRECOMPILER)
20 "Resolve script URIs to absolute or relative file paths in DWARF");
23 write_code_comments_as_synthetic_source_to,
25 "Print comments associated with instructions into the given file");
29 DwarfPosition(int32_t
line, int32_t column) : line_(
line), column_(column) {
31 ASSERT(line_ > kNoLine || column_ <= kNoColumn);
35 explicit DwarfPosition(int32_t
line) : DwarfPosition(
line, -1) {}
36 constexpr DwarfPosition() : line_(-1), column_(-1) {}
40 static constexpr int32_t kNoLine = 0;
41 static constexpr int32_t kNoColumn = 0;
43 int32_t
line()
const {
return line_ > kNoLine ? line_ : kNoLine; }
44 int32_t column()
const {
return column_ > kNoColumn ? column_ : kNoColumn; }
48 void ChangePosition(int32_t line_delta, int32_t new_column) {
58static constexpr auto kNoDwarfPositionInfo = DwarfPosition();
60class InliningNode :
public ZoneAllocated {
62 InliningNode(
const Function&
function,
63 const DwarfPosition& position,
64 int32_t start_pc_offset)
67 start_pc_offset(start_pc_offset),
69 children_head(nullptr),
70 children_tail(nullptr),
71 children_next(nullptr) {
76 void AppendChild(InliningNode* child) {
77 if (children_tail ==
nullptr) {
78 children_head = children_tail = child;
80 children_tail->children_next = child;
81 children_tail = child;
86 DwarfPosition position;
87 int32_t start_pc_offset;
88 int32_t end_pc_offset;
89 InliningNode* children_head;
90 InliningNode* children_tail;
91 InliningNode* children_next;
94Dwarf::Dwarf(Zone* zone,
const Trie<const char>* deobfuscation_trie)
96 deobfuscation_trie_(deobfuscation_trie),
99 functions_(zone, 1024),
100 function_to_index_(zone),
101 scripts_(zone, 1024),
102 script_to_index_(zone) {}
104void Dwarf::AddCode(
const Code& orig_code, intptr_t label) {
105 ASSERT(!orig_code.IsNull());
108 if (
auto const old_pair = code_to_label_.Lookup(&orig_code)) {
117 const auto&
code = Code::ZoneHandle(zone_, orig_code.ptr());
121 code_to_label_.Insert({&
code, label});
123 if (
code.IsFunctionCode() && !
code.IsUnknownDartCode()) {
124 const Function&
function = Function::Handle(zone_,
code.function());
127 const Array& inline_functions =
128 Array::Handle(zone_,
code.inlined_id_to_function());
129 if (!inline_functions.IsNull()) {
130 Function&
function = Function::Handle(zone_);
131 for (intptr_t
i = 0;
i < inline_functions.Length();
i++) {
138intptr_t Dwarf::AddFunction(
const Function&
function) {
140 FunctionIndexPair* pair = function_to_index_.Lookup(&
function);
141 if (pair !=
nullptr) {
144 intptr_t index = functions_.length();
145 const Function& zone_func = Function::ZoneHandle(zone_,
function.ptr());
146 function_to_index_.Insert(FunctionIndexPair(&zone_func, index));
147 functions_.Add(&zone_func);
153intptr_t Dwarf::AddScript(
const Script&
script) {
155 ScriptIndexPair* pair = script_to_index_.Lookup(&
script);
156 if (pair !=
nullptr) {
160 intptr_t index = scripts_.length() + 1;
161 const Script& zone_script = Script::ZoneHandle(zone_,
script.ptr());
162 script_to_index_.Insert(ScriptIndexPair(&zone_script, index));
163 scripts_.Add(&zone_script);
167intptr_t Dwarf::LookupFunction(
const Function&
function) {
169 FunctionIndexPair* pair = function_to_index_.Lookup(&
function);
170 if (pair ==
nullptr) {
171 FATAL(
"Function detected too late during DWARF generation: %s",
177intptr_t Dwarf::LookupScript(
const Script&
script) {
179 ScriptIndexPair* pair = script_to_index_.Lookup(&
script);
180 if (pair ==
nullptr) {
181 FATAL(
"Script detected too late during DWARF generation: %s",
187void Dwarf::WriteAbbreviations(DwarfWriteStream*
stream) {
192 stream->uleb128(kCompilationUnit);
193 stream->uleb128(DW_TAG_compile_unit);
194 stream->u1(DW_CHILDREN_yes);
195 stream->uleb128(DW_AT_name);
196 stream->uleb128(DW_FORM_string);
197 stream->uleb128(DW_AT_producer);
198 stream->uleb128(DW_FORM_string);
199 stream->uleb128(DW_AT_comp_dir);
200 stream->uleb128(DW_FORM_string);
201 stream->uleb128(DW_AT_low_pc);
202 stream->uleb128(DW_FORM_addr);
203 stream->uleb128(DW_AT_high_pc);
204 stream->uleb128(DW_FORM_addr);
205 stream->uleb128(DW_AT_stmt_list);
206 stream->uleb128(DW_FORM_sec_offset);
210 stream->uleb128(kAbstractFunction);
211 stream->uleb128(DW_TAG_subprogram);
212 stream->u1(DW_CHILDREN_yes);
213 stream->uleb128(DW_AT_name);
214 stream->uleb128(DW_FORM_string);
215 stream->uleb128(DW_AT_decl_file);
216 stream->uleb128(DW_FORM_udata);
217 stream->uleb128(DW_AT_inline);
218 stream->uleb128(DW_FORM_udata);
222 stream->uleb128(kConcreteFunction);
223 stream->uleb128(DW_TAG_subprogram);
224 stream->u1(DW_CHILDREN_yes);
225 stream->uleb128(DW_AT_abstract_origin);
226 stream->uleb128(DW_FORM_ref4);
227 stream->uleb128(DW_AT_low_pc);
228 stream->uleb128(DW_FORM_addr);
229 stream->uleb128(DW_AT_high_pc);
230 stream->uleb128(DW_FORM_addr);
231 stream->uleb128(DW_AT_artificial);
232 stream->uleb128(DW_FORM_flag);
236 stream->uleb128(kInlinedFunction);
237 stream->uleb128(DW_TAG_inlined_subroutine);
238 stream->u1(DW_CHILDREN_yes);
239 stream->uleb128(DW_AT_abstract_origin);
240 stream->uleb128(DW_FORM_ref4);
241 stream->uleb128(DW_AT_low_pc);
242 stream->uleb128(DW_FORM_addr);
243 stream->uleb128(DW_AT_high_pc);
244 stream->uleb128(DW_FORM_addr);
245 stream->uleb128(DW_AT_call_file);
246 stream->uleb128(DW_FORM_udata);
247 stream->uleb128(DW_AT_call_line);
248 stream->uleb128(DW_FORM_udata);
249 stream->uleb128(DW_AT_call_column);
250 stream->uleb128(DW_FORM_udata);
251 stream->uleb128(DW_AT_artificial);
252 stream->uleb128(DW_FORM_flag);
259void Dwarf::WriteDebugInfo(DwarfWriteStream*
stream) {
263 stream->WritePrefixedLength(
"cu", [&]() {
271 stream->uleb128(kCompilationUnit);
272 const Library& root_library = Library::Handle(
273 zone_, IsolateGroup::Current()->object_store()->root_library());
274 const String& root_uri = String::Handle(zone_, root_library.url());
275 stream->string(root_uri.ToCString());
276 stream->string(
"Dart VM");
283 auto const isolate_instructions_label = ImageWriter::SectionLabel(
284 ImageWriter::ProgramSection::Text,
false);
285 stream->OffsetFromSymbol(isolate_instructions_label, 0);
291 if (codes_.is_empty()) {
293 stream->OffsetFromSymbol(isolate_instructions_label, 0);
295 const Code& last_code = *codes_.Last();
296 auto const last_code_label = code_to_label_.LookupValue(&last_code);
297 ASSERT(last_code_label > 0);
298 stream->OffsetFromSymbol(last_code_label, last_code.Size());
306 WriteAbstractFunctions(
stream);
307 WriteConcreteFunctions(
stream);
315void Dwarf::WriteAbstractFunctions(DwarfWriteStream*
stream) {
316 Script&
script = Script::Handle(zone_);
317 String&
name = String::Handle(zone_);
318 stream->InitializeAbstractOrigins(functions_.length());
322 for (intptr_t
i = 0;
i < functions_.length();
i++) {
323 const Function&
function = *(functions_[
i]);
327 auto const name_cstr =
328 ImageWriter::Deobfuscate(zone_, deobfuscation_trie_,
name.ToCString());
330 stream->RegisterAbstractOrigin(
i);
331 stream->uleb128(kAbstractFunction);
332 stream->string(name_cstr);
334 stream->uleb128(DW_INL_inlined);
339void Dwarf::WriteConcreteFunctions(DwarfWriteStream*
stream) {
340 Function&
function = Function::Handle(zone_);
341 Script&
script = Script::Handle(zone_);
342 for (intptr_t
i = 0;
i < codes_.length();
i++) {
343 const Code&
code = *(codes_[
i]);
345 if (!
code.IsFunctionCode() ||
code.IsUnknownDartCode()) {
350 intptr_t function_index = LookupFunction(
function);
352 intptr_t label = code_to_label_.LookupValue(&
code);
355 stream->uleb128(kConcreteFunction);
358 stream->AbstractOrigin(function_index);
361 stream->OffsetFromSymbol(label, 0);
367 InliningNode* node = ExpandInliningTree(
code);
368 if (node !=
nullptr) {
369 for (InliningNode* child = node->children_head; child !=
nullptr;
370 child = child->children_next) {
383InliningNode* Dwarf::ExpandInliningTree(
const Code&
code) {
384 const CodeSourceMap&
map =
385 CodeSourceMap::Handle(zone_,
code.code_source_map());
389 const Array& functions = Array::Handle(zone_,
code.inlined_id_to_function());
390 const Function& root_function = Function::ZoneHandle(zone_,
code.function());
391 if (root_function.IsNull()) {
392 FATAL(
"Wherefore art thou functionless code, %s?\n",
code.ToCString());
395 GrowableArray<InliningNode*> node_stack(zone_, 4);
396 GrowableArray<DwarfPosition> token_positions(zone_, 4);
398 NoSafepointScope no_safepoint;
401 int32_t current_pc_offset = 0;
402 token_positions.Add(kNoDwarfPositionInfo);
403 InliningNode* root_node =
404 new (zone_) InliningNode(root_function, token_positions.Last(), 0);
405 root_node->end_pc_offset =
code.Size();
406 node_stack.Add(root_node);
408 while (
stream.PendingBytes() > 0) {
413 case CodeSourceMapOps::kChangePosition: {
414 DwarfPosition&
pos = token_positions[token_positions.length() - 1];
415 pos.ChangePosition(arg1, arg2);
418 case CodeSourceMapOps::kAdvancePC: {
419 current_pc_offset += arg1;
426 current_pc_offset += 1;
430 case CodeSourceMapOps::kPushFunction: {
431 const Function& child_func =
432 Function::ZoneHandle(zone_, Function::RawCast(functions.At(arg1)));
433 InliningNode* child_node =
new (zone_)
434 InliningNode(child_func, token_positions.Last(), current_pc_offset);
435 node_stack.Last()->AppendChild(child_node);
436 node_stack.Add(child_node);
437 token_positions.Add(kNoDwarfPositionInfo);
440 case CodeSourceMapOps::kPopFunction: {
442 ASSERT(node_stack.length() > 1);
443 ASSERT(token_positions.length() > 1);
444 node_stack.Last()->end_pc_offset = current_pc_offset;
445 node_stack.RemoveLast();
446 token_positions.RemoveLast();
449 case CodeSourceMapOps::kNullCheck: {
457 while (node_stack.length() > 1) {
458 node_stack.Last()->end_pc_offset = current_pc_offset;
459 node_stack.RemoveLast();
460 token_positions.RemoveLast();
462 ASSERT(node_stack[0] == root_node);
466void Dwarf::WriteInliningNode(DwarfWriteStream*
stream,
469 const Script& parent_script) {
471 intptr_t
file = LookupScript(parent_script);
472 intptr_t function_index = LookupFunction(node->function);
473 const Script&
script = Script::Handle(zone_, node->function.script());
475 stream->uleb128(kInlinedFunction);
478 stream->AbstractOrigin(function_index);
481 stream->OffsetFromSymbol(root_label, node->start_pc_offset);
483 stream->OffsetFromSymbol(root_label, node->end_pc_offset);
488 stream->uleb128(node->position.line());
490 stream->uleb128(node->position.column());
492 stream->u1(node->function.is_visible() ? 0 : 1);
494 for (InliningNode* child = node->children_head; child !=
nullptr;
495 child = child->children_next) {
505class LineNumberProgramWriter {
507 explicit LineNumberProgramWriter(DwarfWriteStream*
stream)
510 void EmitRow(intptr_t
file,
514 intptr_t pc_offset) {
515 if (AddRow(
file,
line, column, label, pc_offset)) {
518 stream_->u1(Dwarf::DW_LNS_copy);
529 intptr_t pc_offset) {
531 bool source_info_changed =
false;
535 stream_->u1(Dwarf::DW_LNS_set_file);
536 stream_->uleb128(
file);
538 source_info_changed =
true;
542 stream_->u1(Dwarf::DW_LNS_advance_line);
543 stream_->sleb128(
line - line_);
545 source_info_changed =
true;
547 ASSERT(column >= DwarfPosition::kNoColumn);
548 if (column != column_) {
549 stream_->u1(Dwarf::DW_LNS_set_column);
550 stream_->uleb128(column);
552 source_info_changed =
true;
558 if (source_info_changed) {
559 SetCurrentPosition(label, pc_offset);
561 return source_info_changed;
569 stream_->u1(Dwarf::DW_LNE_end_sequence);
570 end_sequence_ =
true;
573 void MarkEnd(intptr_t label, intptr_t pc_offset) {
575 SetCurrentPosition(label, pc_offset);
580 void SetCurrentPosition(intptr_t label, intptr_t pc_offset) {
585 ASSERT(label_ != label || pc_offset > pc_offset_);
586 if (label_ != label) {
590 stream_->u1(instr_size);
591 stream_->u1(Dwarf::DW_LNE_set_address);
592 stream_->OffsetFromSymbol(label, pc_offset);
595 stream_->u1(Dwarf::DW_LNS_advance_pc);
596 stream_->uleb128(pc_offset - pc_offset_);
599 pc_offset_ = pc_offset;
602 DwarfWriteStream*
const stream_;
605 intptr_t pc_offset_ = 0;
608 intptr_t column_ = 0;
609 bool end_sequence_ =
false;
615void Dwarf::WriteSyntheticLineNumberProgram(LineNumberProgramWriter* writer) {
617 const intptr_t comments_file_index = scripts_.length() + 1;
619 auto file_open = Dart::file_open_callback();
620 auto file_write = Dart::file_write_callback();
621 auto file_close = Dart::file_close_callback();
622 if ((file_open ==
nullptr) || (file_write ==
nullptr) ||
623 (file_close ==
nullptr)) {
624 OS::PrintErr(
"warning: Could not access file callbacks.");
628 TextBuffer comments_buffer(128 *
KB);
630 const char* filename = FLAG_write_code_comments_as_synthetic_source_to;
631 void* comments_file = file_open(filename,
true);
632 if (comments_file ==
nullptr) {
633 OS::PrintErr(
"warning: Failed to write code comments source: %s\n",
639 intptr_t current_line = 1;
641 for (intptr_t
i = 0;
i < codes_.length();
i++) {
642 const Code&
code = *(codes_[
i]);
643 auto const label = code_to_label_.LookupValue(&
code);
646 auto& comments =
code.comments();
647 for (intptr_t
i = 0,
len = comments.Length();
i <
len;) {
648 intptr_t current_pc_offset = comments.PCOffsetAt(
i);
649 while (
i <
len && current_pc_offset == comments.PCOffsetAt(
i)) {
650 comments_buffer.AddString(comments.CommentAt(
i));
651 comments_buffer.AddChar(
'\n');
655 writer->EmitRow(comments_file_index, current_line - 1,
656 DwarfPosition::kNoColumn, label, current_pc_offset);
660 file_write(comments_buffer.buffer(), comments_buffer.length(), comments_file);
661 file_close(comments_file);
664void Dwarf::WriteLineNumberProgramFromCodeSourceMaps(
665 LineNumberProgramWriter* writer) {
666 Function& root_function = Function::Handle(zone_);
667 Script&
script = Script::Handle(zone_);
668 CodeSourceMap&
map = CodeSourceMap::Handle(zone_);
669 Array& functions = Array::Handle(zone_);
670 GrowableArray<const Function*> function_stack(zone_, 8);
671 GrowableArray<DwarfPosition> token_positions(zone_, 8);
673 for (intptr_t
i = 0;
i < codes_.length();
i++) {
674 const Code&
code = *(codes_[
i]);
675 auto const label = code_to_label_.LookupValue(&
code);
682 root_function =
code.function();
683 functions =
code.inlined_id_to_function();
685 NoSafepointScope no_safepoint;
686 ReadStream code_map_stream(
map.Data(),
map.Length());
688 function_stack.Clear();
689 token_positions.Clear();
709 bool function_entry_position_was_emitted =
false;
711 int32_t current_pc_offset = 0;
712 function_stack.Add(&root_function);
713 token_positions.Add(kNoDwarfPositionInfo);
715 while (code_map_stream.PendingBytes() > 0) {
718 const uint8_t opcode =
721 case CodeSourceMapOps::kChangePosition: {
722 DwarfPosition&
pos = token_positions[token_positions.length() - 1];
723 pos.ChangePosition(arg1, arg2);
726 case CodeSourceMapOps::kAdvancePC: {
729 const Function&
function = *(function_stack.Last());
732 const intptr_t
line = token_positions.Last().line();
733 const intptr_t column = token_positions.Last().column();
734 intptr_t pc_offset_adjustment = 0;
735 bool should_emit =
true;
740 if (current_pc_offset == 0 && function_entry_position_was_emitted) {
741 pc_offset_adjustment = 1;
744 should_emit = !(
line == 0 && column == 0);
748 writer->EmitRow(
file,
line, column, label,
749 current_pc_offset + pc_offset_adjustment);
752 current_pc_offset += arg1;
754 ASSERT(current_pc_offset == 0);
755 ASSERT(!function_entry_position_was_emitted);
756 function_entry_position_was_emitted =
true;
760 case CodeSourceMapOps::kPushFunction: {
762 &Function::Handle(zone_, Function::RawCast(functions.At(arg1)));
763 function_stack.Add(child_func);
764 token_positions.Add(kNoDwarfPositionInfo);
767 case CodeSourceMapOps::kPopFunction: {
769 ASSERT(function_stack.length() > 1);
770 ASSERT(token_positions.length() > 1);
771 function_stack.RemoveLast();
772 token_positions.RemoveLast();
775 case CodeSourceMapOps::kNullCheck: {
785static constexpr char kResolvedFileRoot[] =
"file:///";
786static constexpr intptr_t kResolvedFileRootLen =
sizeof(kResolvedFileRoot) - 1;
787static constexpr char kResolvedFlutterRoot[] =
"org-dartlang-sdk:///flutter/";
788static constexpr intptr_t kResolvedFlutterRootLen =
789 sizeof(kResolvedFlutterRoot) - 1;
790static constexpr char kResolvedSdkRoot[] =
"org-dartlang-sdk:///";
791static constexpr intptr_t kResolvedSdkRootLen =
sizeof(kResolvedSdkRoot) - 1;
792static constexpr char kResolvedGoogle3Root[] =
"google3:///";
793static constexpr intptr_t kResolvedGoogle3RootLen =
794 sizeof(kResolvedGoogle3Root) - 1;
796static const char* ConvertResolvedURI(
const char* str) {
797 const intptr_t
len = strlen(str);
798 if (
len > kResolvedFileRootLen &&
799 strncmp(str, kResolvedFileRoot, kResolvedFileRootLen) == 0) {
800#if defined(DART_HOST_OS_WINDOWS)
801 return str + kResolvedFileRootLen;
803 return str + kResolvedFileRootLen - 1;
808 if (
len > kResolvedFlutterRootLen &&
809 strncmp(str, kResolvedFlutterRoot, kResolvedFlutterRootLen) == 0) {
810 return str + kResolvedFlutterRootLen;
812 if (
len > kResolvedSdkRootLen &&
813 strncmp(str, kResolvedSdkRoot, kResolvedSdkRootLen) == 0) {
814 return str + kResolvedSdkRootLen;
816 if (
len > kResolvedGoogle3RootLen &&
817 strncmp(str, kResolvedGoogle3Root, kResolvedGoogle3RootLen) == 0) {
818 return str + kResolvedGoogle3RootLen;
823void Dwarf::WriteLineNumberProgram(DwarfWriteStream*
stream) {
827 stream->WritePrefixedLength(
"line", [&]() {
831 stream->WritePrefixedLength(
"lineheader", [&]() {
857 String& uri = String::Handle(zone_);
858 for (intptr_t
i = 0;
i < scripts_.length();
i++) {
859 const Script&
script = *(scripts_[
i]);
860 const char* uri_cstr =
nullptr;
861 if (FLAG_resolve_dwarf_paths) {
862 uri =
script.resolved_url();
865 FATAL(
"no resolved URI for Script %s available",
869 auto const orig_cstr = uri.ToCString();
870 auto const converted_cstr = ConvertResolvedURI(orig_cstr);
872 if (converted_cstr ==
nullptr) {
873 FATAL(
"cannot convert resolved URI %s", orig_cstr);
875 uri_cstr = converted_cstr;
879 uri_cstr = ImageWriter::Deobfuscate(zone_, deobfuscation_trie_,
889 if (FLAG_write_code_comments_as_synthetic_source_to !=
nullptr) {
891 FLAG_write_code_comments_as_synthetic_source_to);
900 LineNumberProgramWriter lnp_writer(
stream);
901 if (FLAG_write_code_comments_as_synthetic_source_to !=
nullptr) {
902 WriteSyntheticLineNumberProgram(&lnp_writer);
904 WriteLineNumberProgramFromCodeSourceMaps(&lnp_writer);
908 if (codes_.length() != 0) {
909 const intptr_t last_code_index = codes_.length() - 1;
910 const Code& last_code = *(codes_[last_code_index]);
911 const intptr_t last_pc_offset = last_code.Size();
912 auto const last_label = code_to_label_.LookupValue(&last_code);
914 lnp_writer.MarkEnd(last_label, last_pc_offset);
916 lnp_writer.MarkEnd();
#define DEBUG_ASSERT(cond)
#define ASSERT_EQUAL(expected, actual)
#define RELEASE_ASSERT(cond)
static T AddWithWrapAround(T a, T b)
#define DART_WARN_UNUSED_RESULT
Dart_NativeFunction function
SK_API bool Read(SkStreamSeekable *src, SkDocumentPage *dstArray, int dstArrayCount, const SkDeserialProcs *=nullptr)
DEFINE_FLAG(bool, print_cluster_information, false, "Print information about clusters written to snapshot")
constexpr intptr_t kWordSize
DEF_SWITCHES_START aot vmservice shared library name
SI auto map(std::index_sequence< I... >, Fn &&fn, const Args &... args) -> skvx::Vec< sizeof...(I), decltype(fn(args[0]...))>