From 5635f77a99ff796af8d4ff595e8ad1bb2ae2bcfb Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Thu, 21 Mar 2013 03:36:01 +0000 Subject: [PATCH] Add a new method GetFunctionAddressAndSizeVector to DWARFCallFrameInfo. This returns a vector of entries for all of the functions in the module that have an eh_frame FDE. Update ObjectFileMachO to use the eh_frame FDE function addresses if the LC_FUNCTION_STARTS section is missing, to fill in the start addresses of any symbols that have been stripped from the binary. Generally speaking, lldb works best if it knows the actual start address of every function in a module - it's especially important for unwinding, where lldb inspects the instructions in the prologue of the function. In a stripped binary, it is deprived of this information and it reduces the quality of our unwinds and saved register retrieval. Other ObjectFile users may want to use the function addresses from DWARFCallFrameInfo to fill in any stripped symbols like ObjectFileMachO does already. llvm-svn: 177624 --- lldb/include/lldb/Symbol/DWARFCallFrameInfo.h | 25 ++++++++++++-- .../ObjectFile/Mach-O/ObjectFileMachO.cpp | 33 +++++++++++++++++++ lldb/source/Symbol/DWARFCallFrameInfo.cpp | 16 +++++++++ 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h b/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h index bd0b9941d192..d5d5e071169b 100644 --- a/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h +++ b/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h @@ -54,6 +54,25 @@ public: bool GetUnwindPlan (Address addr, UnwindPlan& unwind_plan); + typedef RangeVector FunctionAddressAndSizeVector; + + //------------------------------------------------------------------ + // Build a vector of file address and size for all functions in this Module + // based on the eh_frame FDE entries. + // + // The eh_frame information can be a useful source of file address and size of + // the functions in a Module. Often a binary's non-exported symbols are stripped + // before shipping so lldb won't know the start addr / size of many functions + // in the Module. But the eh_frame can help to give the addresses of these + // stripped symbols, at least. + // + // @param[out] function_info + // A vector provided by the caller is filled out. May be empty if no FDEs/no eh_frame + // is present in this Module. + + void + GetFunctionAddressAndSizeVector (FunctionAddressAndSizeVector &function_info); + private: enum { @@ -81,13 +100,13 @@ private: typedef STD_SHARED_PTR(CIE) CIESP; - // Start address, size, offset of FDE location + typedef std::map cie_map_t; + + // Start address (file address), size, offset of FDE location // used for finding an FDE for a given File address; the start address field is // an offset into an individual Module. typedef RangeDataVector FDEEntryMap; - typedef std::map cie_map_t; - bool IsEHFrame() const; diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index e2b75ad8e16f..6f3093236897 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -28,6 +28,7 @@ #include "lldb/Host/Host.h" #include "lldb/Host/FileSpec.h" #include "lldb/Symbol/ClangNamespaceDecl.h" +#include "lldb/Symbol/DWARFCallFrameInfo.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" @@ -1449,6 +1450,17 @@ ObjectFileMachO::ParseSymtab (bool minimize) eh_frame_section_sp = section_list->FindSectionByName (g_section_name_eh_frame); const bool is_arm = (m_header.cputype == llvm::MachO::CPUTypeARM); + + // lldb works best if it knows the start addresss of all functions in a module. + // Linker symbols or debug info are normally the best source of information for start addr / size but + // they may be stripped in a released binary. + // Two additional sources of information exist in Mach-O binaries: + // LC_FUNCTION_STARTS - a list of ULEB128 encoded offsets of each function's start address in the + // binary, relative to the text section. + // eh_frame - the eh_frame FDEs have the start addr & size of each function + // LC_FUNCTION_STARTS is the fastest source to read in, and is present on all modern binaries. + // Binaries built to run on older releases may need to use eh_frame information. + if (text_section_sp && function_starts_data.GetByteSize()) { FunctionStarts::Entry function_start_entry; @@ -1462,6 +1474,27 @@ ObjectFileMachO::ParseSymtab (bool minimize) function_start_entry.addr += delta; function_starts.Append(function_start_entry); } + } + else + { + if (text_section_sp.get() && eh_frame_section_sp.get()) + { + DWARFCallFrameInfo eh_frame(*this, eh_frame_section_sp, eRegisterKindGCC, true); + DWARFCallFrameInfo::FunctionAddressAndSizeVector functions; + eh_frame.GetFunctionAddressAndSizeVector (functions); + addr_t text_base_addr = text_section_sp->GetFileAddress(); + size_t count = functions.GetSize(); + for (size_t i = 0; i < count; ++i) + { + const DWARFCallFrameInfo::FunctionAddressAndSizeVector::Entry *func = functions.GetEntryAtIndex (i); + if (func) + { + FunctionStarts::Entry function_start_entry; + function_start_entry.addr = func->base - text_base_addr; + function_starts.Append(function_start_entry); + } + } + } } const size_t function_starts_count = function_starts.GetSize(); diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp index 3bc0e7e07fdf..c8bc08bbd991 100644 --- a/lldb/source/Symbol/DWARFCallFrameInfo.cpp +++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp @@ -104,6 +104,22 @@ DWARFCallFrameInfo::GetFDEEntryByFileAddress (addr_t file_addr, FDEEntryMap::Ent return true; } +void +DWARFCallFrameInfo::GetFunctionAddressAndSizeVector (FunctionAddressAndSizeVector &function_info) +{ + GetFDEIndex(); + const size_t count = m_fde_index.GetSize(); + for (size_t i = 0; i < count; ++i) + { + const FDEEntryMap::Entry *func_offset_data_entry = m_fde_index.GetEntryAtIndex (i); + if (func_offset_data_entry) + { + FunctionAddressAndSizeVector::Entry function_offset_entry (func_offset_data_entry->base, func_offset_data_entry->size); + function_info.Append (function_offset_entry); + } + } +} + const DWARFCallFrameInfo::CIE* DWARFCallFrameInfo::GetCIE(dw_offset_t cie_offset) {