Home | History | Annotate | Download | only in dwarf
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "dwarf_test.h"
     18 
     19 #include "debug/dwarf/debug_frame_opcode_writer.h"
     20 #include "debug/dwarf/debug_info_entry_writer.h"
     21 #include "debug/dwarf/debug_line_opcode_writer.h"
     22 #include "debug/dwarf/dwarf_constants.h"
     23 #include "debug/dwarf/headers.h"
     24 #include "gtest/gtest.h"
     25 
     26 namespace art {
     27 namespace dwarf {
     28 
     29 // Run the tests only on host since we need objdump.
     30 #ifndef ART_TARGET_ANDROID
     31 
     32 constexpr CFIFormat kCFIFormat = DW_DEBUG_FRAME_FORMAT;
     33 
     34 TEST_F(DwarfTest, DebugFrame) {
     35   const bool is64bit = false;
     36 
     37   // Pick offset value which would catch Uleb vs Sleb errors.
     38   const int offset = 40000;
     39   ASSERT_EQ(UnsignedLeb128Size(offset / 4), 2u);
     40   ASSERT_EQ(SignedLeb128Size(offset / 4), 3u);
     41   DW_CHECK("Data alignment factor: -4");
     42   const Reg reg(6);
     43 
     44   // Test the opcodes in the order mentioned in the spec.
     45   // There are usually several encoding variations of each opcode.
     46   DebugFrameOpCodeWriter<> opcodes;
     47   DW_CHECK("FDE");
     48   int pc = 0;
     49   for (int i : {0, 1, 0x3F, 0x40, 0xFF, 0x100, 0xFFFF, 0x10000}) {
     50     pc += i;
     51     opcodes.AdvancePC(pc);
     52   }
     53   DW_CHECK_NEXT("DW_CFA_advance_loc: 1 to 01000001");
     54   DW_CHECK_NEXT("DW_CFA_advance_loc: 63 to 01000040");
     55   DW_CHECK_NEXT("DW_CFA_advance_loc1: 64 to 01000080");
     56   DW_CHECK_NEXT("DW_CFA_advance_loc1: 255 to 0100017f");
     57   DW_CHECK_NEXT("DW_CFA_advance_loc2: 256 to 0100027f");
     58   DW_CHECK_NEXT("DW_CFA_advance_loc2: 65535 to 0101027e");
     59   DW_CHECK_NEXT("DW_CFA_advance_loc4: 65536 to 0102027e");
     60   opcodes.DefCFA(reg, offset);
     61   DW_CHECK_NEXT("DW_CFA_def_cfa: r6 (esi) ofs 40000");
     62   opcodes.DefCFA(reg, -offset);
     63   DW_CHECK_NEXT("DW_CFA_def_cfa_sf: r6 (esi) ofs -40000");
     64   opcodes.DefCFARegister(reg);
     65   DW_CHECK_NEXT("DW_CFA_def_cfa_register: r6 (esi)");
     66   opcodes.DefCFAOffset(offset);
     67   DW_CHECK_NEXT("DW_CFA_def_cfa_offset: 40000");
     68   opcodes.DefCFAOffset(-offset);
     69   DW_CHECK_NEXT("DW_CFA_def_cfa_offset_sf: -40000");
     70   uint8_t expr[] = { 0 };
     71   opcodes.DefCFAExpression(expr, arraysize(expr));
     72   DW_CHECK_NEXT("DW_CFA_def_cfa_expression");
     73   opcodes.Undefined(reg);
     74   DW_CHECK_NEXT("DW_CFA_undefined: r6 (esi)");
     75   opcodes.SameValue(reg);
     76   DW_CHECK_NEXT("DW_CFA_same_value: r6 (esi)");
     77   opcodes.Offset(Reg(0x3F), -offset);
     78   // Bad register likely means that it does not exist on x86,
     79   // but we want to test high register numbers anyway.
     80   DW_CHECK_NEXT("DW_CFA_offset: bad register: r63 at cfa-40000");
     81   opcodes.Offset(Reg(0x40), -offset);
     82   DW_CHECK_NEXT("DW_CFA_offset_extended: bad register: r64 at cfa-40000");
     83   opcodes.Offset(Reg(0x40), offset);
     84   DW_CHECK_NEXT("DW_CFA_offset_extended_sf: bad register: r64 at cfa+40000");
     85   opcodes.ValOffset(reg, -offset);
     86   DW_CHECK_NEXT("DW_CFA_val_offset: r6 (esi) at cfa-40000");
     87   opcodes.ValOffset(reg, offset);
     88   DW_CHECK_NEXT("DW_CFA_val_offset_sf: r6 (esi) at cfa+40000");
     89   opcodes.Register(reg, Reg(1));
     90   DW_CHECK_NEXT("DW_CFA_register: r6 (esi) in r1 (ecx)");
     91   opcodes.Expression(reg, expr, arraysize(expr));
     92   DW_CHECK_NEXT("DW_CFA_expression: r6 (esi)");
     93   opcodes.ValExpression(reg, expr, arraysize(expr));
     94   DW_CHECK_NEXT("DW_CFA_val_expression: r6 (esi)");
     95   opcodes.Restore(Reg(0x3F));
     96   DW_CHECK_NEXT("DW_CFA_restore: bad register: r63");
     97   opcodes.Restore(Reg(0x40));
     98   DW_CHECK_NEXT("DW_CFA_restore_extended: bad register: r64");
     99   opcodes.Restore(reg);
    100   DW_CHECK_NEXT("DW_CFA_restore: r6 (esi)");
    101   opcodes.RememberState();
    102   DW_CHECK_NEXT("DW_CFA_remember_state");
    103   opcodes.RestoreState();
    104   DW_CHECK_NEXT("DW_CFA_restore_state");
    105   opcodes.Nop();
    106   DW_CHECK_NEXT("DW_CFA_nop");
    107 
    108   // Also test helpers.
    109   opcodes.DefCFA(Reg(4), 100);  // ESP
    110   DW_CHECK_NEXT("DW_CFA_def_cfa: r4 (esp) ofs 100");
    111   opcodes.AdjustCFAOffset(8);
    112   DW_CHECK_NEXT("DW_CFA_def_cfa_offset: 108");
    113   opcodes.RelOffset(Reg(0), 0);  // push R0
    114   DW_CHECK_NEXT("DW_CFA_offset: r0 (eax) at cfa-108");
    115   opcodes.RelOffset(Reg(1), 4);  // push R1
    116   DW_CHECK_NEXT("DW_CFA_offset: r1 (ecx) at cfa-104");
    117   opcodes.RelOffsetForMany(Reg(2), 8, 1 | (1 << 3), 4);  // push R2 and R5
    118   DW_CHECK_NEXT("DW_CFA_offset: r2 (edx) at cfa-100");
    119   DW_CHECK_NEXT("DW_CFA_offset: r5 (ebp) at cfa-96");
    120   opcodes.RestoreMany(Reg(2), 1 | (1 << 3));  // pop R2 and R5
    121   DW_CHECK_NEXT("DW_CFA_restore: r2 (edx)");
    122   DW_CHECK_NEXT("DW_CFA_restore: r5 (ebp)");
    123 
    124   DebugFrameOpCodeWriter<> initial_opcodes;
    125   WriteCIE(is64bit, Reg(is64bit ? 16 : 8),
    126            initial_opcodes, kCFIFormat, &debug_frame_data_);
    127   std::vector<uintptr_t> debug_frame_patches;
    128   std::vector<uintptr_t> expected_patches = { 28 };
    129   WriteFDE(is64bit, 0, 0, 0x01000000, 0x01000000, ArrayRef<const uint8_t>(*opcodes.data()),
    130            kCFIFormat, 0, &debug_frame_data_, &debug_frame_patches);
    131 
    132   EXPECT_EQ(expected_patches, debug_frame_patches);
    133   CheckObjdumpOutput(is64bit, "-W");
    134 }
    135 
    136 TEST_F(DwarfTest, DebugFrame64) {
    137   constexpr bool is64bit = true;
    138   DebugFrameOpCodeWriter<> initial_opcodes;
    139   WriteCIE(is64bit, Reg(16),
    140            initial_opcodes, kCFIFormat, &debug_frame_data_);
    141   DebugFrameOpCodeWriter<> opcodes;
    142   std::vector<uintptr_t> debug_frame_patches;
    143   std::vector<uintptr_t> expected_patches = { 32 };
    144   WriteFDE(is64bit, 0, 0, 0x0100000000000000, 0x0200000000000000,
    145            ArrayRef<const uint8_t>(*opcodes.data()),
    146                      kCFIFormat, 0, &debug_frame_data_, &debug_frame_patches);
    147   DW_CHECK("FDE cie=00000000 pc=100000000000000..300000000000000");
    148 
    149   EXPECT_EQ(expected_patches, debug_frame_patches);
    150   CheckObjdumpOutput(is64bit, "-W");
    151 }
    152 
    153 // Test x86_64 register mapping. It is the only non-trivial architecture.
    154 // ARM, X86, and Mips have: dwarf_reg = art_reg + constant.
    155 TEST_F(DwarfTest, x86_64_RegisterMapping) {
    156   constexpr bool is64bit = true;
    157   DebugFrameOpCodeWriter<> opcodes;
    158   for (int i = 0; i < 16; i++) {
    159     opcodes.RelOffset(Reg::X86_64Core(i), 0);
    160   }
    161   DW_CHECK("FDE");
    162   DW_CHECK_NEXT("DW_CFA_offset: r0 (rax)");
    163   DW_CHECK_NEXT("DW_CFA_offset: r2 (rcx)");
    164   DW_CHECK_NEXT("DW_CFA_offset: r1 (rdx)");
    165   DW_CHECK_NEXT("DW_CFA_offset: r3 (rbx)");
    166   DW_CHECK_NEXT("DW_CFA_offset: r7 (rsp)");
    167   DW_CHECK_NEXT("DW_CFA_offset: r6 (rbp)");
    168   DW_CHECK_NEXT("DW_CFA_offset: r4 (rsi)");
    169   DW_CHECK_NEXT("DW_CFA_offset: r5 (rdi)");
    170   DW_CHECK_NEXT("DW_CFA_offset: r8 (r8)");
    171   DW_CHECK_NEXT("DW_CFA_offset: r9 (r9)");
    172   DW_CHECK_NEXT("DW_CFA_offset: r10 (r10)");
    173   DW_CHECK_NEXT("DW_CFA_offset: r11 (r11)");
    174   DW_CHECK_NEXT("DW_CFA_offset: r12 (r12)");
    175   DW_CHECK_NEXT("DW_CFA_offset: r13 (r13)");
    176   DW_CHECK_NEXT("DW_CFA_offset: r14 (r14)");
    177   DW_CHECK_NEXT("DW_CFA_offset: r15 (r15)");
    178   DebugFrameOpCodeWriter<> initial_opcodes;
    179   WriteCIE(is64bit, Reg(16),
    180            initial_opcodes, kCFIFormat, &debug_frame_data_);
    181   std::vector<uintptr_t> debug_frame_patches;
    182   WriteFDE(is64bit, 0, 0, 0x0100000000000000, 0x0200000000000000,
    183            ArrayRef<const uint8_t>(*opcodes.data()),
    184                      kCFIFormat, 0, &debug_frame_data_, &debug_frame_patches);
    185 
    186   CheckObjdumpOutput(is64bit, "-W");
    187 }
    188 
    189 TEST_F(DwarfTest, DebugLine) {
    190   const bool is64bit = false;
    191   const int code_factor_bits = 1;
    192   DebugLineOpCodeWriter<> opcodes(is64bit, code_factor_bits);
    193 
    194   std::vector<std::string> include_directories;
    195   include_directories.push_back("/path/to/source");
    196   DW_CHECK("/path/to/source");
    197 
    198   std::vector<FileEntry> files {
    199     { "file0.c", 0, 1000, 2000 },
    200     { "file1.c", 1, 1000, 2000 },
    201     { "file2.c", 1, 1000, 2000 },
    202   };
    203   DW_CHECK("1\t0\t1000\t2000\tfile0.c");
    204   DW_CHECK_NEXT("2\t1\t1000\t2000\tfile1.c");
    205   DW_CHECK_NEXT("3\t1\t1000\t2000\tfile2.c");
    206 
    207   DW_CHECK("Line Number Statements");
    208   opcodes.SetAddress(0x01000000);
    209   DW_CHECK_NEXT("Extended opcode 2: set Address to 0x1000000");
    210   opcodes.AddRow();
    211   DW_CHECK_NEXT("Copy");
    212   opcodes.AdvancePC(0x01000100);
    213   DW_CHECK_NEXT("Advance PC by 256 to 0x1000100");
    214   opcodes.SetFile(2);
    215   DW_CHECK_NEXT("Set File Name to entry 2 in the File Name Table");
    216   opcodes.AdvanceLine(3);
    217   DW_CHECK_NEXT("Advance Line by 2 to 3");
    218   opcodes.SetColumn(4);
    219   DW_CHECK_NEXT("Set column to 4");
    220   opcodes.SetIsStmt(true);
    221   DW_CHECK_NEXT("Set is_stmt to 1");
    222   opcodes.SetIsStmt(false);
    223   DW_CHECK_NEXT("Set is_stmt to 0");
    224   opcodes.SetBasicBlock();
    225   DW_CHECK_NEXT("Set basic block");
    226   opcodes.SetPrologueEnd();
    227   DW_CHECK_NEXT("Set prologue_end to true");
    228   opcodes.SetEpilogueBegin();
    229   DW_CHECK_NEXT("Set epilogue_begin to true");
    230   opcodes.SetISA(5);
    231   DW_CHECK_NEXT("Set ISA to 5");
    232   opcodes.EndSequence();
    233   DW_CHECK_NEXT("Extended opcode 1: End of Sequence");
    234   opcodes.DefineFile("file.c", 0, 1000, 2000);
    235   DW_CHECK_NEXT("Extended opcode 3: define new File Table entry");
    236   DW_CHECK_NEXT("Entry\tDir\tTime\tSize\tName");
    237   DW_CHECK_NEXT("1\t0\t1000\t2000\tfile.c");
    238 
    239   std::vector<uintptr_t> debug_line_patches;
    240   std::vector<uintptr_t> expected_patches = { 87 };
    241   WriteDebugLineTable(include_directories, files, opcodes,
    242                       0, &debug_line_data_, &debug_line_patches);
    243 
    244   EXPECT_EQ(expected_patches, debug_line_patches);
    245   CheckObjdumpOutput(is64bit, "-W");
    246 }
    247 
    248 // DWARF has special one byte codes which advance PC and line at the same time.
    249 TEST_F(DwarfTest, DebugLineSpecialOpcodes) {
    250   const bool is64bit = false;
    251   const int code_factor_bits = 1;
    252   uint32_t pc = 0x01000000;
    253   int line = 1;
    254   DebugLineOpCodeWriter<> opcodes(is64bit, code_factor_bits);
    255   opcodes.SetAddress(pc);
    256   size_t num_rows = 0;
    257   DW_CHECK("Line Number Statements:");
    258   DW_CHECK("Special opcode");
    259   DW_CHECK("Advance PC by constant");
    260   DW_CHECK("Decoded dump of debug contents of section .debug_line:");
    261   DW_CHECK("Line number    Starting address");
    262   for (int addr_delta = 0; addr_delta < 80; addr_delta += 2) {
    263     for (int line_delta = 16; line_delta >= -16; --line_delta) {
    264       pc += addr_delta;
    265       line += line_delta;
    266       opcodes.AddRow(pc, line);
    267       num_rows++;
    268       ASSERT_EQ(opcodes.CurrentAddress(), pc);
    269       ASSERT_EQ(opcodes.CurrentLine(), line);
    270       char expected[1024];
    271       sprintf(expected, "%i           0x%x", line, pc);
    272       DW_CHECK_NEXT(expected);
    273     }
    274   }
    275   EXPECT_LT(opcodes.data()->size(), num_rows * 3);
    276 
    277   std::vector<std::string> directories;
    278   std::vector<FileEntry> files = { { "file.c", 0, 1000, 2000 } };
    279   std::vector<uintptr_t> debug_line_patches;
    280   WriteDebugLineTable(directories, files, opcodes,
    281                       0, &debug_line_data_, &debug_line_patches);
    282 
    283   CheckObjdumpOutput(is64bit, "-W -WL");
    284 }
    285 
    286 TEST_F(DwarfTest, DebugInfo) {
    287   constexpr bool is64bit = false;
    288   DebugAbbrevWriter<> debug_abbrev(&debug_abbrev_data_);
    289   DebugInfoEntryWriter<> info(is64bit, &debug_abbrev);
    290   DW_CHECK("Contents of the .debug_info section:");
    291   info.StartTag(dwarf::DW_TAG_compile_unit);
    292   DW_CHECK("Abbrev Number: 1 (DW_TAG_compile_unit)");
    293   info.WriteStrp(dwarf::DW_AT_producer, "Compiler name", &debug_str_data_);
    294   DW_CHECK_NEXT("DW_AT_producer    : (indirect string, offset: 0x0): Compiler name");
    295   info.WriteAddr(dwarf::DW_AT_low_pc, 0x01000000);
    296   DW_CHECK_NEXT("DW_AT_low_pc      : 0x1000000");
    297   info.WriteAddr(dwarf::DW_AT_high_pc, 0x02000000);
    298   DW_CHECK_NEXT("DW_AT_high_pc     : 0x2000000");
    299   info.StartTag(dwarf::DW_TAG_subprogram);
    300   DW_CHECK("Abbrev Number: 2 (DW_TAG_subprogram)");
    301   info.WriteStrp(dwarf::DW_AT_name, "Foo", &debug_str_data_);
    302   DW_CHECK_NEXT("DW_AT_name        : (indirect string, offset: 0xe): Foo");
    303   info.WriteAddr(dwarf::DW_AT_low_pc, 0x01010000);
    304   DW_CHECK_NEXT("DW_AT_low_pc      : 0x1010000");
    305   info.WriteAddr(dwarf::DW_AT_high_pc, 0x01020000);
    306   DW_CHECK_NEXT("DW_AT_high_pc     : 0x1020000");
    307   info.EndTag();  // DW_TAG_subprogram
    308   info.StartTag(dwarf::DW_TAG_subprogram);
    309   DW_CHECK("Abbrev Number: 2 (DW_TAG_subprogram)");
    310   info.WriteStrp(dwarf::DW_AT_name, "Bar", &debug_str_data_);
    311   DW_CHECK_NEXT("DW_AT_name        : (indirect string, offset: 0x12): Bar");
    312   info.WriteAddr(dwarf::DW_AT_low_pc, 0x01020000);
    313   DW_CHECK_NEXT("DW_AT_low_pc      : 0x1020000");
    314   info.WriteAddr(dwarf::DW_AT_high_pc, 0x01030000);
    315   DW_CHECK_NEXT("DW_AT_high_pc     : 0x1030000");
    316   info.EndTag();  // DW_TAG_subprogram
    317   info.EndTag();  // DW_TAG_compile_unit
    318   // Test that previous list was properly terminated and empty children.
    319   info.StartTag(dwarf::DW_TAG_compile_unit);
    320   info.EndTag();  // DW_TAG_compile_unit
    321 
    322   // The abbrev table is just side product, but check it as well.
    323   DW_CHECK("Abbrev Number: 3 (DW_TAG_compile_unit)");
    324   DW_CHECK("Contents of the .debug_abbrev section:");
    325   DW_CHECK("1      DW_TAG_compile_unit    [has children]");
    326   DW_CHECK_NEXT("DW_AT_producer     DW_FORM_strp");
    327   DW_CHECK_NEXT("DW_AT_low_pc       DW_FORM_addr");
    328   DW_CHECK_NEXT("DW_AT_high_pc      DW_FORM_addr");
    329   DW_CHECK("2      DW_TAG_subprogram    [no children]");
    330   DW_CHECK_NEXT("DW_AT_name         DW_FORM_strp");
    331   DW_CHECK_NEXT("DW_AT_low_pc       DW_FORM_addr");
    332   DW_CHECK_NEXT("DW_AT_high_pc      DW_FORM_addr");
    333   DW_CHECK("3      DW_TAG_compile_unit    [no children]");
    334 
    335   std::vector<uintptr_t> debug_info_patches;
    336   std::vector<uintptr_t> expected_patches = { 16, 20, 29, 33, 42, 46 };
    337   dwarf::WriteDebugInfoCU(0 /* debug_abbrev_offset */, info,
    338                           0, &debug_info_data_, &debug_info_patches);
    339 
    340   EXPECT_EQ(expected_patches, debug_info_patches);
    341   CheckObjdumpOutput(is64bit, "-W");
    342 }
    343 
    344 #endif  // ART_TARGET_ANDROID
    345 
    346 }  // namespace dwarf
    347 }  // namespace art
    348