44
55#include " vm/dwarf.h"
66
7+ #include " vm/code_comments.h"
78#include " vm/code_descriptors.h"
89#include " vm/elf.h"
910#include " vm/image_snapshot.h"
@@ -13,6 +14,11 @@ namespace dart {
1314
1415#if defined(DART_PRECOMPILER)
1516
17+ DEFINE_FLAG (charp,
18+ write_code_comments_as_synthetic_source_to,
19+ nullptr ,
20+ " Print comments associated with instructions into the given file" );
21+
1622class DwarfPosition {
1723 public:
1824 DwarfPosition (int32_t line, int32_t column) : line_(line), column_(column) {
@@ -506,7 +512,158 @@ void Dwarf::WriteInliningNode(DwarfWriteStream* stream,
506512 stream->uleb128 (0 ); // End of children.
507513}
508514
515+ void Dwarf::WriteSyntheticLineNumberProgram (DwarfWriteStream* stream) {
516+ auto file_open = Dart::file_open_callback ();
517+ auto file_write = Dart::file_write_callback ();
518+ auto file_close = Dart::file_close_callback ();
519+ if ((file_open == nullptr ) || (file_write == nullptr ) ||
520+ (file_close == nullptr )) {
521+ return ;
522+ }
523+
524+ TextBuffer comments_buffer (128 * KB );
525+
526+ auto comments_file = file_open (FLAG_write_code_comments_as_synthetic_source_to, /* write=*/ true );
527+ if (comments_file == nullptr ) {
528+ OS::PrintErr (" Failed to open file %s\n " , FLAG_write_code_comments_as_synthetic_source_to);
529+ return ;
530+ }
531+
532+ // 6.2.4 The Line Number Program Header
533+
534+ // 1. unit_length. This encoding implies 32-bit DWARF.
535+ auto const line_prefix = " line" ;
536+ intptr_t line_start;
537+ intptr_t line_size_fixup = stream->ReserveSize (line_prefix, &line_start);
538+
539+ stream->u2 (2 ); // 2. DWARF version 2
540+
541+ // 3. header_length
542+ auto const lineheader_prefix = " lineheader" ;
543+ intptr_t lineheader_start;
544+ intptr_t lineheader_size_fixup =
545+ stream->ReserveSize (lineheader_prefix, &lineheader_start);
546+
547+ stream->u1 (1 ); // 4. minimum_instruction_length
548+ stream->u1 (1 ); // 5. default_is_stmt (true for compatibility with dsymutil).
549+ stream->u1 (0 ); // 6. line_base
550+ stream->u1 (1 ); // 7. line_range
551+ stream->u1 (13 ); // 8. opcode_base (12 standard opcodes in Dwarf 2)
552+
553+ // 9. standard_opcode_lengths
554+ stream->u1 (0 ); // DW_LNS_copy, 0 operands
555+ stream->u1 (1 ); // DW_LNS_advance_pc, 1 operands
556+ stream->u1 (1 ); // DW_LNS_advance_list, 1 operands
557+ stream->u1 (1 ); // DW_LNS_set_file, 1 operands
558+ stream->u1 (1 ); // DW_LNS_set_column, 1 operands
559+ stream->u1 (0 ); // DW_LNS_negate_stmt, 0 operands
560+ stream->u1 (0 ); // DW_LNS_set_basic_block, 0 operands
561+ stream->u1 (0 ); // DW_LNS_const_add_pc, 0 operands
562+ stream->u1 (1 ); // DW_LNS_fixed_advance_pc, 1 operands
563+ stream->u1 (0 ); // DW_LNS_set_prolog_end, 0 operands
564+ stream->u1 (0 ); // DW_LNS_set_epligoue_begin, 0 operands
565+ stream->u1 (1 ); // DW_LNS_set_isa, 1 operands
566+
567+ // 10. include_directories (sequence of path names)
568+ // We don't emit any because we use full paths below.
569+ stream->u1 (0 );
570+
571+ // 11. file_names (sequence of file entries)
572+ stream->string (FLAG_write_code_comments_as_synthetic_source_to); // NOLINT
573+ stream->uleb128 (0 ); // Include directory index.
574+ stream->uleb128 (0 ); // File modification time.
575+ stream->uleb128 (0 ); // File length.
576+ stream->u1 (0 ); // End of file names.
577+ stream->SetSize (lineheader_size_fixup, lineheader_prefix, lineheader_start);
578+
579+ // 6.2.5 The Line Number Program
580+
581+ // The initial values for the line number program state machine registers
582+ // according to the DWARF standard.
583+ intptr_t previous_pc_offset = 0 ;
584+ intptr_t previous_line = 1 ;
585+ // Other info not stored in the state machine registers.
586+ const char * previous_asm_name = nullptr ;
587+
588+ intptr_t current_line = 0 ;
589+
590+ for (intptr_t i = 0 ; i < codes_.length (); i++) {
591+ const Code& code = *(codes_[i]);
592+ auto const asm_name = code_to_name_.LookupValue (&code);
593+ ASSERT (asm_name != nullptr );
594+
595+ auto comments = code.comments ();
596+ if (comments == nullptr ) {
597+ continue ;
598+ }
599+
600+ for (intptr_t i = 0 , len = comments->Length (); i < len;) {
601+ intptr_t current_pc_offset = comments->PCOffsetAt (i);
602+ while (i < len && current_pc_offset == comments->PCOffsetAt (i)) {
603+ comments_buffer.AddString (comments->CommentAt (i));
604+ comments_buffer.AddChar (' \n ' );
605+ current_line++;
606+ i++;
607+ }
608+
609+ if (current_line != previous_line) {
610+ stream->u1 (DW_LNS_advance_line);
611+ stream->sleb128 (current_line - previous_line);
612+ previous_line = current_line;
613+ }
614+
615+ if (previous_asm_name == nullptr ) {
616+ auto const instr_size = 1 + compiler::target::kWordSize ;
617+ stream->u1 (0 ); // This is an extended opcode
618+ stream->u1 (instr_size); // that is 5 or 9 bytes long
619+ stream->u1 (DW_LNE_set_address);
620+ stream->OffsetFromSymbol (asm_name, current_pc_offset);
621+ } else {
622+ stream->u1 (DW_LNS_advance_pc);
623+ stream->DistanceBetweenSymbolOffsets (asm_name, current_pc_offset,
624+ previous_asm_name,
625+ previous_pc_offset);
626+ }
627+ stream->u1 (DW_LNS_copy);
628+ previous_asm_name = asm_name;
629+ previous_pc_offset = current_pc_offset;
630+ }
631+ }
632+
633+ // Advance pc to end of the compilation unit if not already there.
634+ if (codes_.length () != 0 ) {
635+ const intptr_t last_code_index = codes_.length () - 1 ;
636+ const Code& last_code = *(codes_[last_code_index]);
637+ const intptr_t last_pc_offset = last_code.Size ();
638+ const char * last_asm_name = code_to_name_.LookupValue (&last_code);
639+ ASSERT (last_asm_name != nullptr );
640+
641+ stream->u1 (DW_LNS_advance_pc);
642+ if (previous_asm_name != nullptr ) {
643+ stream->DistanceBetweenSymbolOffsets (
644+ last_asm_name, last_pc_offset, previous_asm_name, previous_pc_offset);
645+ } else {
646+ // No LNP entries (e.g., only stub code).
647+ ASSERT (previous_pc_offset == 0 );
648+ stream->uleb128 (last_pc_offset);
649+ }
650+ }
651+
652+ // End of contiguous machine code.
653+ stream->u1 (0 ); // This is an extended opcode
654+ stream->u1 (1 ); // that is 1 byte long
655+ stream->u1 (DW_LNE_end_sequence);
656+ stream->SetSize (line_size_fixup, line_prefix, line_start);
657+
658+ file_write (comments_buffer.buffer (), comments_buffer.length (), comments_file);
659+ file_close (comments_file);
660+ }
661+
509662void Dwarf::WriteLineNumberProgram (DwarfWriteStream* stream) {
663+ if (FLAG_write_code_comments_as_synthetic_source_to != nullptr ) {
664+ WriteSyntheticLineNumberProgram (stream);
665+ return ;
666+ }
510667 // 6.2.4 The Line Number Program Header
511668
512669 // 1. unit_length. This encoding implies 32-bit DWARF.
0 commit comments