Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion lldb/source/Core/ModuleList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,29 @@ ModuleList::~ModuleList() = default;
void ModuleList::AppendImpl(const ModuleSP &module_sp, bool use_notifier) {
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
m_modules.push_back(module_sp);
// We are required to keep the first element of the Module List as the
// executable module. So check here and if the first module is NOT an
// but the new one is, we insert this module at the beginning, rather than
// at the end.
// We don't need to do any of this if the list is empty:
if (m_modules.empty()) {
m_modules.push_back(module_sp);
} else {
// Since producing the ObjectFile may take some work, first check the 0th
// element, and only if that's NOT an executable look at the incoming
// ObjectFile. That way in the normal case we only look at the element
// 0 ObjectFile.
const bool elem_zero_is_executable
= m_modules[0]->GetObjectFile()->GetType()
== ObjectFile::Type::eTypeExecutable;
lldb_private::ObjectFile *obj = module_sp->GetObjectFile();
if (!elem_zero_is_executable && obj
&& obj->GetType() == ObjectFile::Type::eTypeExecutable) {
m_modules.insert(m_modules.begin(), module_sp);
} else {
m_modules.push_back(module_sp);
}
}
if (use_notifier && m_notifier)
m_notifier->NotifyModuleAdded(*this, module_sp);
}
Expand Down
4 changes: 4 additions & 0 deletions lldb/test/API/functionalities/executable_first/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CXX_SOURCES := main.cpp
DYLIB_CXX_SOURCES := b.cpp
DYLIB_NAME := bar
include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# This test checks that we make the executable the first
# element in the image list.

import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class TestExecutableIsFirst(TestBase):
NO_DEBUG_INFO_TESTCASE = True

def test_executable_is_first_before_run(self):
self.build()

ctx = self.platformContext
lib_name = ctx.shlib_prefix + "bar." + ctx.shlib_extension

exe = self.getBuildArtifact("a.out")
lib = self.getBuildArtifact(lib_name)

target = self.dbg.CreateTarget(None)
module = target.AddModule(lib, None, None)
self.assertTrue(module.IsValid(), "Added the module for the library")

module = target.AddModule(exe, None, None)
self.assertTrue(module.IsValid(), "Added the executable module")

# This is the executable module so it should be the first in the list:
first_module = target.GetModuleAtIndex(0)
print("This is the first test, this one succeeds")
self.assertEqual(module, first_module, "This executable is the first module")

# The executable property is an SBFileSpec to the executable. Make sure
# that is also right:
executable_module = target.executable
self.assertEqual(
first_module.file, executable_module, "Python property is also our module"
)

def test_executable_is_first_during_run(self):
self.build()
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "break after function call", lldb.SBFileSpec("main.cpp"),
extra_images=["bar"]
)

first_module = target.GetModuleAtIndex(0)
self.assertTrue(first_module.IsValid(), "We have at least one module")
executable_module = target.executable
self.assertEqual(first_module.file, executable_module, "They are the same")
1 change: 1 addition & 0 deletions lldb/test/API/functionalities/executable_first/b.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
int LLDB_DYLIB_EXPORT b_function() { return 500; }
6 changes: 6 additions & 0 deletions lldb/test/API/functionalities/executable_first/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
extern int b_function();

int main(int argc, char* argv[]) {
int ret_value = b_function();
return ret_value; // break after function call
}
8 changes: 8 additions & 0 deletions lldb/tools/debugserver/source/MacOSX/MachProcess.mm
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <algorithm>
#include <chrono>
#include <map>
#include <unordered_set>

#include <TargetConditionals.h>
#import <Foundation/Foundation.h>
Expand Down Expand Up @@ -1065,9 +1066,16 @@ static bool mach_header_validity_test(uint32_t magic, uint32_t cputype) {
dyld_process_info info =
m_dyld_process_info_create(m_task.TaskPort(), 0, &kern_ret);
if (info) {
// There's a bug in the interaction between dyld and older dyld_sim's
// (e.g. from the iOS 15 simulator) that causes dyld to report the same
// binary twice. We use this set to eliminate the duplicates.
__block std::unordered_set<uint64_t> seen_header_addrs;
m_dyld_process_info_for_each_image(
info,
^(uint64_t mach_header_addr, const uuid_t uuid, const char *path) {
auto res_pair = seen_header_addrs.insert(mach_header_addr);
if (!res_pair.second)
return;
struct binary_image_information image;
image.filename = path;
uuid_copy(image.macho_info.uuid, uuid);
Expand Down