Index: include/lldb/Symbol/CompileUnit.h =================================================================== --- include/lldb/Symbol/CompileUnit.h +++ include/lldb/Symbol/CompileUnit.h @@ -11,6 +11,7 @@ #define liblldb_CompUnit_h_ #include "lldb/lldb-enumerations.h" +#include "lldb/Symbol/DebugMacros.h" #include "lldb/Symbol/Function.h" #include "lldb/Core/FileSpecList.h" #include "lldb/Core/ModuleChild.h" @@ -250,6 +251,9 @@ LineTable* GetLineTable (); + DebugMacros* + GetDebugMacros (); + //------------------------------------------------------------------ /// Get the compile unit's support file list. /// @@ -344,6 +348,9 @@ void SetLineTable(LineTable* line_table); + void + SetDebugMacros(const DebugMacrosSP &debug_macros); + //------------------------------------------------------------------ /// Set accessor for the variable list. /// @@ -437,6 +444,7 @@ ///< compile unit. FileSpecList m_support_files; ///< Files associated with this compile unit's line table and declarations. std::unique_ptr m_line_table_ap; ///< Line table that will get parsed on demand. + DebugMacrosSP m_debug_macros_sp; ///< Debug macros that will get parsed on demand. lldb::VariableListSP m_variables; ///< Global and static variable list that will get parsed on demand. bool m_is_optimized; /// eLazyBoolYes if this compile unit was compiled with optimization. @@ -448,7 +456,8 @@ flagsParsedSupportFiles = (1u << 2), ///< Have we already parsed the support files for this compile unit? flagsParsedLineTable = (1u << 3), ///< Have we parsed the line table already? flagsParsedLanguage = (1u << 4), ///< Have we parsed the language already? - flagsParsedImportedModules = (1u << 5) ///< Have we parsed the imported modules already? + flagsParsedImportedModules = (1u << 5), ///< Have we parsed the imported modules already? + flagsParsedDebugMacros = (1u << 6) ///< Have we parsed the debug macros already? }; DISALLOW_COPY_AND_ASSIGN (CompileUnit); Index: include/lldb/Symbol/DebugMacros.h =================================================================== --- /dev/null +++ include/lldb/Symbol/DebugMacros.h @@ -0,0 +1,140 @@ +//===-- DebugMacros.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DebugMacros_h_ +#define liblldb_DebugMacros_h_ + +// C Includes +// C++ Includes +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Core/ConstString.h" + +namespace lldb_private { + +class CompileUnit; +class DebugMacros; +typedef std::shared_ptr DebugMacrosSP; + +class DebugMacroEntry +{ +public: + enum EntryType + { + INVALID, + DEFINE, + UNDEF, + START_FILE, + END_FILE, + INDIRECT + }; + +public: + static DebugMacroEntry + CreateDefineEntry(uint32_t line, const char *str); + + static DebugMacroEntry + CreateUndefEntry(uint32_t line, const char *str); + + static DebugMacroEntry + CreateStartFileEntry(uint32_t line, uint32_t debug_line_file_idx); + + static DebugMacroEntry + CreateEndFileEntry(); + + static DebugMacroEntry + CreateIndirectEntry(const DebugMacrosSP &debug_macros_sp); + + DebugMacroEntry() : m_type(INVALID) { } + + ~DebugMacroEntry() = default; + + EntryType + GetType() const + { + return m_type; + } + + uint64_t + GetLineNumber() const + { + return m_line; + } + + ConstString + GetMacroString() const + { + return m_str; + } + + const FileSpec& GetFileSpec(CompileUnit *comp_unit) const; + + DebugMacros * + GetIndirectDebugMacros() const + { + return m_debug_macros_sp.get(); + } + +private: + DebugMacroEntry(EntryType type, + uint32_t line, + uint32_t debug_line_file_idx, + const char *str); + + DebugMacroEntry(EntryType type, + const DebugMacrosSP &debug_macros_sp); + + EntryType m_type:3; + uint32_t m_line:29; + uint32_t m_debug_line_file_idx; + ConstString m_str; + DebugMacrosSP m_debug_macros_sp; +}; + +class DebugMacros +{ +public: + DebugMacros() = default; + + ~DebugMacros() = default; + + void + AddMacroEntry(const DebugMacroEntry &entry) + { + m_macro_entries.push_back(entry); + } + + size_t + GetNumMacroEntries() const + { + return m_macro_entries.size(); + } + + DebugMacroEntry + GetMacroEntryAtIndex(const size_t index) const + { + if (index < m_macro_entries.size()) + return m_macro_entries[index]; + else + return DebugMacroEntry(); + } + +private: + DISALLOW_COPY_AND_ASSIGN(DebugMacros); + + std::vector m_macro_entries; +}; + +} // namespace lldb_private + +#endif // liblldb_DebugMacros_h_ Index: include/lldb/Symbol/SymbolFile.h =================================================================== --- include/lldb/Symbol/SymbolFile.h +++ include/lldb/Symbol/SymbolFile.h @@ -123,6 +123,7 @@ virtual lldb::LanguageType ParseCompileUnitLanguage (const SymbolContext& sc) = 0; virtual size_t ParseCompileUnitFunctions (const SymbolContext& sc) = 0; virtual bool ParseCompileUnitLineTable (const SymbolContext& sc) = 0; + virtual bool ParseCompileUnitDebugMacros (const SymbolContext& sc) = 0; virtual bool ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList& support_files) = 0; virtual bool ParseImportedModules (const SymbolContext &sc, std::vector &imported_modules) = 0; virtual size_t ParseFunctionBlocks (const SymbolContext& sc) = 0; Index: include/lldb/Symbol/SymbolVendor.h =================================================================== --- include/lldb/Symbol/SymbolVendor.h +++ include/lldb/Symbol/SymbolVendor.h @@ -62,6 +62,9 @@ ParseCompileUnitLineTable (const SymbolContext& sc); virtual bool + ParseCompileUnitDebugMacros (const SymbolContext& sc); + + virtual bool ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList& support_files); Index: include/lldb/lldb-enumerations.h =================================================================== --- include/lldb/lldb-enumerations.h +++ include/lldb/lldb-enumerations.h @@ -603,6 +603,7 @@ eSectionTypeDWARFDebugLine, eSectionTypeDWARFDebugLoc, eSectionTypeDWARFDebugMacInfo, + eSectionTypeDWARFDebugMacro, eSectionTypeDWARFDebugPubNames, eSectionTypeDWARFDebugPubTypes, eSectionTypeDWARFDebugRanges, Index: packages/Python/lldbsuite/test/expression_command/macros/Makefile =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/expression_command/macros/Makefile @@ -0,0 +1,8 @@ +LEVEL = ../../make + +CXX_SOURCES := main.cpp + +DEBUG_INFO_FLAG = -g3 + + +include $(LEVEL)/Makefile.rules Index: packages/Python/lldbsuite/test/expression_command/macros/TestMacros.py =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/expression_command/macros/TestMacros.py @@ -0,0 +1,105 @@ +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil + +class TestMacros(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @expectedFailureClang("clang does not emit .debug_macro[.dwo] sections.") + @expectedFailureDwo("GCC produces multiple .debug_macro.dwo sections and the spec is unclear as to what it means") + def test_expr_with_macros(self): + self.build() + + # Get main source file + src_file = "main.cpp" + hdr_file = "macro1.h" + src_file_spec = lldb.SBFileSpec(src_file) + self.assertTrue(src_file_spec.IsValid(), "Main source file") + + # Get the path of the executable + cwd = os.getcwd() + exe_file = "a.out" + exe_path = os.path.join(cwd, exe_file) + + # Load the executable + target = self.dbg.CreateTarget(exe_path) + self.assertTrue(target.IsValid(), VALID_TARGET) + + # Set breakpoints + bp1 = target.BreakpointCreateBySourceRegex("Break here", src_file_spec) + self.assertTrue(bp1.IsValid() and bp1.GetNumLocations() >= 1, VALID_BREAKPOINT) + + # Launch the process + process = target.LaunchSimple(None, None, self.get_process_working_directory()) + self.assertTrue(process.IsValid(), PROCESS_IS_VALID) + + # Get the thread of the process + self.assertTrue(process.GetState() == lldb.eStateStopped, PROCESS_STOPPED) + thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) + + # Get frame for current thread + frame = thread.GetSelectedFrame() + + result = frame.EvaluateExpression("MACRO_1") + self.assertTrue(result.IsValid() and result.GetValue() == "100", "MACRO_1 = 100") + + result = frame.EvaluateExpression("MACRO_2") + self.assertTrue(result.IsValid() and result.GetValue() == "200", "MACRO_2 = 200") + + result = frame.EvaluateExpression("ONE") + self.assertTrue(result.IsValid() and result.GetValue() == "1", "ONE = 1") + + result = frame.EvaluateExpression("TWO") + self.assertTrue(result.IsValid() and result.GetValue() == "2", "TWO = 2") + + result = frame.EvaluateExpression("THREE") + self.assertTrue(result.IsValid() and result.GetValue() == "3", "THREE = 3") + + result = frame.EvaluateExpression("FOUR") + self.assertTrue(result.IsValid() and result.GetValue() == "4", "FOUR = 4") + + result = frame.EvaluateExpression("HUNDRED") + self.assertTrue(result.IsValid() and result.GetValue() == "100", "HUNDRED = 100") + + result = frame.EvaluateExpression("THOUSAND") + self.assertTrue(result.IsValid() and result.GetValue() == "1000", "THOUSAND = 1000") + + result = frame.EvaluateExpression("MILLION") + self.assertTrue(result.IsValid() and result.GetValue() == "1000000", "MILLION = 1000000") + + result = frame.EvaluateExpression("MAX(ONE, TWO)") + self.assertTrue(result.IsValid() and result.GetValue() == "2", "MAX(ONE, TWO) = 2") + + result = frame.EvaluateExpression("MAX(THREE, TWO)") + self.assertTrue(result.IsValid() and result.GetValue() == "3", "MAX(THREE, TWO) = 3") + + # Get the thread of the process + thread.StepOver() + + # Get frame for current thread + frame = thread.GetSelectedFrame() + + result = frame.EvaluateExpression("MACRO_2") + self.assertTrue(result.GetError().Fail(), "Printing MACRO_2 fails in the mail file") + + result = frame.EvaluateExpression("FOUR") + self.assertTrue(result.GetError().Fail(), "Printing FOUR fails in the main file") + + thread.StepInto() + + # Get frame for current thread + frame = thread.GetSelectedFrame() + + result = frame.EvaluateExpression("ONE") + self.assertTrue(result.IsValid() and result.GetValue() == "1", "ONE = 1") + + result = frame.EvaluateExpression("MAX(ONE, TWO)") + self.assertTrue(result.IsValid() and result.GetValue() == "2", "MAX(ONE, TWO) = 2") + + # This time, MACRO_1 and MACRO_2 are not visible. + result = frame.EvaluateExpression("MACRO_1") + self.assertTrue(result.GetError().Fail(), "Printing MACRO_1 fails in the header file") + + result = frame.EvaluateExpression("MACRO_2") + self.assertTrue(result.GetError().Fail(), "Printing MACRO_2 fails in the header file") Index: packages/Python/lldbsuite/test/expression_command/macros/macro1.h =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/expression_command/macros/macro1.h @@ -0,0 +1,17 @@ + +#include "macro2.h" + +#define ONE 1 +#define TWO 2 +#define THREE 3 +#define FOUR 4 + +class Simple +{ +public: + int + Method() + { + return ONE + TWO; + }; +}; Index: packages/Python/lldbsuite/test/expression_command/macros/macro2.h =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/expression_command/macros/macro2.h @@ -0,0 +1,8 @@ +#define HUNDRED 100 +#define THOUSAND 1000 +#define MILLION 1000000 + +#define MAX(a, b)\ +((a) > (b) ?\ + (a):\ + (b)) Index: packages/Python/lldbsuite/test/expression_command/macros/main.cpp =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/expression_command/macros/main.cpp @@ -0,0 +1,15 @@ +#include "macro1.h" + +#define MACRO_1 100 +#define MACRO_2 200 + +int +main () +{ + int a = ONE + TWO; // Break here + + #undef MACRO_2 + #undef FOUR + + return Simple().Method(); +} Index: packages/Python/lldbsuite/test/make/Makefile.rules =================================================================== --- packages/Python/lldbsuite/test/make/Makefile.rules +++ packages/Python/lldbsuite/test/make/Makefile.rules @@ -182,7 +182,9 @@ LIMIT_DEBUG_INFO_FLAGS += -flimit-debug-info endif -CFLAGS ?= -g -O0 -fno-builtin +DEBUG_INFO_FLAG ?= -g + +CFLAGS ?= $(DEBUG_INFO_FLAG) -O0 -fno-builtin ifeq "$(OS)" "Darwin" CFLAGS += $(ARCHFLAG) $(ARCH) $(FRAMEWORK_INCLUDES) $(CFLAGS_EXTRAS) -I$(LLDB_BASE_DIR)include else Index: source/Expression/ExpressionSourceCode.cpp =================================================================== --- source/Expression/ExpressionSourceCode.cpp +++ source/Expression/ExpressionSourceCode.cpp @@ -12,6 +12,8 @@ #include "lldb/Core/StreamString.h" #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/DebugMacros.h" #include "lldb/Symbol/Block.h" #include "lldb/Symbol/TypeSystem.h" #include "lldb/Target/ExecutionContext.h" @@ -57,6 +59,121 @@ } )"; +namespace { + +class AddMacroState +{ + enum State + { + CURRENT_FILE_NOT_YET_PUSHED, + CURRENT_FILE_PUSHED, + CURRENT_FILE_POPPED + }; + +public: + AddMacroState(const FileSpec ¤t_file, const uint32_t current_file_line) + : m_state(CURRENT_FILE_NOT_YET_PUSHED), + m_current_file(current_file), + m_current_file_line(current_file_line) + { } + + void + StartFile(const FileSpec &file) + { + m_file_stack.push_back(file); + if (file == m_current_file) + m_state = CURRENT_FILE_PUSHED; + } + + void + EndFile() + { + if (m_file_stack.size() == 0) + return; + + FileSpec old_top = m_file_stack.back(); + m_file_stack.pop_back(); + if (old_top == m_current_file) + m_state = CURRENT_FILE_POPPED; + } + + // An entry is valid if it occurs before the current line in + // the current file. + bool + IsValidEntry(uint32_t line) + { + switch (m_state) + { + case CURRENT_FILE_NOT_YET_PUSHED: + return true; + case CURRENT_FILE_POPPED: + return false; + case CURRENT_FILE_PUSHED: + // If we are in file included in the current file, + // the entry should be added. + if (m_file_stack.back() != m_current_file) + return true; + + if (line >= m_current_file_line) + return false; + else + return true; + } + } + +private: + std::vector m_file_stack; + State m_state; + FileSpec m_current_file; + uint32_t m_current_file_line; +}; + +} // anonymous namespace + +static void +AddMacros(const DebugMacros *dm, CompileUnit *comp_unit, AddMacroState &state, StreamString &stream) +{ + if (dm == nullptr) + return; + + for (size_t i = 0; i < dm->GetNumMacroEntries(); i++) + { + const DebugMacroEntry &entry = dm->GetMacroEntryAtIndex(i); + uint32_t line; + + switch (entry.GetType()) + { + case DebugMacroEntry::DEFINE: + if (state.IsValidEntry(entry.GetLineNumber())) + stream.Printf("#define %s\n", entry.GetMacroString().AsCString()); + else + return; + break; + case DebugMacroEntry::UNDEF: + if (state.IsValidEntry(entry.GetLineNumber())) + stream.Printf("#undef %s\n", entry.GetMacroString().AsCString()); + else + return; + break; + case DebugMacroEntry::START_FILE: + line = entry.GetLineNumber(); + if (state.IsValidEntry(line)) + state.StartFile(entry.GetFileSpec(comp_unit)); + else + return; + break; + case DebugMacroEntry::END_FILE: + state.EndFile(); + break; + case DebugMacroEntry::INDIRECT: + AddMacros(entry.GetIndirectDebugMacros(), comp_unit, state, stream); + break; + default: + // This is an unknown/invalid entry. Ignore. + break; + } + } +} bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrapping_language, bool const_object, bool static_method, ExecutionContext &exe_ctx) const { @@ -120,6 +237,23 @@ } } + + StreamString debug_macros_stream; + if (StackFrame *frame = exe_ctx.GetFramePtr()) + { + const SymbolContext &sc = frame->GetSymbolContext( + lldb:: eSymbolContextCompUnit | lldb::eSymbolContextLineEntry); + + if (sc.comp_unit && sc.line_entry.IsValid()) + { + DebugMacros *dm = sc.comp_unit->GetDebugMacros(); + if (dm) + { + AddMacroState state(sc.line_entry.file, sc.line_entry.line); + AddMacros(dm, sc.comp_unit, state, debug_macros_stream); + } + } + } if (m_wrap) { @@ -135,8 +269,9 @@ StreamString wrap_stream; - wrap_stream.Printf("%s\n%s\n%s\n%s\n", + wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", module_macros.c_str(), + debug_macros_stream.GetData(), g_expression_prefix, target_specific_defines, m_prefix.c_str()); Index: source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp =================================================================== --- source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -1772,6 +1772,7 @@ static ConstString g_sect_name_dwarf_debug_line (".debug_line"); static ConstString g_sect_name_dwarf_debug_loc (".debug_loc"); static ConstString g_sect_name_dwarf_debug_macinfo (".debug_macinfo"); + static ConstString g_sect_name_dwarf_debug_macro (".debug_macro"); static ConstString g_sect_name_dwarf_debug_pubnames (".debug_pubnames"); static ConstString g_sect_name_dwarf_debug_pubtypes (".debug_pubtypes"); static ConstString g_sect_name_dwarf_debug_ranges (".debug_ranges"); @@ -1780,6 +1781,7 @@ static ConstString g_sect_name_dwarf_debug_abbrev_dwo (".debug_abbrev.dwo"); static ConstString g_sect_name_dwarf_debug_info_dwo (".debug_info.dwo"); static ConstString g_sect_name_dwarf_debug_line_dwo (".debug_line.dwo"); + static ConstString g_sect_name_dwarf_debug_macro_dwo (".debug_macro.dwo"); static ConstString g_sect_name_dwarf_debug_loc_dwo (".debug_loc.dwo"); static ConstString g_sect_name_dwarf_debug_str_dwo (".debug_str.dwo"); static ConstString g_sect_name_dwarf_debug_str_offsets_dwo (".debug_str_offsets.dwo"); @@ -1827,6 +1829,7 @@ else if (name == g_sect_name_dwarf_debug_line) sect_type = eSectionTypeDWARFDebugLine; else if (name == g_sect_name_dwarf_debug_loc) sect_type = eSectionTypeDWARFDebugLoc; else if (name == g_sect_name_dwarf_debug_macinfo) sect_type = eSectionTypeDWARFDebugMacInfo; + else if (name == g_sect_name_dwarf_debug_macro) sect_type = eSectionTypeDWARFDebugMacro; else if (name == g_sect_name_dwarf_debug_pubnames) sect_type = eSectionTypeDWARFDebugPubNames; else if (name == g_sect_name_dwarf_debug_pubtypes) sect_type = eSectionTypeDWARFDebugPubTypes; else if (name == g_sect_name_dwarf_debug_ranges) sect_type = eSectionTypeDWARFDebugRanges; @@ -1835,6 +1838,7 @@ else if (name == g_sect_name_dwarf_debug_abbrev_dwo) sect_type = eSectionTypeDWARFDebugAbbrev; else if (name == g_sect_name_dwarf_debug_info_dwo) sect_type = eSectionTypeDWARFDebugInfo; else if (name == g_sect_name_dwarf_debug_line_dwo) sect_type = eSectionTypeDWARFDebugLine; + else if (name == g_sect_name_dwarf_debug_macro_dwo) sect_type = eSectionTypeDWARFDebugMacro; else if (name == g_sect_name_dwarf_debug_loc_dwo) sect_type = eSectionTypeDWARFDebugLoc; else if (name == g_sect_name_dwarf_debug_str_dwo) sect_type = eSectionTypeDWARFDebugStr; else if (name == g_sect_name_dwarf_debug_str_offsets_dwo) sect_type = eSectionTypeDWARFDebugStrOffsets; Index: source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp =================================================================== --- source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -1369,6 +1369,7 @@ case eSectionTypeDWARFDebugLine: case eSectionTypeDWARFDebugLoc: case eSectionTypeDWARFDebugMacInfo: + case eSectionTypeDWARFDebugMacro: case eSectionTypeDWARFDebugPubNames: case eSectionTypeDWARFDebugPubTypes: case eSectionTypeDWARFDebugRanges: Index: source/Plugins/SymbolFile/DWARF/CMakeLists.txt =================================================================== --- source/Plugins/SymbolFile/DWARF/CMakeLists.txt +++ source/Plugins/SymbolFile/DWARF/CMakeLists.txt @@ -12,6 +12,7 @@ DWARFDebugInfo.cpp DWARFDebugInfoEntry.cpp DWARFDebugLine.cpp + DWARFDebugMacro.cpp DWARFDebugMacinfo.cpp DWARFDebugMacinfoEntry.cpp DWARFDebugPubnames.cpp Index: source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.h =================================================================== --- /dev/null +++ source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.h @@ -0,0 +1,68 @@ +//===-- DWARFDebugMacro.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_DWARFDebugMacro_h_ +#define SymbolFileDWARF_DWARFDebugMacro_h_ + +#include + +#include "lldb/lldb-types.h" +#include "lldb/Core/dwarf.h" +#include "lldb/Symbol/DebugMacros.h" + +namespace lldb_private +{ + +class DWARFDataExtractor; + +} // namespace lldb_private + +class SymbolFileDWARF; + +class DWARFDebugMacroHeader +{ +public: + enum HeaderFlagMask + { + OFFSET_SIZE_MASK = 0x1, + DEBUG_LINE_OFFSET_MASK = 0x2, + OPCODE_OPERANDS_TABLE_MASK = 0x4 + }; + + static DWARFDebugMacroHeader + ParseHeader(const lldb_private::DWARFDataExtractor &debug_macro_data, lldb::offset_t *offset); + + bool + OffsetIs64Bit() const + { + return m_offset_is_64_bit; + } + +private: + static void + SkipOperandTable(const lldb_private::DWARFDataExtractor &debug_macro_data, lldb::offset_t *offset); + + uint16_t m_version; + bool m_offset_is_64_bit; + uint64_t m_debug_line_offset; +}; + +class DWARFDebugMacroEntry +{ +public: + static void + ReadMacroEntries(const lldb_private::DWARFDataExtractor &debug_macro_data, + const lldb_private::DWARFDataExtractor &debug_str_data, + const bool offset_is_64_bit, + lldb::offset_t *sect_offset, + SymbolFileDWARF *sym_file_dwarf, + lldb_private::DebugMacrosSP &debug_macros_sp); +}; + +#endif // SymbolFileDWARF_DWARFDebugMacro_h_ Index: source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp =================================================================== --- /dev/null +++ source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp @@ -0,0 +1,128 @@ +//===-- DWARFDebugMacro.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugMacro.h" +#include "SymbolFileDWARF.h" + +#include "lldb/Symbol/DebugMacros.h" + +#include "DWARFDataExtractor.h" + +using namespace lldb_private; + +DWARFDebugMacroHeader +DWARFDebugMacroHeader::ParseHeader(const DWARFDataExtractor &debug_macro_data, lldb::offset_t *offset) +{ + DWARFDebugMacroHeader header; + + // Skip over the version field in header. + header.m_version = debug_macro_data.GetU16(offset); + + uint8_t flags = debug_macro_data.GetU8(offset); + header.m_offset_is_64_bit = flags & OFFSET_SIZE_MASK ? true : false; + + if (flags & DEBUG_LINE_OFFSET_MASK) + { + if (header.m_offset_is_64_bit) + header.m_debug_line_offset = debug_macro_data.GetU64(offset); + else + header.m_debug_line_offset = debug_macro_data.GetU32(offset); + } + + // Skip over the operands table if it is present. + if (flags & OPCODE_OPERANDS_TABLE_MASK) + SkipOperandTable(debug_macro_data, offset); + + return header; +} + +void +DWARFDebugMacroHeader::SkipOperandTable(const DWARFDataExtractor &debug_macro_data, lldb::offset_t *offset) +{ + uint8_t entry_count = debug_macro_data.GetU8(offset); + for (uint8_t i = 0; i < entry_count; i++) + { + // Skip over the opcode number. + debug_macro_data.GetU8(offset); + + uint64_t operand_count = debug_macro_data.GetULEB128(offset); + + for (uint64_t j = 0; j < operand_count; j++) + { + // Skip over the operand form + debug_macro_data.GetU8(offset); + } + } +} + +void +DWARFDebugMacroEntry::ReadMacroEntries(const DWARFDataExtractor &debug_macro_data, + const DWARFDataExtractor &debug_str_data, + const bool offset_is_64_bit, + lldb::offset_t *offset, + SymbolFileDWARF *sym_file_dwarf, + DebugMacrosSP &debug_macros_sp) +{ + llvm::dwarf::MacroEntryType type = static_cast(debug_macro_data.GetU8(offset)); + while (type != 0) + { + lldb::offset_t new_offset = 0, str_offset = 0; + uint32_t line = 0; + const char *macro_str = nullptr; + uint32_t debug_line_file_idx = 0; + + switch (type) + { + case DW_MACRO_define: + case DW_MACRO_undef: + line = debug_macro_data.GetULEB128(offset); + macro_str = debug_macro_data.GetCStr(offset); + if (type == DW_MACRO_define) + debug_macros_sp->AddMacroEntry(DebugMacroEntry::CreateDefineEntry(line, macro_str)); + else + debug_macros_sp->AddMacroEntry(DebugMacroEntry::CreateUndefEntry(line, macro_str)); + break; + case DW_MACRO_define_indirect: + case DW_MACRO_undef_indirect: + line = debug_macro_data.GetULEB128(offset); + if (offset_is_64_bit) + str_offset = debug_macro_data.GetU64(offset); + else + str_offset = debug_macro_data.GetU32(offset); + macro_str = debug_str_data.GetCStr(&str_offset); + if (type == DW_MACRO_define_indirect) + debug_macros_sp->AddMacroEntry(DebugMacroEntry::CreateDefineEntry(line, macro_str)); + else + debug_macros_sp->AddMacroEntry(DebugMacroEntry::CreateUndefEntry(line, macro_str)); + break; + case DW_MACRO_start_file: + line = debug_macro_data.GetULEB128(offset); + debug_line_file_idx = debug_macro_data.GetULEB128(offset); + debug_macros_sp->AddMacroEntry(DebugMacroEntry::CreateStartFileEntry(line, debug_line_file_idx)); + break; + case DW_MACRO_end_file: + // This operation has no operands. + debug_macros_sp->AddMacroEntry(DebugMacroEntry::CreateEndFileEntry()); + break; + case DW_MACRO_transparent_include: + if (offset_is_64_bit) + new_offset = debug_macro_data.GetU64(offset); + else + new_offset = debug_macro_data.GetU32(offset); + debug_macros_sp->AddMacroEntry( + DebugMacroEntry::CreateIndirectEntry(sym_file_dwarf->ParseDebugMacros(&new_offset))); + break; + default: + // TODO: Add support for other standard operations. + // TODO: Provide mechanism to hook handling of non-standard/extension operands. + return; + } + type = static_cast(debug_macro_data.GetU8(offset)); + } +} Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -16,6 +16,7 @@ #include #include #include +#include #include // Other libraries and framework includes @@ -28,6 +29,7 @@ #include "lldb/Core/RangeMap.h" #include "lldb/Core/UniqueCStringMap.h" #include "lldb/Expression/DWARFExpression.h" +#include "lldb/Symbol/DebugMacros.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/SymbolContext.h" @@ -124,6 +126,9 @@ ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc) override; bool + ParseCompileUnitDebugMacros (const lldb_private::SymbolContext& sc) override; + + bool ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList& support_files) override; @@ -248,6 +253,7 @@ const lldb_private::DWARFDataExtractor& get_debug_frame_data (); const lldb_private::DWARFDataExtractor& get_debug_info_data (); const lldb_private::DWARFDataExtractor& get_debug_line_data (); + const lldb_private::DWARFDataExtractor& get_debug_macro_data (); const lldb_private::DWARFDataExtractor& get_debug_loc_data (); const lldb_private::DWARFDataExtractor& get_debug_ranges_data (); const lldb_private::DWARFDataExtractor& get_debug_str_data (); @@ -302,6 +308,9 @@ bool Supports_DW_AT_APPLE_objc_complete_type (DWARFCompileUnit *cu); + lldb_private::DebugMacrosSP + ParseDebugMacros(lldb::offset_t *offset); + static DWARFDIE GetParentSymbolContextDIE(const DWARFDIE &die); @@ -530,6 +539,7 @@ DWARFDataSegment m_data_debug_frame; DWARFDataSegment m_data_debug_info; DWARFDataSegment m_data_debug_line; + DWARFDataSegment m_data_debug_macro; DWARFDataSegment m_data_debug_loc; DWARFDataSegment m_data_debug_ranges; DWARFDataSegment m_data_debug_str; @@ -549,6 +559,10 @@ std::unique_ptr m_apple_namespaces_ap; std::unique_ptr m_apple_objc_ap; std::unique_ptr m_global_aranges_ap; + + typedef std::unordered_map DebugMacrosMap; + DebugMacrosMap m_debug_macros_map; + ExternalTypeModuleMap m_external_type_modules; NameToDIE m_function_basename_index; // All concrete functions NameToDIE m_function_fullname_index; // All concrete functions Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -39,6 +39,7 @@ #include "lldb/Symbol/CompilerDeclContext.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/DebugMacros.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/TypeSystem.h" @@ -58,6 +59,7 @@ #include "DWARFDebugAranges.h" #include "DWARFDebugInfo.h" #include "DWARFDebugLine.h" +#include "DWARFDebugMacro.h" #include "DWARFDebugPubnames.h" #include "DWARFDebugRanges.h" #include "DWARFDeclContext.h" @@ -436,6 +438,7 @@ m_data_debug_frame (), m_data_debug_info (), m_data_debug_line (), + m_data_debug_macro (), m_data_debug_loc (), m_data_debug_ranges (), m_data_debug_str (), @@ -709,6 +712,12 @@ } const DWARFDataExtractor& +SymbolFileDWARF::get_debug_macro_data() +{ + return GetCachedSectionData (eSectionTypeDWARFDebugMacro, m_data_debug_macro); +} + +const DWARFDataExtractor& SymbolFileDWARF::get_debug_loc_data() { return GetCachedSectionData (eSectionTypeDWARFDebugLoc, m_data_debug_loc); @@ -1204,6 +1213,51 @@ return false; } +lldb_private::DebugMacrosSP +SymbolFileDWARF::ParseDebugMacros(lldb::offset_t *offset) +{ + auto iter = m_debug_macros_map.find(*offset); + if (iter != m_debug_macros_map.end()) + return iter->second; + + const DWARFDataExtractor &debug_macro_data = get_debug_macro_data(); + if (debug_macro_data.GetByteSize() == 0) + return DebugMacrosSP(); + + lldb_private::DebugMacrosSP debug_macros_sp(new lldb_private::DebugMacros()); + m_debug_macros_map[*offset] = debug_macros_sp; + + const DWARFDebugMacroHeader &header = DWARFDebugMacroHeader::ParseHeader(debug_macro_data, offset); + DWARFDebugMacroEntry::ReadMacroEntries( + debug_macro_data, get_debug_str_data(), header.OffsetIs64Bit(), offset, this, debug_macros_sp); + + return debug_macros_sp; +} + +bool +SymbolFileDWARF::ParseCompileUnitDebugMacros(const SymbolContext& sc) +{ + assert (sc.comp_unit); + + DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + if (dwarf_cu == nullptr) + return false; + + const DWARFDIE dwarf_cu_die = dwarf_cu->GetCompileUnitDIEOnly(); + if (!dwarf_cu_die) + return false; + + lldb::offset_t sect_offset = dwarf_cu_die.GetAttributeValueAsUnsigned(DW_AT_macros, DW_INVALID_OFFSET); + if (sect_offset == DW_INVALID_OFFSET) + sect_offset = dwarf_cu_die.GetAttributeValueAsUnsigned(DW_AT_GNU_macros, DW_INVALID_OFFSET); + if (sect_offset == DW_INVALID_OFFSET) + return false; + + sc.comp_unit->SetDebugMacros(ParseDebugMacros(§_offset)); + + return true; +} + size_t SymbolFileDWARF::ParseFunctionBlocks (const SymbolContext& sc, Block *parent_block, Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -63,6 +63,7 @@ lldb::LanguageType ParseCompileUnitLanguage (const lldb_private::SymbolContext& sc) override; size_t ParseCompileUnitFunctions (const lldb_private::SymbolContext& sc) override; bool ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc) override; + bool ParseCompileUnitDebugMacros (const lldb_private::SymbolContext& sc) override; bool ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList &support_files) override; bool ParseImportedModules (const lldb_private::SymbolContext &sc, std::vector &imported_modules) override; size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc) override; Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -707,6 +707,15 @@ } bool +SymbolFileDWARFDebugMap::ParseCompileUnitDebugMacros (const SymbolContext& sc) +{ + SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc); + if (oso_dwarf) + return oso_dwarf->ParseCompileUnitDebugMacros (sc); + return false; +} + +bool SymbolFileDWARFDebugMap::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList &support_files) { SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc); Index: source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h =================================================================== --- source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h +++ source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h @@ -69,6 +69,9 @@ ParseCompileUnitLineTable(const lldb_private::SymbolContext& sc) override; bool + ParseCompileUnitDebugMacros(const lldb_private::SymbolContext& sc) override; + + bool ParseCompileUnitSupportFiles(const lldb_private::SymbolContext& sc, lldb_private::FileSpecList &support_files) override; Index: source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp =================================================================== --- source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp +++ source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp @@ -253,6 +253,12 @@ } bool +SymbolFileSymtab::ParseCompileUnitDebugMacros (const SymbolContext &sc) +{ + return false; +} + +bool SymbolFileSymtab::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList &support_files) { return false; Index: source/Symbol/CMakeLists.txt =================================================================== --- source/Symbol/CMakeLists.txt +++ source/Symbol/CMakeLists.txt @@ -10,6 +10,7 @@ CompilerType.cpp CompileUnit.cpp CompactUnwindInfo.cpp + DebugMacros.cpp Declaration.cpp DWARFCallFrameInfo.cpp Function.cpp Index: source/Symbol/CompileUnit.cpp =================================================================== --- source/Symbol/CompileUnit.cpp +++ source/Symbol/CompileUnit.cpp @@ -268,6 +268,37 @@ m_line_table_ap.reset(line_table); } +DebugMacros* +CompileUnit::GetDebugMacros() +{ + if (m_debug_macros_sp.get() == nullptr) + { + if (m_flags.IsClear(flagsParsedDebugMacros)) + { + m_flags.Set(flagsParsedDebugMacros); + SymbolVendor* symbol_vendor = GetModule()->GetSymbolVendor(); + if (symbol_vendor) + { + SymbolContext sc; + CalculateSymbolContext(&sc); + symbol_vendor->ParseCompileUnitDebugMacros(sc); + } + } + } + + return m_debug_macros_sp.get(); +} + +void +CompileUnit::SetDebugMacros(const DebugMacrosSP &debug_macros_sp) +{ + if (debug_macros_sp.get() == nullptr) + m_flags.Clear(flagsParsedDebugMacros); + else + m_flags.Set(flagsParsedDebugMacros); + m_debug_macros_sp = debug_macros_sp; +} + VariableListSP CompileUnit::GetVariableList(bool can_create) { Index: source/Symbol/DebugMacros.cpp =================================================================== --- /dev/null +++ source/Symbol/DebugMacros.cpp @@ -0,0 +1,65 @@ +//===-- DebugMacros.cpp -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/DebugMacros.h" + +#include "lldb/Symbol/CompileUnit.h" + +using namespace lldb_private; + +DebugMacroEntry::DebugMacroEntry(EntryType type, + uint32_t line, + uint32_t debug_line_file_idx, + const char *str) + : m_type(type), + m_line(line), + m_debug_line_file_idx(debug_line_file_idx), + m_str(str) +{ } + +DebugMacroEntry::DebugMacroEntry(EntryType type, + const DebugMacrosSP &debug_macros_sp) + : m_type(type), m_line(0), m_debug_line_file_idx(0), m_debug_macros_sp(debug_macros_sp) +{ } + +const FileSpec& +DebugMacroEntry::GetFileSpec(CompileUnit *comp_unit) const +{ + return comp_unit->GetSupportFiles().GetFileSpecAtIndex(m_debug_line_file_idx); +} + +DebugMacroEntry +DebugMacroEntry::CreateDefineEntry(uint32_t line, const char *str) +{ + return DebugMacroEntry(DebugMacroEntry::DEFINE, line, 0, str); +} + +DebugMacroEntry +DebugMacroEntry::CreateUndefEntry(uint32_t line, const char *str) +{ + return DebugMacroEntry(DebugMacroEntry::UNDEF, line, 0, str); +} + +DebugMacroEntry +DebugMacroEntry::CreateStartFileEntry(uint32_t line, uint32_t debug_line_file_idx) +{ + return DebugMacroEntry(DebugMacroEntry::START_FILE, line, debug_line_file_idx, nullptr); +} + +DebugMacroEntry +DebugMacroEntry::CreateEndFileEntry() +{ + return DebugMacroEntry(DebugMacroEntry::END_FILE, 0, 0, nullptr); +} + +DebugMacroEntry +DebugMacroEntry::CreateIndirectEntry(const DebugMacrosSP &debug_macros_sp) +{ + return DebugMacroEntry(DebugMacroEntry::INDIRECT, debug_macros_sp); +} Index: source/Symbol/ObjectFile.cpp =================================================================== --- source/Symbol/ObjectFile.cpp +++ source/Symbol/ObjectFile.cpp @@ -362,6 +362,7 @@ case eSectionTypeDWARFDebugLine: case eSectionTypeDWARFDebugLoc: case eSectionTypeDWARFDebugMacInfo: + case eSectionTypeDWARFDebugMacro: case eSectionTypeDWARFDebugPubNames: case eSectionTypeDWARFDebugPubTypes: case eSectionTypeDWARFDebugRanges: Index: source/Symbol/SymbolVendor.cpp =================================================================== --- source/Symbol/SymbolVendor.cpp +++ source/Symbol/SymbolVendor.cpp @@ -186,6 +186,18 @@ } bool +SymbolVendor::ParseCompileUnitDebugMacros (const SymbolContext &sc) +{ + ModuleSP module_sp(GetModule()); + if (module_sp) + { + lldb_private::Mutex::Locker locker(module_sp->GetMutex()); + if (m_sym_file_ap.get()) + return m_sym_file_ap->ParseCompileUnitDebugMacros(sc); + } + return false; +} +bool SymbolVendor::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList& support_files) { ModuleSP module_sp(GetModule()); Index: source/Utility/ConvertEnum.cpp =================================================================== --- source/Utility/ConvertEnum.cpp +++ source/Utility/ConvertEnum.cpp @@ -77,6 +77,8 @@ return "dwarf-loc"; case eSectionTypeDWARFDebugMacInfo: return "dwarf-macinfo"; + case eSectionTypeDWARFDebugMacro: + return "dwarf-macro"; case eSectionTypeDWARFDebugPubNames: return "dwarf-pubnames"; case eSectionTypeDWARFDebugPubTypes: