Home | History | Annotate | Download | only in dwarf
      1 /*
      2  * Copyright (C) 2014 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 #ifndef ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
     18 #define ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
     19 
     20 #include <cstdint>
     21 #include <unordered_map>
     22 
     23 #include "dwarf/dwarf_constants.h"
     24 #include "dwarf/writer.h"
     25 #include "leb128.h"
     26 
     27 namespace art {
     28 namespace dwarf {
     29 
     30 // 32-bit FNV-1a hash function which we use to find duplicate abbreviations.
     31 // See http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
     32 template< typename Allocator >
     33 struct FNVHash {
     34   size_t operator()(const std::vector<uint8_t, Allocator>& v) const {
     35     uint32_t hash = 2166136261u;
     36     for (size_t i = 0; i < v.size(); i++) {
     37       hash = (hash ^ v[i]) * 16777619u;
     38     }
     39     return hash;
     40   }
     41 };
     42 
     43 /*
     44  * Writer for debug information entries (DIE).
     45  * It also handles generation of abbreviations.
     46  *
     47  * Usage:
     48  *   StartTag(DW_TAG_compile_unit, DW_CHILDREN_yes);
     49  *     WriteStrp(DW_AT_producer, "Compiler name", debug_str);
     50  *     StartTag(DW_TAG_subprogram, DW_CHILDREN_no);
     51  *       WriteStrp(DW_AT_name, "Foo", debug_str);
     52  *     EndTag();
     53  *   EndTag();
     54  */
     55 template< typename Allocator = std::allocator<uint8_t> >
     56 class DebugInfoEntryWriter FINAL : private Writer<Allocator> {
     57  public:
     58   // Start debugging information entry.
     59   void StartTag(Tag tag, Children children) {
     60     DCHECK(has_children) << "This tag can not have nested tags";
     61     if (inside_entry_) {
     62       // Write abbrev code for the previous entry.
     63       this->UpdateUleb128(abbrev_code_offset_, EndAbbrev());
     64       inside_entry_ = false;
     65     }
     66     StartAbbrev(tag, children);
     67     // Abbrev code placeholder of sufficient size.
     68     abbrev_code_offset_ = this->data()->size();
     69     this->PushUleb128(NextAbbrevCode());
     70     depth_++;
     71     inside_entry_ = true;
     72     has_children = (children == DW_CHILDREN_yes);
     73   }
     74 
     75   // End debugging information entry.
     76   void EndTag() {
     77     DCHECK_GT(depth_, 0);
     78     if (inside_entry_) {
     79       // Write abbrev code for this tag.
     80       this->UpdateUleb128(abbrev_code_offset_, EndAbbrev());
     81       inside_entry_ = false;
     82     }
     83     if (has_children) {
     84       this->PushUint8(0);  // End of children.
     85     }
     86     depth_--;
     87     has_children = true;  // Parent tag obviously has children.
     88   }
     89 
     90   void WriteAddr(Attribute attrib, uint64_t value) {
     91     AddAbbrevAttribute(attrib, DW_FORM_addr);
     92     patch_locations_.push_back(this->data()->size());
     93     if (is64bit_) {
     94       this->PushUint64(value);
     95     } else {
     96       this->PushUint32(value);
     97     }
     98   }
     99 
    100   void WriteBlock(Attribute attrib, const void* ptr, int size) {
    101     AddAbbrevAttribute(attrib, DW_FORM_block);
    102     this->PushUleb128(size);
    103     this->PushData(ptr, size);
    104   }
    105 
    106   void WriteData1(Attribute attrib, uint8_t value) {
    107     AddAbbrevAttribute(attrib, DW_FORM_data1);
    108     this->PushUint8(value);
    109   }
    110 
    111   void WriteData2(Attribute attrib, uint16_t value) {
    112     AddAbbrevAttribute(attrib, DW_FORM_data2);
    113     this->PushUint16(value);
    114   }
    115 
    116   void WriteData4(Attribute attrib, uint32_t value) {
    117     AddAbbrevAttribute(attrib, DW_FORM_data4);
    118     this->PushUint32(value);
    119   }
    120 
    121   void WriteData8(Attribute attrib, uint64_t value) {
    122     AddAbbrevAttribute(attrib, DW_FORM_data8);
    123     this->PushUint64(value);
    124   }
    125 
    126   void WriteSdata(Attribute attrib, int value) {
    127     AddAbbrevAttribute(attrib, DW_FORM_sdata);
    128     this->PushSleb128(value);
    129   }
    130 
    131   void WriteUdata(Attribute attrib, int value) {
    132     AddAbbrevAttribute(attrib, DW_FORM_udata);
    133     this->PushUleb128(value);
    134   }
    135 
    136   void WriteUdata(Attribute attrib, uint32_t value) {
    137     AddAbbrevAttribute(attrib, DW_FORM_udata);
    138     this->PushUleb128(value);
    139   }
    140 
    141   void WriteFlag(Attribute attrib, bool value) {
    142     AddAbbrevAttribute(attrib, DW_FORM_flag);
    143     this->PushUint8(value ? 1 : 0);
    144   }
    145 
    146   void WriteRef4(Attribute attrib, int cu_offset) {
    147     AddAbbrevAttribute(attrib, DW_FORM_ref4);
    148     this->PushUint32(cu_offset);
    149   }
    150 
    151   void WriteRef(Attribute attrib, int cu_offset) {
    152     AddAbbrevAttribute(attrib, DW_FORM_ref_udata);
    153     this->PushUleb128(cu_offset);
    154   }
    155 
    156   void WriteString(Attribute attrib, const char* value) {
    157     AddAbbrevAttribute(attrib, DW_FORM_string);
    158     this->PushString(value);
    159   }
    160 
    161   void WriteStrp(Attribute attrib, int address) {
    162     AddAbbrevAttribute(attrib, DW_FORM_strp);
    163     this->PushUint32(address);
    164   }
    165 
    166   void WriteStrp(Attribute attrib, const char* value, std::vector<uint8_t>* debug_str) {
    167     AddAbbrevAttribute(attrib, DW_FORM_strp);
    168     int address = debug_str->size();
    169     debug_str->insert(debug_str->end(), value, value + strlen(value) + 1);
    170     this->PushUint32(address);
    171   }
    172 
    173   bool Is64bit() const { return is64bit_; }
    174 
    175   const std::vector<uintptr_t>& GetPatchLocations() const {
    176     return patch_locations_;
    177   }
    178 
    179   using Writer<Allocator>::data;
    180 
    181   DebugInfoEntryWriter(bool is64bitArch,
    182                        std::vector<uint8_t, Allocator>* debug_abbrev,
    183                        const Allocator& alloc = Allocator())
    184       : Writer<Allocator>(&entries_),
    185         debug_abbrev_(debug_abbrev),
    186         current_abbrev_(alloc),
    187         abbrev_codes_(alloc),
    188         entries_(alloc),
    189         is64bit_(is64bitArch) {
    190     debug_abbrev_.PushUint8(0);  // Add abbrev table terminator.
    191   }
    192 
    193   ~DebugInfoEntryWriter() {
    194     DCHECK_EQ(depth_, 0);
    195   }
    196 
    197  private:
    198   // Start abbreviation declaration.
    199   void StartAbbrev(Tag tag, Children children) {
    200     DCHECK(!inside_entry_);
    201     current_abbrev_.clear();
    202     EncodeUnsignedLeb128(&current_abbrev_, tag);
    203     current_abbrev_.push_back(children);
    204   }
    205 
    206   // Add attribute specification.
    207   void AddAbbrevAttribute(Attribute name, Form type) {
    208     DCHECK(inside_entry_) << "Call StartTag before adding attributes.";
    209     EncodeUnsignedLeb128(&current_abbrev_, name);
    210     EncodeUnsignedLeb128(&current_abbrev_, type);
    211   }
    212 
    213   int NextAbbrevCode() {
    214     return 1 + abbrev_codes_.size();
    215   }
    216 
    217   // End abbreviation declaration and return its code.
    218   int EndAbbrev() {
    219     DCHECK(inside_entry_);
    220     auto it = abbrev_codes_.insert(std::make_pair(std::move(current_abbrev_),
    221                                                   NextAbbrevCode()));
    222     int abbrev_code = it.first->second;
    223     if (UNLIKELY(it.second)) {  // Inserted new entry.
    224       const std::vector<uint8_t, Allocator>& abbrev = it.first->first;
    225       debug_abbrev_.Pop();  // Remove abbrev table terminator.
    226       debug_abbrev_.PushUleb128(abbrev_code);
    227       debug_abbrev_.PushData(abbrev.data(), abbrev.size());
    228       debug_abbrev_.PushUint8(0);  // Attribute list end.
    229       debug_abbrev_.PushUint8(0);  // Attribute list end.
    230       debug_abbrev_.PushUint8(0);  // Add abbrev table terminator.
    231     }
    232     return abbrev_code;
    233   }
    234 
    235  private:
    236   // Fields for writing and deduplication of abbrevs.
    237   Writer<Allocator> debug_abbrev_;
    238   std::vector<uint8_t, Allocator> current_abbrev_;
    239   std::unordered_map<std::vector<uint8_t, Allocator>, int,
    240                      FNVHash<Allocator> > abbrev_codes_;
    241 
    242   // Fields for writing of debugging information entries.
    243   std::vector<uint8_t, Allocator> entries_;
    244   bool is64bit_;
    245   int depth_ = 0;
    246   size_t abbrev_code_offset_ = 0;  // Location to patch once we know the code.
    247   bool inside_entry_ = false;  // Entry ends at first child (if any).
    248   bool has_children = true;
    249   std::vector<uintptr_t> patch_locations_;
    250 };
    251 
    252 }  // namespace dwarf
    253 }  // namespace art
    254 
    255 #endif  // ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
    256