[Lldb-commits] [lldb] r204749 - Improve Elf object file UUID calculation performance.
Todd Fiala
tfiala at google.com
Tue Mar 25 12:29:09 PDT 2014
Author: tfiala
Date: Tue Mar 25 14:29:09 2014
New Revision: 204749
URL: http://llvm.org/viewvc/llvm-project?rev=204749&view=rev
Log:
Improve Elf object file UUID calculation performance.
This change makes significant improvements in the performance of
calculating a UUID within ObjectFileELF, and handles both running
processes and core files correctly. This does lazy evaluation of
UUID generation and caches the result when calculated.
Change by Piotr Rak.
Modified:
lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
Modified: lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp?rev=204749&r1=204748&r2=204749&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp (original)
+++ lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp Tue Mar 25 14:29:09 2014
@@ -22,6 +22,7 @@
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
#include "lldb/Symbol/DWARFCallFrameInfo.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/SectionLoadList.h"
@@ -231,6 +232,10 @@ ELFNote::Parse(const DataExtractor &data
return true;
}
+// Arbitrary constant used as UUID prefix for core files.
+const uint32_t
+ObjectFileELF::g_core_uuid_magic(0xE210C);
+
//------------------------------------------------------------------
// Static methods.
//------------------------------------------------------------------
@@ -348,7 +353,7 @@ ObjectFileELF::MagicBytesMatch (DataBuff
* code or tables extracted from it, as desired without restriction.
*/
static uint32_t
-calc_gnu_debuglink_crc32(const void *buf, size_t size)
+calc_crc32(uint32_t crc, const void *buf, size_t size)
{
static const uint32_t g_crc32_tab[] =
{
@@ -397,14 +402,51 @@ calc_gnu_debuglink_crc32(const void *buf
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
const uint8_t *p = (const uint8_t *)buf;
- uint32_t crc;
- crc = ~0U;
+ crc = crc ^ ~0U;
while (size--)
crc = g_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
return crc ^ ~0U;
}
+static uint32_t
+calc_gnu_debuglink_crc32(const void *buf, size_t size)
+{
+ return calc_crc32(0U, buf, size);
+}
+
+uint32_t
+ObjectFileELF::CalculateELFNotesSegmentsCRC32 (const ProgramHeaderColl& program_headers,
+ DataExtractor& object_data)
+{
+ typedef ProgramHeaderCollConstIter Iter;
+
+ uint32_t core_notes_crc = 0;
+
+ for (Iter I = program_headers.begin(); I != program_headers.end(); ++I)
+ {
+ if (I->p_type == llvm::ELF::PT_NOTE)
+ {
+ const elf_off ph_offset = I->p_offset;
+ const size_t ph_size = I->p_filesz;
+
+ DataExtractor segment_data;
+ if (segment_data.SetData(object_data, ph_offset, ph_size) != ph_size)
+ {
+ // The ELF program header contained incorrect data,
+ // prabably corefile is incomplete or corrupted.
+ break;
+ }
+
+ core_notes_crc = calc_crc32(core_notes_crc,
+ segment_data.GetDataStart(),
+ segment_data.GetByteSize());
+ }
+ }
+
+ return core_notes_crc;
+}
+
size_t
ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file,
lldb::DataBufferSP& data_sp,
@@ -454,14 +496,54 @@ ObjectFileELF::GetModuleSpecifications (
lldb_private::UUID &uuid = spec.GetUUID();
GetSectionHeaderInfo(section_headers, data, header, uuid, gnu_debuglink_file, gnu_debuglink_crc);
+
if (!uuid.IsValid())
{
+ uint32_t core_notes_crc = 0;
+
if (!gnu_debuglink_crc)
{
- // Need to map entire file into memory to calculate the crc.
- data_sp = file.MemoryMapFileContents (file_offset, SIZE_MAX);
- data.SetData(data_sp);
- gnu_debuglink_crc = calc_gnu_debuglink_crc32 (data.GetDataStart(), data.GetByteSize());
+ lldb_private::Timer scoped_timer (__PRETTY_FUNCTION__,
+ "Calculating module crc32 %s with size %" PRIu64 " KiB",
+ file.GetLastPathComponent().AsCString(),
+ (file.GetByteSize()-file_offset)/1024);
+
+ // For core files - which usually don't happen to have a gnu_debuglink,
+ // and are pretty bulky - calulating whole contents crc32 would be too much of luxury.
+ // Thus we will need to fallback to something simpler.
+ if (header.e_type == llvm::ELF::ET_CORE)
+ {
+ size_t program_headers_end = header.e_phoff + header.e_phnum * header.e_phentsize;
+ if (program_headers_end > data_sp->GetByteSize())
+ {
+ data_sp = file.MemoryMapFileContents(file_offset, program_headers_end);
+ data.SetData(data_sp);
+ }
+ ProgramHeaderColl program_headers;
+ GetProgramHeaderInfo(program_headers, data, header);
+
+ size_t segment_data_end = 0;
+ for (ProgramHeaderCollConstIter I = program_headers.begin();
+ I != program_headers.end(); ++I)
+ {
+ segment_data_end = std::max (I->p_offset + I->p_filesz, segment_data_end);
+ }
+
+ if (segment_data_end > data_sp->GetByteSize())
+ {
+ data_sp = file.MemoryMapFileContents(file_offset, segment_data_end);
+ data.SetData(data_sp);
+ }
+
+ core_notes_crc = CalculateELFNotesSegmentsCRC32 (program_headers, data);
+ }
+ else
+ {
+ // Need to map entire file into memory to calculate the crc.
+ data_sp = file.MemoryMapFileContents (file_offset, SIZE_MAX);
+ data.SetData(data_sp);
+ gnu_debuglink_crc = calc_gnu_debuglink_crc32 (data.GetDataStart(), data.GetByteSize());
+ }
}
if (gnu_debuglink_crc)
{
@@ -469,6 +551,13 @@ ObjectFileELF::GetModuleSpecifications (
uint32_t uuidt[4] = { gnu_debuglink_crc, 0, 0, 0 };
uuid.SetBytes (uuidt, sizeof(uuidt));
}
+ else if (core_notes_crc)
+ {
+ // Use 8 bytes - first 4 bytes for *magic* prefix, mainly to make it look different form
+ // .gnu_debuglink crc followed by 4 bytes of note segments crc.
+ uint32_t uuidt[4] = { g_core_uuid_magic, core_notes_crc, 0, 0 };
+ uuid.SetBytes (uuidt, sizeof(uuidt));
+ }
}
specs.Append(spec);
@@ -620,7 +709,7 @@ bool
ObjectFileELF::GetUUID(lldb_private::UUID* uuid)
{
// Need to parse the section list to get the UUIDs, so make sure that's been done.
- if (!ParseSectionHeaders())
+ if (!ParseSectionHeaders() && GetType() != ObjectFile::eTypeCoreFile)
return false;
if (m_uuid.IsValid())
@@ -629,7 +718,25 @@ ObjectFileELF::GetUUID(lldb_private::UUI
*uuid = m_uuid;
return true;
}
- else
+ else if (GetType() == ObjectFile::eTypeCoreFile)
+ {
+ uint32_t core_notes_crc = 0;
+
+ if (!ParseProgramHeaders())
+ return false;
+
+ core_notes_crc = CalculateELFNotesSegmentsCRC32(m_program_headers, m_data);
+
+ if (core_notes_crc)
+ {
+ // Use 8 bytes - first 4 bytes for *magic* prefix, mainly to make it
+ // look different form .gnu_debuglink crc - followed by 4 bytes of note
+ // segments crc.
+ uint32_t uuidt[4] = { g_core_uuid_magic, core_notes_crc, 0, 0 };
+ m_uuid.SetBytes (uuidt, sizeof(uuidt));
+ }
+ }
+ else
{
if (!m_gnu_debuglink_crc)
m_gnu_debuglink_crc = calc_gnu_debuglink_crc32 (m_data.GetDataStart(), m_data.GetByteSize());
@@ -637,11 +744,16 @@ ObjectFileELF::GetUUID(lldb_private::UUI
{
// Use 4 bytes of crc from the .gnu_debuglink section.
uint32_t uuidt[4] = { m_gnu_debuglink_crc, 0, 0, 0 };
- uuid->SetBytes (uuidt, sizeof(uuidt));
- return true;
+ m_uuid.SetBytes (uuidt, sizeof(uuidt));
}
}
+ if (m_uuid.IsValid())
+ {
+ *uuid = m_uuid;
+ return true;
+ }
+
return false;
}
@@ -801,41 +913,53 @@ ObjectFileELF::ParseDependentModules()
}
//----------------------------------------------------------------------
-// ParseProgramHeaders
+// GetProgramHeaderInfo
//----------------------------------------------------------------------
size_t
-ObjectFileELF::ParseProgramHeaders()
+ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
+ DataExtractor &object_data,
+ const ELFHeader &header)
{
// We have already parsed the program headers
- if (!m_program_headers.empty())
- return m_program_headers.size();
+ if (!program_headers.empty())
+ return program_headers.size();
// If there are no program headers to read we are done.
- if (m_header.e_phnum == 0)
+ if (header.e_phnum == 0)
return 0;
- m_program_headers.resize(m_header.e_phnum);
- if (m_program_headers.size() != m_header.e_phnum)
+ program_headers.resize(header.e_phnum);
+ if (program_headers.size() != header.e_phnum)
return 0;
- const size_t ph_size = m_header.e_phnum * m_header.e_phentsize;
- const elf_off ph_offset = m_header.e_phoff;
+ const size_t ph_size = header.e_phnum * header.e_phentsize;
+ const elf_off ph_offset = header.e_phoff;
DataExtractor data;
- if (GetData (ph_offset, ph_size, data) != ph_size)
+ if (data.SetData(object_data, ph_offset, ph_size) != ph_size)
return 0;
uint32_t idx;
lldb::offset_t offset;
- for (idx = 0, offset = 0; idx < m_header.e_phnum; ++idx)
+ for (idx = 0, offset = 0; idx < header.e_phnum; ++idx)
{
- if (m_program_headers[idx].Parse(data, &offset) == false)
+ if (program_headers[idx].Parse(data, &offset) == false)
break;
}
- if (idx < m_program_headers.size())
- m_program_headers.resize(idx);
+ if (idx < program_headers.size())
+ program_headers.resize(idx);
+
+ return program_headers.size();
+
+}
- return m_program_headers.size();
+//----------------------------------------------------------------------
+// ParseProgramHeaders
+//----------------------------------------------------------------------
+size_t
+ObjectFileELF::ParseProgramHeaders()
+{
+ return GetProgramHeaderInfo(m_program_headers, m_data, m_header);
}
static bool
Modified: lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.h?rev=204749&r1=204748&r2=204749&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.h (original)
+++ lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.h Tue Mar 25 14:29:09 2014
@@ -214,6 +214,7 @@ private:
/// Version of this reader common to all plugins based on this class.
static const uint32_t m_plugin_version = 1;
+ static const uint32_t g_core_uuid_magic;
/// ELF file header.
elf::ELFHeader m_header;
@@ -249,6 +250,17 @@ private:
size_t
SectionIndex(const SectionHeaderCollConstIter &I) const;
+ // Parses the ELF program headers.
+ static size_t
+ GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
+ lldb_private::DataExtractor &data,
+ const elf::ELFHeader &header);
+
+ // Finds PT_NOTE segments and calculates their crc sum.
+ static uint32_t
+ CalculateELFNotesSegmentsCRC32(const ProgramHeaderColl& program_headers,
+ lldb_private::DataExtractor &data);
+
/// Parses all section headers present in this object file and populates
/// m_program_headers. This method will compute the header list only once.
/// Returns the number of headers parsed.
More information about the lldb-commits
mailing list