Index: source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h +++ source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h @@ -10,7 +10,9 @@ #define liblldb_DWARFAbbreviationDeclaration_h_ #include "DWARFAttribute.h" +#include "DWARFDefines.h" #include "SymbolFileDWARF.h" +#include "llvm/Support/Error.h" class DWARFAbbreviationDeclaration { public: @@ -44,10 +46,18 @@ return m_attributes[idx].get_form(); } uint32_t FindAttributeIndex(dw_attr_t attr) const; - bool Extract(const lldb_private::DWARFDataExtractor &data, - lldb::offset_t *offset_ptr); - bool Extract(const lldb_private::DWARFDataExtractor &data, - lldb::offset_t *offset_ptr, dw_uleb128_t code); + + /// Extract one abbreviation declaration and all of its associated attributes. + /// Possible return values: + /// DWARFEnumState::Complete - the extraction completed successfully. This + /// was the last abbrev decl in a sequence, and the user should not call + /// this function again. + /// DWARFEnumState::MoreItems - the extraction completed successfully. The + /// user should call this function again to retrieve the next decl. + /// llvm::Error - A parsing error occurred. The debug info is malformed. + llvm::Expected + extract(const lldb_private::DWARFDataExtractor &data, + lldb::offset_t *offset_ptr); bool IsValid(); void Dump(lldb_private::Stream *s) const; bool operator==(const DWARFAbbreviationDeclaration &rhs) const; Index: source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp @@ -11,6 +11,8 @@ #include "lldb/Core/dwarf.h" #include "lldb/Utility/Stream.h" +#include "llvm/Object/Error.h" + #include "DWARFFormValue.h" using namespace lldb_private; @@ -23,41 +25,48 @@ : m_code(InvalidCode), m_tag(tag), m_has_children(has_children), m_attributes() {} -bool DWARFAbbreviationDeclaration::Extract(const DWARFDataExtractor &data, - lldb::offset_t *offset_ptr) { - return Extract(data, offset_ptr, data.GetULEB128(offset_ptr)); -} +llvm::Expected +DWARFAbbreviationDeclaration::extract(const DWARFDataExtractor &data, + lldb::offset_t *offset_ptr) { + m_code = data.GetULEB128(offset_ptr); + if (m_code == 0) + return DWARFEnumState::Complete; -bool DWARFAbbreviationDeclaration::Extract(const DWARFDataExtractor &data, - lldb::offset_t *offset_ptr, - dw_uleb128_t code) { - m_code = code; m_attributes.clear(); - if (m_code) { - m_tag = data.GetULEB128(offset_ptr); - m_has_children = data.GetU8(offset_ptr); - - while (data.ValidOffset(*offset_ptr)) { - dw_attr_t attr = data.GetULEB128(offset_ptr); - dw_form_t form = data.GetULEB128(offset_ptr); - DWARFFormValue::ValueType val; - - if (form == DW_FORM_implicit_const) - val.value.sval = data.GetULEB128(offset_ptr); - - if (attr && form) - m_attributes.push_back(DWARFAttribute(attr, form, val)); - else - break; - } - - return m_tag != 0; - } else { - m_tag = 0; - m_has_children = 0; + m_tag = data.GetULEB128(offset_ptr); + if (m_tag == DW_TAG_null) { + // FIXME: According to the DWARF spec this may actually be malformed. + // Should this return an error instead? + return DWARFEnumState::Complete; + } + + m_has_children = data.GetU8(offset_ptr); + + while (data.ValidOffset(*offset_ptr)) { + dw_attr_t attr = data.GetULEB128(offset_ptr); + dw_form_t form = data.GetULEB128(offset_ptr); + + // This is the last attribute for this abbrev decl, but there may still be + // more abbrev decls, so return MoreItems to indicate to the caller that + // they should call this function again. + if (!attr && !form) + return DWARFEnumState::MoreItems; + + if (!attr || !form) + return llvm::make_error( + "malformed abbreviation declaration attribute"); + + DWARFFormValue::ValueType val; + + if (form == DW_FORM_implicit_const) + val.value.sval = data.GetULEB128(offset_ptr); + + m_attributes.push_back(DWARFAttribute(attr, form, val)); } - return false; + return llvm::make_error( + "abbreviation declaration attribute list not terminated with a null " + "entry"); } void DWARFAbbreviationDeclaration::Dump(Stream *s) const { Index: source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h +++ source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h @@ -35,8 +35,11 @@ void Clear(); dw_offset_t GetOffset() const { return m_offset; } void Dump(lldb_private::Stream *s) const; - bool Extract(const lldb_private::DWARFDataExtractor &data, - lldb::offset_t *offset_ptr); + + /// Extract all abbrev decls in a set. Returns llvm::ErrorSuccess() on + /// success, and an appropriate llvm::Error object otherwise. + llvm::Error extract(const lldb_private::DWARFDataExtractor &data, + lldb::offset_t *offset_ptr); // void Encode(BinaryStreamBuf& debug_abbrev_buf) const; dw_uleb128_t AppendAbbrevDeclSequential(const DWARFAbbreviationDeclaration &abbrevDecl); @@ -64,7 +67,11 @@ const DWARFAbbreviationDeclarationSet * GetAbbreviationDeclarationSet(dw_offset_t cu_abbr_offset) const; void Dump(lldb_private::Stream *s) const; - void Parse(const lldb_private::DWARFDataExtractor &data); + + /// Extract all abbreviations for a particular compile unit. Returns + /// llvm::ErrorSuccess() on success, and an appropriate llvm::Error object + /// otherwise. + llvm::Error parse(const lldb_private::DWARFDataExtractor &data); void GetUnsupportedForms(std::set &invalid_forms) const; protected: Index: source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp @@ -25,14 +25,22 @@ //---------------------------------------------------------------------- // DWARFAbbreviationDeclarationSet::Extract() //---------------------------------------------------------------------- -bool DWARFAbbreviationDeclarationSet::Extract(const DWARFDataExtractor &data, - lldb::offset_t *offset_ptr) { +llvm::Error +DWARFAbbreviationDeclarationSet::extract(const DWARFDataExtractor &data, + lldb::offset_t *offset_ptr) { const lldb::offset_t begin_offset = *offset_ptr; m_offset = begin_offset; Clear(); DWARFAbbreviationDeclaration abbrevDeclaration; dw_uleb128_t prev_abbr_code = 0; - while (abbrevDeclaration.Extract(data, offset_ptr)) { + DWARFEnumState state = DWARFEnumState::MoreItems; + while (state == DWARFEnumState::MoreItems) { + llvm::Expected es = + abbrevDeclaration.extract(data, offset_ptr); + if (!es) + return es.takeError(); + + state = *es; m_decls.push_back(abbrevDeclaration); if (m_idx_offset == 0) m_idx_offset = abbrevDeclaration.Code(); @@ -43,7 +51,7 @@ } prev_abbr_code = abbrevDeclaration.Code(); } - return begin_offset != *offset_ptr; + return llvm::ErrorSuccess(); } //---------------------------------------------------------------------- @@ -138,19 +146,21 @@ //---------------------------------------------------------------------- // DWARFDebugAbbrev::Parse() //---------------------------------------------------------------------- -void DWARFDebugAbbrev::Parse(const DWARFDataExtractor &data) { +llvm::Error DWARFDebugAbbrev::parse(const DWARFDataExtractor &data) { lldb::offset_t offset = 0; while (data.ValidOffset(offset)) { uint32_t initial_cu_offset = offset; DWARFAbbreviationDeclarationSet abbrevDeclSet; - if (abbrevDeclSet.Extract(data, &offset)) - m_abbrevCollMap[initial_cu_offset] = abbrevDeclSet; - else - break; + llvm::Error error = abbrevDeclSet.extract(data, &offset); + if (error) + return error; + + m_abbrevCollMap[initial_cu_offset] = abbrevDeclSet; } m_prev_abbr_offset_pos = m_abbrevCollMap.end(); + return llvm::ErrorSuccess(); } //---------------------------------------------------------------------- Index: source/Plugins/SymbolFile/DWARF/DWARFDefines.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDefines.h +++ source/Plugins/SymbolFile/DWARF/DWARFDefines.h @@ -14,6 +14,8 @@ namespace lldb_private { +enum class DWARFEnumState { MoreItems, Complete }; + typedef uint32_t DRC_class; // Holds DRC_* class bitfields enum DW_TAG_Category { Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -660,14 +660,23 @@ } DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { - if (m_abbr == NULL) { - const DWARFDataExtractor &debug_abbrev_data = get_debug_abbrev_data(); - if (debug_abbrev_data.GetByteSize() > 0) { - m_abbr.reset(new DWARFDebugAbbrev()); - if (m_abbr) - m_abbr->Parse(debug_abbrev_data); - } + if (m_abbr) + return m_abbr.get(); + + const DWARFDataExtractor &debug_abbrev_data = get_debug_abbrev_data(); + if (debug_abbrev_data.GetByteSize() == 0) + return nullptr; + + auto abbr = llvm::make_unique(); + llvm::Error error = abbr->parse(debug_abbrev_data); + if (error) { + Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO); + LLDB_LOG_ERROR(log, std::move(error), + "Unable to read .debug_abbrev section: {0}"); + return nullptr; } + + m_abbr = std::move(abbr); return m_abbr.get(); }