HashedNameToDIE.h   [plain text]


//===-- HashedNameToDIE.h ---------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef SymbolFileDWARF_HashedNameToDIE_h_
#define SymbolFileDWARF_HashedNameToDIE_h_

#include <vector>

#include "DWARFDefines.h"
#include "DWARFFormValue.h"

#include "lldb/lldb-defines.h"
#include "lldb/Core/dwarf.h"
#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/MappedHash.h"


class SymbolFileDWARF;
class DWARFCompileUnit;
class DWARFDebugInfoEntry;

struct DWARFMappedHash
{
    struct DIEInfo
    {
        dw_offset_t offset;  // The DIE offset
        dw_tag_t tag;
        uint32_t type_flags; // Any flags for this DIEInfo

        DIEInfo () :
            offset (DW_INVALID_OFFSET),
            tag (0),
            type_flags (0)
        {
        }

        DIEInfo (dw_offset_t o, dw_tag_t t, uint32_t f) :
            offset(o),
            tag (t),
            type_flags (f)
        {
        }
        
        void
        Clear()
        {
            offset = DW_INVALID_OFFSET;
            tag = 0;
            type_flags = 0;
        }            
    };
    
    typedef std::vector<DIEInfo> DIEInfoArray;
    typedef std::vector<uint32_t> DIEArray;
    
    static void
    ExtractDIEArray (const DIEInfoArray &die_info_array,
                     DIEArray &die_offsets)
    {
        const size_t count = die_info_array.size();
        for (size_t i=0; i<count; ++i)
        {
            die_offsets.push_back (die_info_array[i].offset);
        }
    }

    static void
    ExtractDIEArray (const DIEInfoArray &die_info_array,
                     const dw_tag_t tag,
                     DIEArray &die_offsets)
    {
        if (tag == 0)
        {
            ExtractDIEArray (die_info_array, die_offsets);
        }
        else
        {
            const size_t count = die_info_array.size();
            for (size_t i=0; i<count; ++i)
            {
                const dw_tag_t die_tag = die_info_array[i].tag;
                bool tag_matches = die_tag == 0 || tag == die_tag;
                if (!tag_matches)
                {
                    if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
                        tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
                }
                if (tag_matches)
                    die_offsets.push_back (die_info_array[i].offset);
            }
        }
    }
    enum AtomType
    {
        eAtomTypeNULL       = 0u,
        eAtomTypeDIEOffset  = 1u,   // DIE offset, check form for encoding
        eAtomTypeCUOffset   = 2u,   // DIE offset of the compiler unit header that contains the item in question
        eAtomTypeTag        = 3u,   // DW_TAG_xxx value, should be encoded as DW_FORM_data1 (if no tags exceed 255) or DW_FORM_data2
        eAtomTypeNameFlags  = 4u,   // Flags from enum NameFlags
        eAtomTypeTypeFlags  = 5u    // Flags from enum TypeFlags
    };
    
    // Bit definitions for the eAtomTypeTypeFlags flags
    enum TypeFlags
    {
        // Always set for C++, only set for ObjC if this is the 
        // @implementation for class
        eTypeFlagClassIsImplementation  = ( 1u << 1 )
    };
    

    static void
    ExtractClassOrStructDIEArray (const DIEInfoArray &die_info_array,
                                  bool return_implementation_only_if_available,
                                  DIEArray &die_offsets)
    {
        const size_t count = die_info_array.size();
        for (size_t i=0; i<count; ++i)
        {
            const dw_tag_t die_tag = die_info_array[i].tag;
            if (die_tag == 0 || die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
            {
                if (die_info_array[i].type_flags & eTypeFlagClassIsImplementation)
                {
                    if (return_implementation_only_if_available)
                    {
                        // We found the one true definiton for this class, so
                        // only return that
                        die_offsets.clear();                        
                        die_offsets.push_back (die_info_array[i].offset);
                        return;
                    }
                    else
                    {
                        // Put the one true definition as the first entry so it
                        // matches first
                        die_offsets.insert (die_offsets.begin(), die_info_array[i].offset);
                    }
                }
                else
                {
                    die_offsets.push_back (die_info_array[i].offset);
                }
            }
        }
    }

    static void
    ExtractTypesFromDIEArray (const DIEInfoArray &die_info_array,
                              uint32_t type_flag_mask,
                              uint32_t type_flag_value,
                              DIEArray &die_offsets)
    {
        const size_t count = die_info_array.size();
        for (size_t i=0; i<count; ++i)
        {
            if ((die_info_array[i].type_flags & type_flag_mask) == type_flag_value)
                die_offsets.push_back (die_info_array[i].offset);
        }
    }

    struct Atom
    {
        uint16_t type;
        dw_form_t form;
        
        Atom (uint16_t t = eAtomTypeNULL, dw_form_t f = 0) :
            type (t),
            form (f)
        {
        }
    };
    
    typedef std::vector<Atom> AtomArray;
    
    static uint32_t 
    GetTypeFlags (SymbolFileDWARF *dwarf2Data,
                  const DWARFCompileUnit* cu,
                  const DWARFDebugInfoEntry* die);
    

    static const char *
    GetAtomTypeName (uint16_t atom)
    {
        switch (atom)
        {
            case eAtomTypeNULL:         return "NULL";
            case eAtomTypeDIEOffset:    return "die-offset";
            case eAtomTypeCUOffset:     return "cu-offset";
            case eAtomTypeTag:          return "die-tag";
            case eAtomTypeNameFlags:    return "name-flags";
            case eAtomTypeTypeFlags:    return "type-flags";
        }
        return "<invalid>";
    }
    struct Prologue
    {
        // DIE offset base so die offsets in hash_data can be CU relative
        dw_offset_t die_base_offset;
        AtomArray atoms;
        uint32_t atom_mask;
        size_t min_hash_data_byte_size;
        bool hash_data_has_fixed_byte_size;
        
        Prologue (dw_offset_t _die_base_offset = 0) :
            die_base_offset (_die_base_offset),
            atoms(),
            atom_mask (0),
            min_hash_data_byte_size(0),
            hash_data_has_fixed_byte_size(true)
        {
            // Define an array of DIE offsets by first defining an array, 
            // and then define the atom type for the array, in this case
            // we have an array of DIE offsets
            AppendAtom (eAtomTypeDIEOffset, DW_FORM_data4);
        }
        
        virtual ~Prologue()
        {
        }

        void
        ClearAtoms ()
        {
            hash_data_has_fixed_byte_size = true;
            min_hash_data_byte_size = 0;
            atom_mask = 0;
            atoms.clear();
        }

        bool
        ContainsAtom (AtomType atom_type) const
        {
            return (atom_mask & (1u << atom_type)) != 0;
        }

        virtual void
        Clear ()
        {
            die_base_offset = 0;
            ClearAtoms ();
        }
        
        void
        AppendAtom (AtomType type, dw_form_t form)
        {
            atoms.push_back (Atom(type, form));
            atom_mask |= 1u << type;
            switch (form)
            {
                case DW_FORM_indirect:
                case DW_FORM_exprloc:
                case DW_FORM_flag_present:
                case DW_FORM_ref_sig8:
                    assert (!"Unhandled atom form");
                    break;

                case DW_FORM_string:
                case DW_FORM_block:
                case DW_FORM_block1:
                case DW_FORM_sdata:
                case DW_FORM_udata:
                case DW_FORM_ref_udata:
                    hash_data_has_fixed_byte_size = false;
                    // Fall through to the cases below...
                case DW_FORM_flag:
                case DW_FORM_data1:
                case DW_FORM_ref1:
                case DW_FORM_sec_offset:
                    min_hash_data_byte_size += 1; 
                    break;

                case DW_FORM_block2:
                    hash_data_has_fixed_byte_size = false;
                    // Fall through to the cases below...
                case DW_FORM_data2: 
                case DW_FORM_ref2:
                    min_hash_data_byte_size += 2; 
                    break;

                case DW_FORM_block4: 
                    hash_data_has_fixed_byte_size = false;
                    // Fall through to the cases below...
                case DW_FORM_data4:
                case DW_FORM_ref4:
                case DW_FORM_addr:
                case DW_FORM_ref_addr:
                case DW_FORM_strp:
                    min_hash_data_byte_size += 4; 
                    break;

                case DW_FORM_data8:
                case DW_FORM_ref8:
                    min_hash_data_byte_size += 8; 
                    break;
                    
            }
        }
        
//        void
//        Dump (std::ostream* ostrm_ptr);        
        
        uint32_t
        Read (const lldb_private::DataExtractor &data, uint32_t offset)
        {
            ClearAtoms ();
            
            die_base_offset = data.GetU32 (&offset);
            
            const uint32_t atom_count = data.GetU32 (&offset);
            if (atom_count == 0x00060003u)
            {
                // Old format, deal with contents of old pre-release format
                while (data.GetU32(&offset))
                    /* do nothing */;

                // Hardcode to the only known value for now.
                AppendAtom (eAtomTypeDIEOffset, DW_FORM_data4);
            }
            else
            {
                for (uint32_t i=0; i<atom_count; ++i)
                {
                    AtomType type = (AtomType)data.GetU16 (&offset);
                    dw_form_t form = (dw_form_t)data.GetU16 (&offset);                    
                    AppendAtom (type, form);
                }
            }
            return offset;
        }
        
//        virtual void
//        Write (BinaryStreamBuf &s);
        
        size_t
        GetByteSize () const
        {
            // Add an extra count to the atoms size for the zero termination Atom that gets
            // written to disk
            return sizeof(die_base_offset) + sizeof(uint32_t) + atoms.size() * sizeof(Atom);
        }
        
        size_t
        GetMinumumHashDataByteSize () const
        {
            return min_hash_data_byte_size;
        }

        bool
        HashDataHasFixedByteSize() const
        {
            return hash_data_has_fixed_byte_size;
        }
    };
    
    struct Header : public MappedHash::Header<Prologue>
    {
        Header (dw_offset_t _die_base_offset = 0)
        {
        }
        
        virtual 
        ~Header()
        {
        }

        virtual size_t
        GetByteSize (const HeaderData &header_data)
        {
            return header_data.GetByteSize();
        }

        //        virtual void
        //        Dump (std::ostream* ostrm_ptr);        
        //        
        virtual uint32_t
        Read (lldb_private::DataExtractor &data, uint32_t offset)
        {
            offset = MappedHash::Header<Prologue>::Read (data, offset);
            if (offset != UINT32_MAX)
            {
                offset = header_data.Read (data, offset);
            }
            return offset;
        }
        
        bool
        Read (const lldb_private::DataExtractor &data, 
              uint32_t *offset_ptr, 
              DIEInfo &hash_data) const
        {
            const size_t num_atoms = header_data.atoms.size();
            if (num_atoms == 0)
                return false;
            
            for (size_t i=0; i<num_atoms; ++i)
            {
                DWARFFormValue form_value (header_data.atoms[i].form);
                
                if (!form_value.ExtractValue(data, offset_ptr, NULL))
                    return false;
                
                switch (header_data.atoms[i].type)
                {
                    case eAtomTypeDIEOffset:    // DIE offset, check form for encoding
                        hash_data.offset = form_value.Reference (header_data.die_base_offset);
                        break;

                    case eAtomTypeTag:          // DW_TAG value for the DIE
                        hash_data.tag = form_value.Unsigned ();
                        
                    case eAtomTypeTypeFlags:    // Flags from enum TypeFlags
                        hash_data.type_flags = form_value.Unsigned ();
                        break;
                    default:
                        return false;
                        break;
                }
            }
            return true;
        }
        
        void
        Dump (lldb_private::Stream& strm, const DIEInfo &hash_data) const
        {
            const size_t num_atoms = header_data.atoms.size();
            for (size_t i=0; i<num_atoms; ++i)
            {
                if (i > 0)
                    strm.PutCString (", ");
                
                DWARFFormValue form_value (header_data.atoms[i].form);
                switch (header_data.atoms[i].type)
                {
                    case eAtomTypeDIEOffset:    // DIE offset, check form for encoding
                        strm.Printf ("{0x%8.8x}", hash_data.offset);
                        break;

                    case eAtomTypeTag:          // DW_TAG value for the DIE
                        {
                            const char *tag_cstr = lldb_private::DW_TAG_value_to_name (hash_data.tag);
                            if (tag_cstr)
                                strm.PutCString (tag_cstr);
                            else
                                strm.Printf ("DW_TAG_(0x%4.4x)", hash_data.tag);
                        }
                        break;

                    case eAtomTypeTypeFlags:    // Flags from enum TypeFlags
                        strm.Printf ("0x%2.2x", hash_data.type_flags);
                        if (hash_data.type_flags)
                        {
                            strm.PutCString (" (");
                            if (hash_data.type_flags & eTypeFlagClassIsImplementation)
                                strm.PutCString (" implementation");
                            strm.PutCString (" )");
                        }
                        break;
                        
                    default:
                        strm.Printf ("AtomType(0x%x)", header_data.atoms[i].type);
                        break;
                }
            }
        }
    };
    
//    class ExportTable
//    {
//    public:
//        ExportTable ();
//        
//        void
//        AppendNames (DWARFDebugPubnamesSet &pubnames_set,
//                     StringTable &string_table);
//        
//        void
//        AppendNamesEntry (SymbolFileDWARF *dwarf2Data,
//                          const DWARFCompileUnit* cu,
//                          const DWARFDebugInfoEntry* die,
//                          StringTable &string_table);
//        
//        void
//        AppendTypesEntry (DWARFData *dwarf2Data,
//                          const DWARFCompileUnit* cu,
//                          const DWARFDebugInfoEntry* die,
//                          StringTable &string_table);
//        
//        size_t
//        Save (BinaryStreamBuf &names_data, const StringTable &string_table);
//        
//        void
//        AppendName (const char *name, 
//                    uint32_t die_offset, 
//                    StringTable &string_table,
//                    dw_offset_t name_debug_str_offset = DW_INVALID_OFFSET); // If "name" has already been looked up, then it can be supplied
//        void
//        AppendType (const char *name, 
//                    uint32_t die_offset, 
//                    StringTable &string_table);
//        
//        
//    protected:
//        struct Entry
//        {
//            uint32_t hash;
//            uint32_t str_offset;
//            uint32_t die_offset;
//        };
//        
//        // Map uniqued .debug_str offset to the corresponding DIE offsets
//        typedef std::map<uint32_t, DIEInfoArray> NameInfo;
//        // Map a name hash to one or more name infos
//        typedef std::map<uint32_t, NameInfo> BucketEntry;
//        
//        static uint32_t
//        GetByteSize (const NameInfo &name_info);
//        
//        typedef std::vector<BucketEntry> BucketEntryColl;
//        typedef std::vector<Entry> EntryColl;
//        EntryColl m_entries;
//        
//    };
    
    
    // A class for reading and using a saved hash table from a block of data
    // in memory
    class MemoryTable : public MappedHash::MemoryTable<uint32_t, DWARFMappedHash::Header, DIEInfoArray>
    {
    public:
        
        MemoryTable (lldb_private::DataExtractor &table_data, 
                     const lldb_private::DataExtractor &string_table,
                     const char *name) :
            MappedHash::MemoryTable<uint32_t, Header, DIEInfoArray> (table_data),
            m_data (table_data),
            m_string_table (string_table),
            m_name (name)
        {
        }
    
        virtual 
        ~MemoryTable ()
        {
        }

        virtual const char *
        GetStringForKeyType (KeyType key) const
        {
            // The key in the DWARF table is the .debug_str offset for the string
            return m_string_table.PeekCStr (key);
        }
        
        virtual Result
        GetHashDataForName (const char *name,
                            uint32_t* hash_data_offset_ptr, 
                            Pair &pair) const
        {
            pair.key = m_data.GetU32 (hash_data_offset_ptr);
            pair.value.clear();

            // If the key is zero, this terminates our chain of HashData objects
            // for this hash value.
            if (pair.key == 0)
                return eResultEndOfHashData;

            // There definitely should be a string for this string offset, if
            // there isn't, there is something wrong, return and error
            const char *strp_cstr = m_string_table.PeekCStr (pair.key);
            if (strp_cstr == NULL)
            {
                *hash_data_offset_ptr = UINT32_MAX;
                return eResultError;
            }

            const uint32_t count = m_data.GetU32 (hash_data_offset_ptr);
            const uint32_t min_total_hash_data_size = count * m_header.header_data.GetMinumumHashDataByteSize();
            if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size))
            {
                // We have at least one HashData entry, and we have enough
                // data to parse at leats "count" HashData enties.
                
                // First make sure the entire C string matches...
                const bool match = strcmp (name, strp_cstr) == 0;
                
                if (!match && m_header.header_data.HashDataHasFixedByteSize())
                {
                    // If the string doesn't match and we have fixed size data,
                    // we can just add the total byte size of all HashData objects
                    // to the hash data offset and be done...
                    *hash_data_offset_ptr += min_total_hash_data_size;
                }
                else
                {
                    // If the string does match, or we don't have fixed size data
                    // then we need to read the hash data as a stream. If the
                    // string matches we also append all HashData objects to the
                    // value array.
                    for (uint32_t i=0; i<count; ++i)
                    {
                        DIEInfo die_info;
                        if (m_header.Read(m_data, hash_data_offset_ptr, die_info))
                        {
                            // Only happend the HashData if the string matched...
                            if (match)
                                pair.value.push_back (die_info);
                        }
                        else
                        {
                            // Something went wrong while reading the data
                            *hash_data_offset_ptr = UINT32_MAX;
                            return eResultError;
                        }
                    }
                }
                // Return the correct response depending on if the string matched
                // or not...
                if (match)
                    return eResultKeyMatch;     // The key (cstring) matches and we have lookup results!
                else
                    return eResultKeyMismatch;  // The key doesn't match, this function will get called 
                                                // again for the next key/value or the key terminator
                                                // which in our case is a zero .debug_str offset.
            }
            else
            {
                *hash_data_offset_ptr = UINT32_MAX;
                return eResultError;
            }
        }

        virtual Result
        AppendHashDataForRegularExpression (const lldb_private::RegularExpression& regex,
                                            uint32_t* hash_data_offset_ptr, 
                                            Pair &pair) const
        {
            pair.key = m_data.GetU32 (hash_data_offset_ptr);
            // If the key is zero, this terminates our chain of HashData objects
            // for this hash value.
            if (pair.key == 0)
                return eResultEndOfHashData;
            
            // There definitely should be a string for this string offset, if
            // there isn't, there is something wrong, return and error
            const char *strp_cstr = m_string_table.PeekCStr (pair.key);
            if (strp_cstr == NULL)
                return eResultError;
            
            const uint32_t count = m_data.GetU32 (hash_data_offset_ptr);
            const uint32_t min_total_hash_data_size = count * m_header.header_data.GetMinumumHashDataByteSize();
            if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size))
            {
                const bool match = regex.Execute(strp_cstr);
                
                if (!match && m_header.header_data.HashDataHasFixedByteSize())
                {
                    // If the regex doesn't match and we have fixed size data,
                    // we can just add the total byte size of all HashData objects
                    // to the hash data offset and be done...
                    *hash_data_offset_ptr += min_total_hash_data_size;
                }
                else
                {
                    // If the string does match, or we don't have fixed size data
                    // then we need to read the hash data as a stream. If the
                    // string matches we also append all HashData objects to the
                    // value array.
                    for (uint32_t i=0; i<count; ++i)
                    {
                        DIEInfo die_info;
                        if (m_header.Read(m_data, hash_data_offset_ptr, die_info))
                        {
                            // Only happend the HashData if the string matched...
                            if (match)
                                pair.value.push_back (die_info);
                        }
                        else
                        {
                            // Something went wrong while reading the data
                            *hash_data_offset_ptr = UINT32_MAX;
                            return eResultError;
                        }
                    }
                }
                // Return the correct response depending on if the string matched
                // or not...
                if (match)
                    return eResultKeyMatch;     // The key (cstring) matches and we have lookup results!
                else
                    return eResultKeyMismatch;  // The key doesn't match, this function will get called 
                                                // again for the next key/value or the key terminator
                                                // which in our case is a zero .debug_str offset.
            }
            else
            {
                *hash_data_offset_ptr = UINT32_MAX;
                return eResultError;
            }
        }

        size_t
        AppendAllDIEsThatMatchingRegex (const lldb_private::RegularExpression& regex, 
                                        DIEInfoArray &die_info_array) const
        {
            const uint32_t hash_count = m_header.hashes_count;
            Pair pair;
            for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx)
            {
                uint32_t hash_data_offset = GetHashDataOffset (offset_idx);
                while (hash_data_offset != UINT32_MAX)
                {
                    const uint32_t prev_hash_data_offset = hash_data_offset;
                    Result hash_result = AppendHashDataForRegularExpression (regex, &hash_data_offset, pair);
                    if (prev_hash_data_offset == hash_data_offset)
                        break;

                    // Check the result of getting our hash data
                    switch (hash_result)
                    {
                        case eResultKeyMatch:
                        case eResultKeyMismatch:
                            // Whether we matches or not, it doesn't matter, we
                            // keep looking.
                            break;
                            
                        case eResultEndOfHashData:
                        case eResultError:
                            hash_data_offset = UINT32_MAX;
                            break;
                    }
                }
            }
            die_info_array.swap (pair.value);
            return die_info_array.size();
        }
        
        size_t
        AppendAllDIEsInRange (const uint32_t die_offset_start, 
                              const uint32_t die_offset_end, 
                              DIEInfoArray &die_info_array) const
        {
            const uint32_t hash_count = m_header.hashes_count;
            for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx)
            {
                bool done = false;
                uint32_t hash_data_offset = GetHashDataOffset (offset_idx);
                while (!done && hash_data_offset != UINT32_MAX)
                {
                    KeyType key = m_data.GetU32 (&hash_data_offset);
                    // If the key is zero, this terminates our chain of HashData objects
                    // for this hash value.
                    if (key == 0)
                        break;
                    
                    const uint32_t count = m_data.GetU32 (&hash_data_offset);
                    for (uint32_t i=0; i<count; ++i)
                    {
                        DIEInfo die_info;
                        if (m_header.Read(m_data, &hash_data_offset, die_info))
                        {
                            if (die_info.offset == 0)
                                done = true;
                            if (die_offset_start <= die_info.offset && die_info.offset < die_offset_end)
                                die_info_array.push_back(die_info);
                        }
                    }
                }
            }
            return die_info_array.size();
        }

        size_t
        FindByName (const char *name, DIEArray &die_offsets)
        {
            DIEInfoArray die_info_array;
            if (FindByName(name, die_info_array))
                DWARFMappedHash::ExtractDIEArray (die_info_array, die_offsets);
            return die_info_array.size();
        }

        size_t
        FindByNameAndTag (const char *name, 
                          const dw_tag_t tag, 
                          DIEArray &die_offsets)
        {
            DIEInfoArray die_info_array;
            if (FindByName(name, die_info_array))
                DWARFMappedHash::ExtractDIEArray (die_info_array, tag, die_offsets);
            return die_info_array.size();
        }

        size_t
        FindCompleteObjCClassByName (const char *name, DIEArray &die_offsets, bool must_be_implementation)
        {
            DIEInfoArray die_info_array;
            if (FindByName(name, die_info_array))
            {
                if (must_be_implementation && GetHeader().header_data.ContainsAtom (eAtomTypeTypeFlags))
                {
                    // If we have two atoms, then we have the DIE offset and
                    // the type flags so we can find the objective C class
                    // efficiently.
                    DWARFMappedHash::ExtractTypesFromDIEArray (die_info_array, 
                                                               UINT32_MAX,
                                                               eTypeFlagClassIsImplementation,
                                                               die_offsets);
                }
                else
                {
                    // We don't only want the one true definition, so try and see
                    // what we can find, and only return class or struct DIEs.
                    // If we do have the full implementation, then return it alone,
                    // else return all possible matches.
                    const bool return_implementation_only_if_available = true;
                    DWARFMappedHash::ExtractClassOrStructDIEArray (die_info_array, 
                                                                   return_implementation_only_if_available,
                                                                   die_offsets);
                }
            }
            return die_offsets.size();
        }

        size_t 
        FindByName (const char *name, DIEInfoArray &die_info_array)
        {
            Pair kv_pair;
            size_t old_size = die_info_array.size();
            if (Find (name, kv_pair))
            {
                die_info_array.swap(kv_pair.value);
                return die_info_array.size() - old_size;
            }
            return 0;
        }
        
    protected:
        const lldb_private::DataExtractor &m_data;
        const lldb_private::DataExtractor &m_string_table;
        std::string m_name;
    };
};


#endif  // SymbolFileDWARF_HashedNameToDIE_h_