Misinterpreting Symbols Issue since LLDB-310

Hi, everyone

The Target::SetExecutableModule invoke Target::ClearModules at the very beginning. Target::ClearModules clears the m_section_load_histroy which maintains the section list of the target. the following symbol parsing phase needs section list of the executable. Empty section list will leads to Misinterpreting various symbol data including Function Starts.

I’ve tried to fix the issue by avoiding clear the m_section_history in Target::SetExecutableModule. It’s work, but I not show weather it’s a proper way to fix the issue.

Hope someone can review the fix.

Best,
Lei Shi

Hi, everyone

The Target::SetExecutableModule invoke Target::ClearModules at the very beginning. Target::ClearModules clears the m_section_load_histroy which maintains the section list of the target. the following symbol parsing phase needs section list of the executable. Empty section list will leads to Misinterpreting various symbol data including Function Starts.

How are you setting up your symbols prior to setting the target executable? Or is the dynamic loader plug-in doing this? Either way the target's main executable should be set, then the sections should be setup.

How are you getting this to happen?

I've tried to fix the issue by avoiding clear the m_section_history in Target::SetExecutableModule. It's work, but I not show weather it's a proper way to fix the issue.

This isn't the right way to do things. Let me know how you are getting Target::SetExecutableModule() to be called and I might be able to tell you more.

shortly say, the section list of target was used when it isn’t available in ObjectFileMachO::ParseSymtab.

look these:

#0 ObjectFileMachO::ParseSymtab() at source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp:1744
#1 ObjectFileMachO::GetSymtab() at source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp:1039
#2 SymbolFileSymtab::CalculateAbilities() at source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp:96
#3 lldb_private::SymbolFile::GetAbilities() at include/lldb/Symbol/SymbolFile.h:96
#4 lldb_private::SymbolFile::FindPlugin(lldb_private::ObjectFile*) at source/Symbol/SymbolFile.cpp:55
#5 lldb_private::SymbolVendor::AddSymbolFileRepresentation(std::__1::shared_ptr<lldb_private::ObjectFile> const&) at source/Symbol/SymbolVendor.cpp:92
#6 SymbolVendorMacOSX::CreateInstance(…) at source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp:291
#7 lldb_private::SymbolVendor::FindPlugin(…) at source/Symbol/SymbolVendor.cpp:42
#8 lldb_private::Module::GetSymbolVendor(bool, lldb_private::Stream*) at source/Core/Module.cpp:958
#9 PlatformDarwin::LocateExecutableScriptingResources(…) at source/Plugins/Platform/MacOSX/PlatformDarwin.cpp:72
#10 lldb_private::Module::LoadScriptingResourceInTarget(…) at source/Core/Module.cpp:1441
#11 LoadScriptingResourceForModule(…) at source/Target/Target.cpp:1006
#12 lldb_private::Target::ModuleAdded(…) at source/Target/Target.cpp:1146
#13 non-virtual thunk to lldb_private::Target::ModuleAdded(…) at source/Target/Target.cpp:1148
#14 lldb_private::ModuleList::AppendImpl(…) at source/Core/ModuleList.cpp:87
#15 lldb_private::ModuleList::Append(…) at source/Core/ModuleList.cpp:94
#16 lldb_private::Target::SetExecutableModule(…) at source/Target/Target.cpp:1049
#17 DynamicLoaderMacOSXDYLD::UpdateImageInfosHeaderAndLoadCommands(…) at source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp:1349
#18 DynamicLoaderMacOSXDYLD::AddModulesUsingImageInfosAddress(…) at source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp:805

void Target::SetExecutableModule (ModuleSP& executable_sp, bool get_dependent_files)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TARGET));
ClearModules(false);

if (executable_sp.get())
{
Timer scoped_timer (
PRETTY_FUNCTION,
“Target::SetExecutableModule (executable = ‘%s’)”,
executable_sp->GetFileSpec().GetPath().c_str()
);

// The first image is our exectuable file
// If we haven’t set an architecture yet, reset our architecture based on what we found in the executable module.
m_images.Append(executable_sp);


}
}

size_t ObjectFileMachO::ParseSymtab ()
{

SectionSP linkedit_section_sp(section_list->FindSectionByName(GetSegmentNameLINKEDIT()));
// Reading mach file from memory in a process or core file…
if (linkedit_section_sp)
{
const addr_t linkedit_load_addr = linkedit_section_sp->GetLoadBaseAddress(&target);

PlatformSP platform_sp (target.GetPlatform());
if (platform_sp && platform_sp->IsHost() && use_lldb_cache)
{
data_was_read = true;
nlist_data.SetData((void *)symoff_addr, nlist_data_byte_size, eByteOrderLittle);
strtab_data.SetData((void *)strtab_addr, strtab_data_byte_size, eByteOrderLittle);
if (function_starts_load_command.cmd)
{
const addr_t func_start_addr = linkedit_load_addr + function_starts_load_command.dataoff - linkedit_file_offset;
function_starts_data.SetData ((void *)func_start_addr, function_starts_load_command.datasize, eByteOrderLittle);
}
}


}

void DynamicLoaderMacOSXDYLD::UpdateImageInfosHeaderAndLoadCommands(DYLDImageInfo::collection &image_infos, uint32_t infos_count, bool update_executable)
{
uint32_t exe_idx = UINT32_MAX;
// Read any UUID values that we can get

for (uint32_t i = 0; i < infos_count; i++)
{
if (!image_infos[i].UUIDValid())
{
DataExtractor data; // Load command data

if (!ReadMachHeader (image_infos[i].address, &image_infos[i].header, &data))
continue;

ParseLoadCommands (data, image_infos[i], NULL);

if (image_infos[i].header.filetype == llvm::MachO::MH_EXECUTE)
exe_idx = i;
}
}

Target &target = m_process->GetTarget();

if (exe_idx < image_infos.size())
{
const bool can_create = true;
ModuleSP exe_module_sp (FindTargetModuleForDYLDImageInfo (image_infos[exe_idx], can_create, NULL));

if (exe_module_sp)
{
UpdateImageLoadAddress (exe_module_sp.get(), image_infos[exe_idx]);

if (exe_module_sp.get() != target.GetExecutableModulePointer())
{
// Don’t load dependent images since we are in dyld where we will know
// and find out about all images that are loaded. Also when setting the
// executable module, it will clear the targets module list, and if we
// have an in memory dyld module, it will get removed from the list
// so we will need to add it back after setting the executable module,
// so we first try and see if we already have a weak pointer to the
// dyld module, make it into a shared pointer, then add the executable,
// then re-add it back to make sure it is always in the list.

ModuleSP dyld_module_sp(m_dyld_module_wp.lock());

const bool get_dependent_images = false;
m_process->GetTarget().SetExecutableModule (exe_module_sp, get_dependent_images);

if (dyld_module_sp)
target.GetImages().AppendIfNeeded (dyld_module_sp);
}
}
}
}

There’re two related problem:

  1. linkedit_load_addr must be invalid, because Target::ClearsModules empty the section list of target
  2. DynamicLoaderMacOSXDYLD::UpdateImageLoadAddress happened before Target::SetExecutableModule.

The first problem won’t fix even if we fix the second problem by moving UpdateImageLoadAddress below.

Maybe these code need some refactory.

My current solution is change the code from this:

voidTarget::SetExecutableModule (ModuleSP& executable_sp, bool get_dependent_files)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TARGET));
ClearModules(false);

if (executable_sp.get())
{

}

}

to this:

void
Target::SetExecutableModule (ModuleSP& executable_sp, bool get_dependent_files)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TARGET));
//ClearModules(false);
ModulesDidUnload (m_images, false);
//m_section_load_history.Clear();
m_images.Clear();
m_scratch_ast_context_ap.reset();
m_scratch_ast_source_ap.reset();
m_ast_importer_ap.reset();

if (executable_sp.get())
{

}

}

It’s work, although, it isn’t the right way.

I think these code needs refine by someone who familiar with lldb codebase.
Hope the issue would be fixed in the next Xcode release.

Best Wishes,
Lei Shi

You can work around this issue for now by adding the following line to your .lldbinit file:

settings set target.load-script-from-symbol-file false

This should disable the code that is looking for scripting resources inside debug symbol files and should avoid the code that is causing your executable to get messed up.

Another way you can fix this is to get a copy of the executable file that you are debugging on your local system. The reason it is having trouble is because it is loading your executable from memory because it doesn't have an on disk representation. This reading from the process is what is sensitive to requiring that sections be loaded before any data from the symbol table can be read from memory.

Is there a reason you don't have a local copy of the executable?

Greg Clayton

Yes, there isn’t a local copy of the executable, because I’m doing a remote debug for a third-party binary. Does this will issue get fixed in the next Xcode release?

Should I file a bug against this issue in case it be forgot?

Yes, please do.