I've attached a patch to add support for JITed ELF objects to the work you
did in your lldb repo. This was taken almost verbatim from the original
patch you posted so all credit goes to you. :) With this patch we now have
breakpoints and full stack traces into the code JITed by our KL compiler on
Linux, including line numbers and variable info.
Since it sounds like you're on OSX I'm guessing your upstream LLVM changes
included adding the calls to the GDBRegistrar in RuntimeDyldMachO.cpp? It
looks like they're only in there for ELF right now. Let me know if there's
anything else I might need for OSX and I'll investigate what's happening
with the missing line numbers there.
On Fri, Jan 3, 2014 at 11:35 PM, Keno Fischer
<[email protected]>wrote:
> Everything I've been doing with that was upstream llvm to get the
> relocations right rather than lldb.
> https://github.com/loladiro/lldb/commit/991583df4d052cb7dab692e657c4ced4d01ff384is
> up to date (the next commit on master has a few debugging things I was
> trying out, but that commit is functionally complete).
>
> Yes, I thought about that solution as well. Seems like the way to go.
>
>
> On Thu, Jan 2, 2014 at 11:56 AM, Andrew MacPherson
> <[email protected]>wrote:
>
>> Hi Keno,
>>
>> This all sounds great, can you check in the progress you've made so far
>> with seeing JITed functions in backtraces? I can try to figure out what's
>> happening with the missing line numbers.
>>
>> Regarding the breakpoints a quick look at Breakpoint.cpp seems to show
>> that this is intentional, there's an explicit check for !IsInternal()
>> inside Breakpoint::ModulesChanged() which I would guess is what applies
>> here. I think we would want these breakpoints to be internal though so that
>> users don't see them and if we make sure that the JITLoader gets an event
>> whenever a new shared library is loaded then we can also add more explicit
>> logging around when the JIT register code function has actually been found
>> and resolved.
>>
>> Thanks!
>> Andrew
>>
>>
>> On Wed, Jan 1, 2014 at 3:39 PM, Keno Fischer <
>> [email protected]> wrote:
>>
>>> I'm currently in holiday mode as well. A couple of things that I didn't
>>> get to that need to be resolved (these are pretty general questions on lldb
>>> itself, so I'd appreciate input from anybody on this list):
>>>
>>> - I'm using a regular rather than an internal breakpoint, because the
>>> latter does not get updated when shared libraries are loaded (Is this
>>> intended? Is there a recommended workaround?)
>>>
>>> - I'm not seeing the function in backtraces even though I can set
>>> breakpoints. Is there anything else that needs to be done/ Do the
>>> backtraces use different information that is perhaps not relocated
>>> properly? If so, how can I check?
>>>
>>> - I'm also not seeing line numbers, etc. Probably related to the second
>>> point.
>>>
>>> - Keno
>>>
>>>
>>> On Tue, Dec 31, 2013 at 10:16 AM, Andrew MacPherson <
>>> [email protected]> wrote:
>>>
>>>> This looks great. I'm still in holiday mode but will tackle any
>>>> outstanding ELF-related work when I'm back on Thursday, feel free to ping
>>>> me or the list again if you get any further. Thanks for pushing on this!
>>>>
>>>> Cheers,
>>>> Andrew
>>>>
>>>>
>>>> On Sun, Dec 29, 2013 at 6:29 PM, Keno Fischer <
>>>> [email protected]> wrote:
>>>>
>>>>> I've gotten pretty far,
>>>>> Code is here: https://github.com/loladiro/lldb
>>>>> It's interacting correctly with the debug interface and I've got it
>>>>> loading the object file from memory correctly for
>>>>> MachO/DWARF (working on ELF right now). Currently not much use as it
>>>>> doesn't seem to be looking at the
>>>>> debug information that were just added (I can see them via `image dump
>>>>> sections` and I can set breakpoints
>>>>> correctly though, so that's a plus). For DWARF, there's a few changes
>>>>> for upstream LLVM needed. I'll put them
>>>>> up if anybody's interested, otherwise, I'll just keep chugging along
>>>>> and wait until I have more complete patch.
>>>>>
>>>>> - Keno
>>>>>
>>>>>
>>>>> On Sat, Dec 28, 2013 at 1:07 PM, Andrew MacPherson <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> Hi Keno,
>>>>>>
>>>>>> I noticed the same thing and agree that the JIT loader doesn't
>>>>>> perfectly fit as a DynamicLoader, the suggestion from a couple of years
>>>>>> back on the list was to make the Process -> DynamicLoader relationship
>>>>>> 1:n
>>>>>> but I prefer your suggestion of adding a new plugin type (JITLoader).
>>>>>> Right
>>>>>> now there would only be one JITLoader type for the GDB interface.
>>>>>>
>>>>>> The patch could probably be fixed up as-is as a first step (leaving
>>>>>> the JIT loading bits as a growth on the DynamicLoaderPOSIXDYLD) and we
>>>>>> could move it out into its own plugin type once that's working. I should
>>>>>> have time this coming week to get this working but if you'll also have
>>>>>> time
>>>>>> then I'm happy to leave it with you.
>>>>>>
>>>>>> Cheers,
>>>>>> Andrew
>>>>>>
>>>>>>
>>>>>> On Sat, Dec 28, 2013 at 9:37 AM, Keno Fischer <
>>>>>> [email protected]> wrote:
>>>>>>
>>>>>>> I've started looking into this and it's actually not that difficult
>>>>>>> to do (the JIT part at least). I think the most difficult thing is
>>>>>>> figuring out where to put the functionality. The way I see it, the
>>>>>>> JIT interface is almost a DynamicLoader, with the difference
>>>>>>> that asking it about things like whether or not loading a dynamic
>>>>>>> library is safe doesn't make much sense. Another problem
>>>>>>> is that currently there's a 1:1 relationship between Processes and
>>>>>>> DynamicLoaders. Perhaps a new class of Plugins
>>>>>>> (JITLoader?) could be added with a 1:n relationship to processes.
>>>>>>> Some of the interface (I'm thinking
>>>>>>> DidLaunch,DidAttach,Get/SetStopWhenImagesChange) could be pulled
>>>>>>> out into an abstract base class. Does that make
>>>>>>> sense. I'd be happy to implement this once we decide on the design.
>>>>>>>
>>>>>>> Keno
>>>>>>>
>>>>>>>
>>>>>>> On Wed, Dec 25, 2013 at 10:30 AM, Andrew MacPherson <
>>>>>>> [email protected]> wrote:
>>>>>>>
>>>>>>>> Looks great, thanks Keno. I'll look into this next week and keep
>>>>>>>> you posted.
>>>>>>>>
>>>>>>>> Cheers,
>>>>>>>> Andrew
>>>>>>>>
>>>>>>>>
>>>>>>>> On Tue, Dec 24, 2013 at 1:19 PM, Keno Fischer <
>>>>>>>> [email protected]> wrote:
>>>>>>>>
>>>>>>>>> I have this (as I said, I haven't tried it). It seems to be a
>>>>>>>>> different patch.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Tue, Dec 24, 2013 at 11:17 AM, Andrew MacPherson <
>>>>>>>>> [email protected]> wrote:
>>>>>>>>>
>>>>>>>>>> Hi Keno,
>>>>>>>>>>
>>>>>>>>>> I found this old patch that hooks into the GDB JIT registration
>>>>>>>>>> mechanism which we were planning to use as a starting point:
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> http://lists.cs.uiuc.edu/pipermail/lldb-dev/2010-December/000314.html
>>>>>>>>>>
>>>>>>>>>> If you have anything else we'd love to take a look!
>>>>>>>>>>
>>>>>>>>>> Cheers,
>>>>>>>>>> Andrew
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On Tue, Dec 24, 2013 at 8:34 AM, Keno Fischer <
>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>
>>>>>>>>>>> Hi Andrew,
>>>>>>>>>>>
>>>>>>>>>>> I'm also one of the Julia core developers and the guy currently
>>>>>>>>>>> working on
>>>>>>>>>>> debugging support. I was given a patch to add MCJIT debugging
>>>>>>>>>>> support
>>>>>>>>>>> to LLDB with the disclaimer that it probably doesn't work. I
>>>>>>>>>>> haven't tried it
>>>>>>>>>>> yet, so I can't say how close it is, but it's probably at least
>>>>>>>>>>> a starting point.
>>>>>>>>>>>
>>>>>>>>>>> I'd be happy to coordinate any efforts.
>>>>>>>>>>>
>>>>>>>>>>> - Keno
>>>>>>>>>>>
>>>>>>>>>>> _______________________________________________
>>>>>>>>>>> lldb-dev mailing list
>>>>>>>>>>> [email protected]
>>>>>>>>>>> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 7bdacfe..8a45339 100644
--- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -71,6 +71,18 @@ public:
static unsigned
RelocSymbol64(const ELFRelocation &rel);
+ static unsigned
+ RelocOffset32(const ELFRelocation &rel);
+
+ static unsigned
+ RelocOffset64(const ELFRelocation &rel);
+
+ static unsigned
+ RelocAddend32(const ELFRelocation &rel);
+
+ static unsigned
+ RelocAddend64(const ELFRelocation &rel);
+
private:
typedef llvm::PointerUnion<ELFRel*, ELFRela*> RelocUnion;
@@ -79,9 +91,9 @@ private:
ELFRelocation::ELFRelocation(unsigned type)
{
- if (type == DT_REL)
+ if (type == DT_REL || type == SHT_REL)
reloc = new ELFRel();
- else if (type == DT_RELA)
+ else if (type == DT_RELA || type == SHT_RELA)
reloc = new ELFRela();
else {
assert(false && "unexpected relocation type");
@@ -142,6 +154,42 @@ ELFRelocation::RelocSymbol64(const ELFRelocation &rel)
return ELFRela::RelocSymbol64(*rel.reloc.get<ELFRela*>());
}
+unsigned
+ELFRelocation::RelocOffset32(const ELFRelocation &rel)
+{
+ if (rel.reloc.is<ELFRel*>())
+ return rel.reloc.get<ELFRel*>()->r_offset;
+ else
+ return rel.reloc.get<ELFRela*>()->r_offset;
+}
+
+unsigned
+ELFRelocation::RelocOffset64(const ELFRelocation &rel)
+{
+ if (rel.reloc.is<ELFRel*>())
+ return rel.reloc.get<ELFRel*>()->r_offset;
+ else
+ return rel.reloc.get<ELFRela*>()->r_offset;
+}
+
+unsigned
+ELFRelocation::RelocAddend32(const ELFRelocation &rel)
+{
+ if (rel.reloc.is<ELFRel*>())
+ return 0;
+ else
+ return rel.reloc.get<ELFRela*>()->r_addend;
+}
+
+unsigned
+ELFRelocation::RelocAddend64(const ELFRelocation &rel)
+{
+ if (rel.reloc.is<ELFRel*>())
+ return 0;
+ else
+ return rel.reloc.get<ELFRela*>()->r_addend;
+}
+
} // end anonymous namespace
bool
@@ -260,6 +308,22 @@ ObjectFileELF::CreateMemoryInstance (const lldb::ModuleSP &module_sp,
const lldb::ProcessSP &process_sp,
lldb::addr_t header_addr)
{
+ if (data_sp && data_sp->GetByteSize() > (llvm::ELF::EI_NIDENT))
+ {
+ const uint8_t *magic = data_sp->GetBytes();
+ if (ELFHeader::MagicBytesMatch(magic))
+ {
+ unsigned address_size = ELFHeader::AddressSizeInBytes(magic);
+ if (address_size == 4 || address_size == 8)
+ {
+ std::auto_ptr<ObjectFileELF> objfile_ap(new ObjectFileELF(module_sp, data_sp, process_sp, header_addr));
+ ArchSpec spec;
+ if (objfile_ap->GetArchitecture(spec) &&
+ objfile_ap->SetModulesArchitecture(spec))
+ return objfile_ap.release();
+ }
+ }
+ }
return NULL;
}
@@ -452,6 +516,20 @@ ObjectFileELF::ObjectFileELF (const lldb::ModuleSP &module_sp,
m_gnu_debuglink_file.clear();
}
+ObjectFileELF::ObjectFileELF (const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ const lldb::ProcessSP &process_sp,
+ addr_t header_addr) :
+ ObjectFile(module_sp, process_sp, header_addr, data_sp),
+ m_header(),
+ m_program_headers(),
+ m_section_headers(),
+ m_filespec_ap()
+{
+ ::memset(&m_header, 0, sizeof(m_header));
+ const_cast<lldb::addr_t &>(m_memory_addr) = LLDB_INVALID_ADDRESS;
+}
+
ObjectFileELF::~ObjectFileELF()
{
}
@@ -1075,8 +1153,9 @@ ObjectFileELF::ParseSymbols (Symtab *symtab,
const char *symbol_name = strtab_data.PeekCStr(symbol.st_name);
- // No need to add symbols that have no names
- if (symbol_name == NULL || symbol_name[0] == '\0')
+ // No need to add non-section symbols that have no names
+ if (symbol.getType() != STT_SECTION &&
+ (symbol_name == NULL || symbol_name[0] == '\0'))
continue;
//symbol.Dump (&strm, i, &strtab_data, section_list);
@@ -1186,7 +1265,7 @@ ObjectFileELF::ParseSymbols (Symtab *symtab,
}
uint64_t symbol_value = symbol.st_value;
- if (symbol_section_sp)
+ if (symbol_section_sp && CalculateType() != ObjectFile::Type::eTypeObjectFile)
symbol_value -= symbol_section_sp->GetFileAddress();
bool is_global = symbol.getBinding() == STB_GLOBAL;
uint32_t flags = symbol.st_other << 8 | symbol.st_info;
@@ -1484,6 +1563,136 @@ ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table,
strtab_data);
}
+unsigned
+ObjectFileELF::RelocateSection(Symtab* symtab, const ELFHeader *hdr, const ELFSectionHeader *rel_hdr,
+ const ELFSectionHeader *symtab_hdr, const ELFSectionHeader *debug_hdr,
+ DataExtractor &rel_data, DataExtractor &symtab_data,
+ DataExtractor &debug_data, Section* rel_section)
+{
+ ELFRelocation rel(rel_hdr->sh_type);
+ lldb::addr_t offset = 0;
+ const unsigned num_relocations = rel_hdr->sh_size / rel_hdr->sh_entsize;
+ typedef unsigned (*reloc_info_fn)(const ELFRelocation &rel);
+ reloc_info_fn reloc_type;
+ reloc_info_fn reloc_symbol;
+
+ if (hdr->Is32Bit())
+ {
+ reloc_type = ELFRelocation::RelocType32;
+ reloc_symbol = ELFRelocation::RelocSymbol32;
+ }
+ else
+ {
+ reloc_type = ELFRelocation::RelocType64;
+ reloc_symbol = ELFRelocation::RelocSymbol64;
+ }
+
+ for (unsigned i = 0; i < num_relocations; ++i)
+ {
+ if (rel.Parse(rel_data, &offset) == false)
+ break;
+
+ Symbol* symbol = NULL;
+
+ if (hdr->Is32Bit())
+ {
+ switch (reloc_type(rel)) {
+ case R_386_32:
+ case R_386_PC32:
+ default:
+ assert(false && "unexpected relocation type");
+ }
+ } else {
+ switch (reloc_type(rel)) {
+ case R_X86_64_64:
+ {
+ symbol = symtab->FindSymbolByID(reloc_symbol(rel));
+ if (symbol)
+ {
+ addr_t value = symbol->GetAddress().GetFileAddress();
+ DataBufferSP& data_buffer_sp = debug_data.GetSharedDataBuffer();
+ uint64_t* dst = reinterpret_cast<uint64_t*>(data_buffer_sp->GetBytes() + rel_section->GetFileOffset() + ELFRelocation::RelocOffset64(rel));
+ *dst = value + ELFRelocation::RelocAddend64(rel);
+ }
+ break;
+ }
+ case R_X86_64_32:
+ case R_X86_64_32S:
+ {
+ symbol = symtab->FindSymbolByID(reloc_symbol(rel));
+ if (symbol)
+ {
+ addr_t value = symbol->GetAddress().GetFileAddress();
+ value += ELFRelocation::RelocAddend32(rel);
+ assert((reloc_type(rel) == R_X86_64_32 && (value <= UINT32_MAX)) ||
+ (reloc_type(rel) == R_X86_64_32S &&
+ ((int64_t)value <= INT32_MAX && (int64_t)value >= INT32_MIN)));
+ uint32_t truncated_addr = (value & 0xFFFFFFFF);
+ DataBufferSP& data_buffer_sp = debug_data.GetSharedDataBuffer();
+ uint32_t* dst = reinterpret_cast<uint32_t*>(data_buffer_sp->GetBytes() + rel_section->GetFileOffset() + ELFRelocation::RelocOffset32(rel));
+ *dst = truncated_addr;
+ }
+ break;
+ }
+ case R_X86_64_PC32:
+ default:
+ assert(false && "unexpected relocation type");
+ }
+ }
+ }
+
+ return 0;
+}
+
+unsigned
+ObjectFileELF::RelocateDebugSections(const ELFSectionHeader *rel_hdr, user_id_t rel_id)
+{
+ assert(rel_hdr->sh_type == SHT_RELA || rel_hdr->sh_type == SHT_REL);
+
+ // Parse in the section list if needed.
+ SectionList *section_list = GetSectionList();
+ if (!section_list)
+ return 0;
+
+ // Section ID's are ones based.
+ user_id_t symtab_id = rel_hdr->sh_link + 1;
+ user_id_t debug_id = rel_hdr->sh_info + 1;
+
+ const ELFSectionHeader *symtab_hdr = GetSectionHeaderByIndex(symtab_id);
+ if (!symtab_hdr)
+ return 0;
+
+ const ELFSectionHeader *debug_hdr = GetSectionHeaderByIndex(debug_id);
+ if (!debug_hdr)
+ return 0;
+
+ Section *rel = section_list->FindSectionByID(rel_id).get();
+ if (!rel)
+ return 0;
+
+ Section *symtab = section_list->FindSectionByID(symtab_id).get();
+ if (!symtab)
+ return 0;
+
+ Section *debug = section_list->FindSectionByID(debug_id).get();
+ if (!debug)
+ return 0;
+
+ DataExtractor rel_data;
+ DataExtractor symtab_data;
+ DataExtractor debug_data;
+
+ if (ReadSectionData(rel, rel_data) &&
+ ReadSectionData(symtab, symtab_data) &&
+ ReadSectionData(debug, debug_data))
+ {
+ RelocateSection(m_symtab_ap.get(), &m_header, rel_hdr, symtab_hdr, debug_hdr,
+ rel_data, symtab_data, debug_data, debug);
+ }
+
+ return 0;
+}
+
Symtab *
ObjectFileELF::GetSymtab()
{
@@ -1546,6 +1755,25 @@ ObjectFileELF::GetSymtab()
}
}
}
+
+ for (SectionHeaderCollIter I = m_section_headers.begin();
+ I != m_section_headers.end(); ++I)
+ {
+ if (I->sh_type == SHT_RELA || I->sh_type == SHT_REL)
+ {
+ if (CalculateType() == eTypeObjectFile)
+ {
+ const char *section_name = I->section_name.AsCString("");
+ if (strstr(section_name, ".rela.debug") ||
+ strstr(section_name, ".rel.debug"))
+ {
+ const ELFSectionHeader &reloc_header = *I;
+ user_id_t reloc_id = SectionIndex(I);
+ RelocateDebugSections(&reloc_header, reloc_id);
+ }
+ }
+ }
+ }
return m_symtab_ap.get();
}
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
index a2ab9b8..0be85c1 100644
--- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -186,6 +186,11 @@ private:
lldb::offset_t offset,
lldb::offset_t length);
+ ObjectFileELF (const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr);
+
typedef std::vector<elf::ELFProgramHeader> ProgramHeaderColl;
typedef ProgramHeaderColl::iterator ProgramHeaderCollIter;
typedef ProgramHeaderColl::const_iterator ProgramHeaderCollConstIter;
@@ -298,6 +303,32 @@ private:
const ELFSectionHeaderInfo *rela_hdr,
lldb::user_id_t section_id);
+ /// Relocates debug sections
+ unsigned
+ RelocateDebugSections(const elf::ELFSectionHeader *rel_hdr, lldb::user_id_t rel_id);
+
+ unsigned
+ RelocateSection(lldb_private::Symtab* symtab, const elf::ELFHeader *hdr, const elf::ELFSectionHeader *rel_hdr,
+ const elf::ELFSectionHeader *symtab_hdr, const elf::ELFSectionHeader *debug_hdr,
+ lldb_private::DataExtractor &rel_data, lldb_private::DataExtractor &symtab_data,
+ lldb_private::DataExtractor &debug_data, lldb_private::Section* rel_section);
+
+ /// Loads the section name string table into m_shstr_data. Returns the
+ /// number of bytes constituting the table.
+ size_t
+ GetSectionHeaderStringTable();
+
+ /// Utility method for looking up a section given its name. Returns the
+ /// index of the corresponding section or zero if no section with the given
+ /// name can be found (note that section indices are always 1 based, and so
+ /// section index 0 is never valid).
+ lldb::user_id_t
+ GetSectionIndexByName(const char *name);
+
+ // Returns the ID of the first section that has the given type.
+ lldb::user_id_t
+ GetSectionIndexByType(unsigned type);
+
/// Returns the section header with the given id or NULL.
const ELFSectionHeaderInfo *
GetSectionHeaderByIndex(lldb::user_id_t id);
_______________________________________________
lldb-dev mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev