forked from OSchip/llvm-project
Add a way to load an image using a library name and list of paths.
This provides an efficient (at least on Posix platforms) way to offload to the target process the search & loading of a library when all we have are the library name and a set of potential candidate locations. <rdar://problem/40905971> llvm-svn: 335912
This commit is contained in:
parent
3cabf73270
commit
0d231f7161
|
@ -313,6 +313,40 @@ public:
|
||||||
const lldb::SBFileSpec &remote_image_spec,
|
const lldb::SBFileSpec &remote_image_spec,
|
||||||
lldb::SBError &error);
|
lldb::SBError &error);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
/// Load a shared library into this process, starting with a
|
||||||
|
/// library name and a list of paths, searching along the list of
|
||||||
|
/// paths till you find a matching library.
|
||||||
|
///
|
||||||
|
/// @param[in] local_spec
|
||||||
|
/// The name of the shared library that you want to load.
|
||||||
|
/// If local_spec is a relative path, the relative path will be
|
||||||
|
/// appended to the search paths.
|
||||||
|
/// If the local_spec is an absolute path, just the basename is used.
|
||||||
|
///
|
||||||
|
/// @param[in] paths
|
||||||
|
/// A list of paths to search for the library whose basename is
|
||||||
|
/// local_spec.
|
||||||
|
///
|
||||||
|
/// @param[out] loaded_path
|
||||||
|
/// If the library was found along the paths, this will store the
|
||||||
|
/// full path to the found library.
|
||||||
|
///
|
||||||
|
/// @param[out] error
|
||||||
|
/// An error object that gets filled in with any errors that
|
||||||
|
/// might occur when trying to search for the shared library.
|
||||||
|
///
|
||||||
|
/// @return
|
||||||
|
/// A token that represents the shared library that can be
|
||||||
|
/// later passed to UnloadImage. A value of
|
||||||
|
/// LLDB_INVALID_IMAGE_TOKEN will be returned if the shared
|
||||||
|
/// library can't be opened.
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
uint32_t LoadImageUsingPaths(const lldb::SBFileSpec &image_spec,
|
||||||
|
SBStringList &paths,
|
||||||
|
lldb::SBFileSpec &loaded_path,
|
||||||
|
lldb::SBError &error);
|
||||||
|
|
||||||
lldb::SBError UnloadImage(uint32_t image_token);
|
lldb::SBError UnloadImage(uint32_t image_token);
|
||||||
|
|
||||||
lldb::SBError SendEventData(const char *data);
|
lldb::SBError SendEventData(const char *data);
|
||||||
|
|
|
@ -832,9 +832,45 @@ public:
|
||||||
const lldb_private::FileSpec &remote_file,
|
const lldb_private::FileSpec &remote_file,
|
||||||
lldb_private::Status &error);
|
lldb_private::Status &error);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
/// Load a shared library specified by base name into this process,
|
||||||
|
/// looking by hand along a set of paths.
|
||||||
|
///
|
||||||
|
/// @param[in] process
|
||||||
|
/// The process to load the image.
|
||||||
|
///
|
||||||
|
/// @param[in] library_name
|
||||||
|
/// The name of the library to look for.
|
||||||
|
///
|
||||||
|
/// @param[in] path_list
|
||||||
|
/// The list of paths to use to search for the library. First
|
||||||
|
/// match wins.
|
||||||
|
///
|
||||||
|
/// @param[out] error
|
||||||
|
/// An error object that gets filled in with any errors that
|
||||||
|
/// might occur when trying to load the shared library.
|
||||||
|
///
|
||||||
|
/// @param[out] loaded_path
|
||||||
|
/// If non-null, the path to the dylib that was successfully loaded
|
||||||
|
/// is stored in this path.
|
||||||
|
///
|
||||||
|
/// @return
|
||||||
|
/// A token that represents the shared library which can be
|
||||||
|
/// passed to UnloadImage. A value of
|
||||||
|
/// LLDB_INVALID_IMAGE_TOKEN will be returned if the shared
|
||||||
|
/// library can't be opened.
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
uint32_t LoadImageUsingPaths(lldb_private::Process *process,
|
||||||
|
const lldb_private::FileSpec &library_name,
|
||||||
|
const std::vector<std::string> &paths,
|
||||||
|
lldb_private::Status &error,
|
||||||
|
lldb_private::FileSpec *loaded_path);
|
||||||
|
|
||||||
virtual uint32_t DoLoadImage(lldb_private::Process *process,
|
virtual uint32_t DoLoadImage(lldb_private::Process *process,
|
||||||
const lldb_private::FileSpec &remote_file,
|
const lldb_private::FileSpec &remote_file,
|
||||||
lldb_private::Status &error);
|
const std::vector<std::string> *paths,
|
||||||
|
lldb_private::Status &error,
|
||||||
|
lldb_private::FileSpec *loaded_path = nullptr);
|
||||||
|
|
||||||
virtual Status UnloadImage(lldb_private::Process *process,
|
virtual Status UnloadImage(lldb_private::Process *process,
|
||||||
uint32_t image_token);
|
uint32_t image_token);
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
basic_process
|
|
@ -0,0 +1,13 @@
|
||||||
|
LEVEL := ../../make
|
||||||
|
|
||||||
|
CXX_SOURCES := main.cpp
|
||||||
|
|
||||||
|
include $(LEVEL)/Makefile.rules
|
||||||
|
|
||||||
|
all: hidden_lib a.out
|
||||||
|
|
||||||
|
hidden_lib:
|
||||||
|
$(MAKE) VPATH=$(SRCDIR)/hidden -I $(SRCDIR)/hidden -C hidden -f $(SRCDIR)/hidden/Makefile
|
||||||
|
|
||||||
|
clean::
|
||||||
|
$(MAKE) -I $(SRCDIR)/hidden -C hidden -f $(SRCDIR)/hidden/Makefile clean
|
|
@ -0,0 +1,126 @@
|
||||||
|
"""
|
||||||
|
Test that SBProcess.LoadImageUsingPaths works correctly.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import re
|
||||||
|
import lldb
|
||||||
|
from lldbsuite.test.decorators import *
|
||||||
|
from lldbsuite.test.lldbtest import *
|
||||||
|
from lldbsuite.test import lldbutil
|
||||||
|
|
||||||
|
|
||||||
|
@skipIfWindows # The Windows platform doesn't implement DoLoadImage.
|
||||||
|
class LoadUsingPathsTestCase(TestBase):
|
||||||
|
|
||||||
|
mydir = TestBase.compute_mydir(__file__)
|
||||||
|
|
||||||
|
NO_DEBUG_INFO_TESTCASE = True
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
# Call super's setUp().
|
||||||
|
TestBase.setUp(self)
|
||||||
|
# Make the hidden directory in the build hierarchy:
|
||||||
|
lldbutil.mkdir_p(self.getBuildArtifact("hidden"))
|
||||||
|
|
||||||
|
# Invoke the default build rule.
|
||||||
|
self.build()
|
||||||
|
|
||||||
|
ext = 'so'
|
||||||
|
if self.platformIsDarwin():
|
||||||
|
ext = 'dylib'
|
||||||
|
self.lib_name = 'libloadunload.' + ext
|
||||||
|
|
||||||
|
self.wd = self.getBuildDir()
|
||||||
|
self.hidden_dir = os.path.join(self.wd, 'hidden')
|
||||||
|
self.hidden_lib = os.path.join(self.hidden_dir, self.lib_name)
|
||||||
|
|
||||||
|
@skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
|
||||||
|
@not_remote_testsuite_ready
|
||||||
|
@skipIfWindows # Windows doesn't have dlopen and friends, dynamic libraries work differently
|
||||||
|
def test_load_using_paths(self):
|
||||||
|
"""Test that we can load a module by providing a set of search paths."""
|
||||||
|
if self.platformIsDarwin():
|
||||||
|
dylibName = 'libloadunload_d.dylib'
|
||||||
|
else:
|
||||||
|
dylibName = 'libloadunload_d.so'
|
||||||
|
|
||||||
|
# The directory with the dynamic library we did not link to.
|
||||||
|
path_dir = os.path.join(self.getBuildDir(), "hidden")
|
||||||
|
|
||||||
|
(target, process, thread,
|
||||||
|
_) = lldbutil.run_to_source_breakpoint(self,
|
||||||
|
"Break here to do the load using paths",
|
||||||
|
lldb.SBFileSpec("main.cpp"))
|
||||||
|
error = lldb.SBError()
|
||||||
|
lib_spec = lldb.SBFileSpec(self.lib_name)
|
||||||
|
paths = lldb.SBStringList()
|
||||||
|
paths.AppendString(self.wd)
|
||||||
|
paths.AppendString(os.path.join(self.wd, "no_such_dir"))
|
||||||
|
|
||||||
|
out_spec = lldb.SBFileSpec()
|
||||||
|
|
||||||
|
# First try with no correct directories on the path, and make sure that doesn't blow up:
|
||||||
|
token = process.LoadImageUsingPaths(lib_spec, paths, out_spec, error)
|
||||||
|
self.assertEqual(token, lldb.LLDB_INVALID_IMAGE_TOKEN, "Only looked on the provided path.")
|
||||||
|
|
||||||
|
# Now add the correct dir to the paths list and try again:
|
||||||
|
paths.AppendString(self.hidden_dir)
|
||||||
|
token = process.LoadImageUsingPaths(lib_spec, paths, out_spec, error)
|
||||||
|
|
||||||
|
self.assertNotEqual(token, lldb.LLDB_INVALID_IMAGE_TOKEN, "Got a valid token")
|
||||||
|
self.assertEqual(out_spec, lldb.SBFileSpec(self.hidden_lib), "Found the expected library")
|
||||||
|
|
||||||
|
# Make sure this really is in the image list:
|
||||||
|
loaded_module = target.FindModule(out_spec)
|
||||||
|
|
||||||
|
self.assertTrue(loaded_module.IsValid(), "The loaded module is in the image list.")
|
||||||
|
|
||||||
|
# Now see that we can call a function in the loaded module.
|
||||||
|
value = thread.frames[0].EvaluateExpression("d_function()", lldb.SBExpressionOptions())
|
||||||
|
self.assertTrue(value.GetError().Success(), "Got a value from the expression")
|
||||||
|
ret_val = value.GetValueAsSigned()
|
||||||
|
self.assertEqual(ret_val, 12345, "Got the right value")
|
||||||
|
|
||||||
|
# Make sure the token works to unload it:
|
||||||
|
process.UnloadImage(token)
|
||||||
|
|
||||||
|
# Make sure this really is no longer in the image list:
|
||||||
|
loaded_module = target.FindModule(out_spec)
|
||||||
|
|
||||||
|
self.assertFalse(loaded_module.IsValid(), "The unloaded module is no longer in the image list.")
|
||||||
|
|
||||||
|
# Make sure a relative path also works:
|
||||||
|
paths.Clear()
|
||||||
|
paths.AppendString(os.path.join(self.wd, "no_such_dir"))
|
||||||
|
paths.AppendString(self.wd)
|
||||||
|
relative_spec = lldb.SBFileSpec(os.path.join("hidden", self.lib_name))
|
||||||
|
|
||||||
|
out_spec = lldb.SBFileSpec()
|
||||||
|
token = process.LoadImageUsingPaths(relative_spec, paths, out_spec, error)
|
||||||
|
|
||||||
|
self.assertNotEqual(token, lldb.LLDB_INVALID_IMAGE_TOKEN, "Got a valid token")
|
||||||
|
self.assertEqual(out_spec, lldb.SBFileSpec(self.hidden_lib), "Found the expected library")
|
||||||
|
|
||||||
|
process.UnloadImage(token)
|
||||||
|
|
||||||
|
# Finally, passing in an absolute path should work like the basename:
|
||||||
|
# This should NOT work because we've taken hidden_dir off the paths:
|
||||||
|
abs_spec = lldb.SBFileSpec(os.path.join(self.hidden_dir, self.lib_name))
|
||||||
|
|
||||||
|
token = process.LoadImageUsingPaths(lib_spec, paths, out_spec, error)
|
||||||
|
self.assertEqual(token, lldb.LLDB_INVALID_IMAGE_TOKEN, "Only looked on the provided path.")
|
||||||
|
|
||||||
|
# But it should work when we add the dir:
|
||||||
|
# Now add the correct dir to the paths list and try again:
|
||||||
|
paths.AppendString(self.hidden_dir)
|
||||||
|
token = process.LoadImageUsingPaths(lib_spec, paths, out_spec, error)
|
||||||
|
|
||||||
|
self.assertNotEqual(token, lldb.LLDB_INVALID_IMAGE_TOKEN, "Got a valid token")
|
||||||
|
self.assertEqual(out_spec, lldb.SBFileSpec(self.hidden_lib), "Found the expected library")
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
LEVEL := ../../../make
|
||||||
|
|
||||||
|
DYLIB_NAME := loadunload
|
||||||
|
DYLIB_CXX_SOURCES := d.cpp
|
||||||
|
DYLIB_ONLY := YES
|
||||||
|
|
||||||
|
include $(LEVEL)/Makefile.rules
|
|
@ -0,0 +1,21 @@
|
||||||
|
//===-- c.c -----------------------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
int d_init()
|
||||||
|
{
|
||||||
|
return 456;
|
||||||
|
}
|
||||||
|
|
||||||
|
int d_global = d_init();
|
||||||
|
|
||||||
|
int
|
||||||
|
d_function ()
|
||||||
|
{ // Find this line number within d_dunction().
|
||||||
|
return 12345;
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
//===-- main.c --------------------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char const *argv[])
|
||||||
|
{
|
||||||
|
printf("Break here to do the load using paths.");
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -373,6 +373,19 @@ public:
|
||||||
uint32_t
|
uint32_t
|
||||||
LoadImage (lldb::SBFileSpec &image_spec, lldb::SBError &error);
|
LoadImage (lldb::SBFileSpec &image_spec, lldb::SBError &error);
|
||||||
|
|
||||||
|
%feature("autodoc", "
|
||||||
|
Load the library whose filename is given by image_spec looking in all the
|
||||||
|
paths supplied in the paths argument. If successful, return a token that
|
||||||
|
can be passed to UnloadImage and fill loaded_path with the path that was
|
||||||
|
successfully loaded. On failure, return
|
||||||
|
lldb.LLDB_INVALID_IMAGE_TOKEN.
|
||||||
|
") LoadImageUsingPaths;
|
||||||
|
uint32_t
|
||||||
|
LoadImageUsingPaths(const lldb::SBFileSpec &image_spec,
|
||||||
|
SBStringList &paths,
|
||||||
|
lldb::SBFileSpec &loaded_path,
|
||||||
|
SBError &error);
|
||||||
|
|
||||||
lldb::SBError
|
lldb::SBError
|
||||||
UnloadImage (uint32_t image_token);
|
UnloadImage (uint32_t image_token);
|
||||||
|
|
||||||
|
|
|
@ -1187,6 +1187,57 @@ uint32_t SBProcess::LoadImage(const lldb::SBFileSpec &sb_local_image_spec,
|
||||||
return LLDB_INVALID_IMAGE_TOKEN;
|
return LLDB_INVALID_IMAGE_TOKEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t SBProcess::LoadImageUsingPaths(const lldb::SBFileSpec &image_spec,
|
||||||
|
SBStringList &paths,
|
||||||
|
lldb::SBFileSpec &loaded_path,
|
||||||
|
lldb::SBError &error) {
|
||||||
|
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
|
||||||
|
ProcessSP process_sp(GetSP());
|
||||||
|
if (process_sp) {
|
||||||
|
Process::StopLocker stop_locker;
|
||||||
|
if (stop_locker.TryLock(&process_sp->GetRunLock())) {
|
||||||
|
if (log)
|
||||||
|
log->Printf("SBProcess(%p)::LoadImageUsingPaths() => "
|
||||||
|
"calling Platform::LoadImageUsingPaths for: %s",
|
||||||
|
static_cast<void *>(process_sp.get()),
|
||||||
|
image_spec.GetFilename());
|
||||||
|
|
||||||
|
std::lock_guard<std::recursive_mutex> guard(
|
||||||
|
process_sp->GetTarget().GetAPIMutex());
|
||||||
|
PlatformSP platform_sp = process_sp->GetTarget().GetPlatform();
|
||||||
|
size_t num_paths = paths.GetSize();
|
||||||
|
std::vector<std::string> paths_vec;
|
||||||
|
paths_vec.reserve(num_paths);
|
||||||
|
for (size_t i = 0; i < num_paths; i++)
|
||||||
|
paths_vec.push_back(paths.GetStringAtIndex(i));
|
||||||
|
FileSpec loaded_spec;
|
||||||
|
|
||||||
|
uint32_t token = platform_sp->LoadImageUsingPaths(process_sp.get(),
|
||||||
|
*image_spec,
|
||||||
|
paths_vec,
|
||||||
|
error.ref(),
|
||||||
|
&loaded_spec);
|
||||||
|
if (token != LLDB_INVALID_IMAGE_TOKEN)
|
||||||
|
loaded_path = loaded_spec;
|
||||||
|
return token;
|
||||||
|
} else {
|
||||||
|
if (log)
|
||||||
|
log->Printf("SBProcess(%p)::LoadImageUsingPaths() => error: "
|
||||||
|
"process is running",
|
||||||
|
static_cast<void *>(process_sp.get()));
|
||||||
|
error.SetErrorString("process is running");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (log)
|
||||||
|
log->Printf("SBProcess(%p)::LoadImageUsingPaths() => error: "
|
||||||
|
"called with invalid process",
|
||||||
|
static_cast<void *>(process_sp.get()));
|
||||||
|
error.SetErrorString("process is invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
return LLDB_INVALID_IMAGE_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
lldb::SBError SBProcess::UnloadImage(uint32_t image_token) {
|
lldb::SBError SBProcess::UnloadImage(uint32_t image_token) {
|
||||||
lldb::SBError sb_error;
|
lldb::SBError sb_error;
|
||||||
ProcessSP process_sp(GetSP());
|
ProcessSP process_sp(GetSP());
|
||||||
|
|
|
@ -91,8 +91,12 @@ bool FunctionCaller::WriteFunctionWrapper(
|
||||||
m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx,
|
m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx,
|
||||||
can_interpret, eExecutionPolicyAlways));
|
can_interpret, eExecutionPolicyAlways));
|
||||||
|
|
||||||
if (!jit_error.Success())
|
if (!jit_error.Success()) {
|
||||||
|
diagnostic_manager.Printf(eDiagnosticSeverityError,
|
||||||
|
"Error in PrepareForExecution: %s.",
|
||||||
|
jit_error.AsCString());
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_parser->GetGenerateDebugInfo()) {
|
if (m_parser->GetGenerateDebugInfo()) {
|
||||||
lldb::ModuleSP jit_module_sp(m_execution_unit_sp->GetJITModule());
|
lldb::ModuleSP jit_module_sp(m_execution_unit_sp->GetJITModule());
|
||||||
|
|
|
@ -946,12 +946,39 @@ PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx,
|
||||||
const char *error_str;
|
const char *error_str;
|
||||||
};
|
};
|
||||||
|
|
||||||
void * __lldb_dlopen_wrapper (const char *path,
|
extern void *memcpy(void *, void *, size_t size);
|
||||||
|
extern size_t strlen(const char *);
|
||||||
|
|
||||||
|
|
||||||
|
void * __lldb_dlopen_wrapper (const char *name,
|
||||||
|
const char *path_strings,
|
||||||
|
char *buffer,
|
||||||
__lldb_dlopen_result *result_ptr)
|
__lldb_dlopen_result *result_ptr)
|
||||||
{
|
{
|
||||||
result_ptr->image_ptr = dlopen(path, 2);
|
// This is the case where the name is the full path:
|
||||||
if (result_ptr->image_ptr == (void *) 0x0)
|
if (path_strings == (char *) 0x0) {
|
||||||
|
result_ptr->image_ptr = dlopen(name, 2);
|
||||||
|
if (result_ptr->image_ptr != (void *) 0x0)
|
||||||
|
result_ptr->error_str = nullptr;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the case where we have a list of paths:
|
||||||
|
size_t name_len = strlen(name);
|
||||||
|
while (path_strings != (void *) 0x0 && path_strings[0] != '\0') {
|
||||||
|
size_t path_len = strlen(path_strings);
|
||||||
|
memcpy((void *) buffer, (void *) path_strings, path_len);
|
||||||
|
buffer[path_len] = '/';
|
||||||
|
char *target_ptr = buffer+path_len+1;
|
||||||
|
memcpy((void *) target_ptr, (void *) name, name_len + 1);
|
||||||
|
result_ptr->image_ptr = dlopen(buffer, 2);
|
||||||
|
if (result_ptr->image_ptr != (void *) 0x0) {
|
||||||
|
result_ptr->error_str = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
result_ptr->error_str = dlerror();
|
result_ptr->error_str = dlerror();
|
||||||
|
path_strings = path_strings + path_len + 1;
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
@ -993,13 +1020,16 @@ PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx,
|
||||||
CompilerType clang_char_pointer_type
|
CompilerType clang_char_pointer_type
|
||||||
= ast->GetBasicType(eBasicTypeChar).GetPointerType();
|
= ast->GetBasicType(eBasicTypeChar).GetPointerType();
|
||||||
|
|
||||||
// We are passing two arguments, the path to dlopen, and a pointer to the
|
// We are passing four arguments, the basename, the list of places to look,
|
||||||
// storage we've made for the result:
|
// a buffer big enough for all the path + name combos, and
|
||||||
|
// a pointer to the storage we've made for the result:
|
||||||
value.SetValueType(Value::eValueTypeScalar);
|
value.SetValueType(Value::eValueTypeScalar);
|
||||||
value.SetCompilerType(clang_void_pointer_type);
|
value.SetCompilerType(clang_void_pointer_type);
|
||||||
arguments.PushValue(value);
|
arguments.PushValue(value);
|
||||||
value.SetCompilerType(clang_char_pointer_type);
|
value.SetCompilerType(clang_char_pointer_type);
|
||||||
arguments.PushValue(value);
|
arguments.PushValue(value);
|
||||||
|
arguments.PushValue(value);
|
||||||
|
arguments.PushValue(value);
|
||||||
|
|
||||||
do_dlopen_function = dlopen_utility_func_up->MakeFunctionCaller(
|
do_dlopen_function = dlopen_utility_func_up->MakeFunctionCaller(
|
||||||
clang_void_pointer_type, arguments, exe_ctx.GetThreadSP(), utility_error);
|
clang_void_pointer_type, arguments, exe_ctx.GetThreadSP(), utility_error);
|
||||||
|
@ -1021,7 +1051,12 @@ PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx,
|
||||||
|
|
||||||
uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process,
|
uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process,
|
||||||
const lldb_private::FileSpec &remote_file,
|
const lldb_private::FileSpec &remote_file,
|
||||||
lldb_private::Status &error) {
|
const std::vector<std::string> *paths,
|
||||||
|
lldb_private::Status &error,
|
||||||
|
lldb_private::FileSpec *loaded_image) {
|
||||||
|
if (loaded_image)
|
||||||
|
loaded_image->Clear();
|
||||||
|
|
||||||
std::string path;
|
std::string path;
|
||||||
path = remote_file.GetPath();
|
path = remote_file.GetPath();
|
||||||
|
|
||||||
|
@ -1100,9 +1135,81 @@ uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process,
|
||||||
process->DeallocateMemory(return_addr);
|
process->DeallocateMemory(return_addr);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// This will be the address of the storage for paths, if we are using them,
|
||||||
|
// or nullptr to signal we aren't.
|
||||||
|
lldb::addr_t path_array_addr = 0x0;
|
||||||
|
llvm::Optional<CleanUp> path_array_cleanup;
|
||||||
|
|
||||||
|
// This is the address to a buffer large enough to hold the largest path
|
||||||
|
// conjoined with the library name we're passing in. This is a convenience
|
||||||
|
// to avoid having to call malloc in the dlopen function.
|
||||||
|
lldb::addr_t buffer_addr = 0x0;
|
||||||
|
llvm::Optional<CleanUp> buffer_cleanup;
|
||||||
|
|
||||||
// Set the values into our args and write them to the target:
|
// Set the values into our args and write them to the target:
|
||||||
|
if (paths != nullptr) {
|
||||||
|
// First insert the paths into the target. This is expected to be a
|
||||||
|
// continuous buffer with the strings laid out null terminated and
|
||||||
|
// end to end with an empty string terminating the buffer.
|
||||||
|
// We also compute the buffer's required size as we go.
|
||||||
|
size_t buffer_size = 0;
|
||||||
|
std::string path_array;
|
||||||
|
for (auto path : *paths) {
|
||||||
|
size_t path_size = path.size();
|
||||||
|
path_array.append(path);
|
||||||
|
path_array.push_back('\0');
|
||||||
|
if (path_size > buffer_size)
|
||||||
|
buffer_size = path_size;
|
||||||
|
}
|
||||||
|
path_array.push_back('\0');
|
||||||
|
|
||||||
|
path_array_addr = process->AllocateMemory(path_array.size(),
|
||||||
|
permissions,
|
||||||
|
utility_error);
|
||||||
|
if (path_array_addr == LLDB_INVALID_ADDRESS) {
|
||||||
|
error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
|
||||||
|
"for path array: %s",
|
||||||
|
utility_error.AsCString());
|
||||||
|
return LLDB_INVALID_IMAGE_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we deallocate the paths array.
|
||||||
|
path_array_cleanup.emplace([process, path_array_addr] {
|
||||||
|
process->DeallocateMemory(path_array_addr);
|
||||||
|
});
|
||||||
|
|
||||||
|
process->WriteMemory(path_array_addr, path_array.data(),
|
||||||
|
path_array.size(), utility_error);
|
||||||
|
|
||||||
|
if (utility_error.Fail()) {
|
||||||
|
error.SetErrorStringWithFormat("dlopen error: could not write path array:"
|
||||||
|
" %s", utility_error.AsCString());
|
||||||
|
return LLDB_INVALID_IMAGE_TOKEN;
|
||||||
|
}
|
||||||
|
// Now make spaces in the target for the buffer. We need to add one for
|
||||||
|
// the '/' that the utility function will insert and one for the '\0':
|
||||||
|
buffer_size += path.size() + 2;
|
||||||
|
|
||||||
|
buffer_addr = process->AllocateMemory(buffer_size,
|
||||||
|
permissions,
|
||||||
|
utility_error);
|
||||||
|
if (buffer_addr == LLDB_INVALID_ADDRESS) {
|
||||||
|
error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
|
||||||
|
"for buffer: %s",
|
||||||
|
utility_error.AsCString());
|
||||||
|
return LLDB_INVALID_IMAGE_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we deallocate the buffer memory:
|
||||||
|
buffer_cleanup.emplace([process, buffer_addr] {
|
||||||
|
process->DeallocateMemory(buffer_addr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
arguments.GetValueAtIndex(0)->GetScalar() = path_addr;
|
arguments.GetValueAtIndex(0)->GetScalar() = path_addr;
|
||||||
arguments.GetValueAtIndex(1)->GetScalar() = return_addr;
|
arguments.GetValueAtIndex(1)->GetScalar() = path_array_addr;
|
||||||
|
arguments.GetValueAtIndex(2)->GetScalar() = buffer_addr;
|
||||||
|
arguments.GetValueAtIndex(3)->GetScalar() = return_addr;
|
||||||
|
|
||||||
lldb::addr_t func_args_addr = LLDB_INVALID_ADDRESS;
|
lldb::addr_t func_args_addr = LLDB_INVALID_ADDRESS;
|
||||||
|
|
||||||
|
@ -1146,7 +1253,7 @@ uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process,
|
||||||
ExpressionResults results = do_dlopen_function->ExecuteFunction(
|
ExpressionResults results = do_dlopen_function->ExecuteFunction(
|
||||||
exe_ctx, &func_args_addr, options, diagnostics, return_value);
|
exe_ctx, &func_args_addr, options, diagnostics, return_value);
|
||||||
if (results != eExpressionCompleted) {
|
if (results != eExpressionCompleted) {
|
||||||
error.SetErrorStringWithFormat("dlopen error: could write execute "
|
error.SetErrorStringWithFormat("dlopen error: failed executing "
|
||||||
"dlopen wrapper function: %s",
|
"dlopen wrapper function: %s",
|
||||||
diagnostics.GetString().c_str());
|
diagnostics.GetString().c_str());
|
||||||
return LLDB_INVALID_IMAGE_TOKEN;
|
return LLDB_INVALID_IMAGE_TOKEN;
|
||||||
|
@ -1162,8 +1269,19 @@ uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process,
|
||||||
}
|
}
|
||||||
|
|
||||||
// The dlopen succeeded!
|
// The dlopen succeeded!
|
||||||
if (token != 0x0)
|
if (token != 0x0) {
|
||||||
|
if (loaded_image && buffer_addr != 0x0)
|
||||||
|
{
|
||||||
|
// Capture the image which was loaded. We leave it in the buffer on
|
||||||
|
// exit from the dlopen function, so we can just read it from there:
|
||||||
|
std::string name_string;
|
||||||
|
process->ReadCStringFromMemory(buffer_addr, name_string, utility_error);
|
||||||
|
if (utility_error.Success())
|
||||||
|
loaded_image->SetFile(name_string, false,
|
||||||
|
llvm::sys::path::Style::posix);
|
||||||
|
}
|
||||||
return process->AddImageToken(token);
|
return process->AddImageToken(token);
|
||||||
|
}
|
||||||
|
|
||||||
// We got an error, lets read in the error string:
|
// We got an error, lets read in the error string:
|
||||||
std::string dlopen_error_str;
|
std::string dlopen_error_str;
|
||||||
|
|
|
@ -165,7 +165,9 @@ public:
|
||||||
|
|
||||||
uint32_t DoLoadImage(lldb_private::Process *process,
|
uint32_t DoLoadImage(lldb_private::Process *process,
|
||||||
const lldb_private::FileSpec &remote_file,
|
const lldb_private::FileSpec &remote_file,
|
||||||
lldb_private::Status &error) override;
|
const std::vector<std::string> *paths,
|
||||||
|
lldb_private::Status &error,
|
||||||
|
lldb_private::FileSpec *loaded_image) override;
|
||||||
|
|
||||||
lldb_private::Status UnloadImage(lldb_private::Process *process,
|
lldb_private::Status UnloadImage(lldb_private::Process *process,
|
||||||
uint32_t image_token) override;
|
uint32_t image_token) override;
|
||||||
|
|
|
@ -1738,7 +1738,7 @@ uint32_t Platform::LoadImage(lldb_private::Process *process,
|
||||||
if (error.Fail())
|
if (error.Fail())
|
||||||
return LLDB_INVALID_IMAGE_TOKEN;
|
return LLDB_INVALID_IMAGE_TOKEN;
|
||||||
}
|
}
|
||||||
return DoLoadImage(process, remote_file, error);
|
return DoLoadImage(process, remote_file, nullptr, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (local_file) {
|
if (local_file) {
|
||||||
|
@ -1751,12 +1751,12 @@ uint32_t Platform::LoadImage(lldb_private::Process *process,
|
||||||
if (error.Fail())
|
if (error.Fail())
|
||||||
return LLDB_INVALID_IMAGE_TOKEN;
|
return LLDB_INVALID_IMAGE_TOKEN;
|
||||||
}
|
}
|
||||||
return DoLoadImage(process, target_file, error);
|
return DoLoadImage(process, target_file, nullptr, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remote_file) {
|
if (remote_file) {
|
||||||
// Only remote file was specified so we don't have to do any copying
|
// Only remote file was specified so we don't have to do any copying
|
||||||
return DoLoadImage(process, remote_file, error);
|
return DoLoadImage(process, remote_file, nullptr, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
error.SetErrorString("Neither local nor remote file was specified");
|
error.SetErrorString("Neither local nor remote file was specified");
|
||||||
|
@ -1765,11 +1765,30 @@ uint32_t Platform::LoadImage(lldb_private::Process *process,
|
||||||
|
|
||||||
uint32_t Platform::DoLoadImage(lldb_private::Process *process,
|
uint32_t Platform::DoLoadImage(lldb_private::Process *process,
|
||||||
const lldb_private::FileSpec &remote_file,
|
const lldb_private::FileSpec &remote_file,
|
||||||
lldb_private::Status &error) {
|
const std::vector<std::string> *paths,
|
||||||
|
lldb_private::Status &error,
|
||||||
|
lldb_private::FileSpec *loaded_image) {
|
||||||
error.SetErrorString("LoadImage is not supported on the current platform");
|
error.SetErrorString("LoadImage is not supported on the current platform");
|
||||||
return LLDB_INVALID_IMAGE_TOKEN;
|
return LLDB_INVALID_IMAGE_TOKEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t Platform::LoadImageUsingPaths(lldb_private::Process *process,
|
||||||
|
const lldb_private::FileSpec &remote_filename,
|
||||||
|
const std::vector<std::string> &paths,
|
||||||
|
lldb_private::Status &error,
|
||||||
|
lldb_private::FileSpec *loaded_path)
|
||||||
|
{
|
||||||
|
FileSpec file_to_use;
|
||||||
|
if (remote_filename.IsAbsolute())
|
||||||
|
file_to_use = FileSpec(remote_filename.GetFilename().GetStringRef(),
|
||||||
|
false,
|
||||||
|
remote_filename.GetPathStyle());
|
||||||
|
else
|
||||||
|
file_to_use = remote_filename;
|
||||||
|
|
||||||
|
return DoLoadImage(process, file_to_use, &paths, error, loaded_path);
|
||||||
|
}
|
||||||
|
|
||||||
Status Platform::UnloadImage(lldb_private::Process *process,
|
Status Platform::UnloadImage(lldb_private::Process *process,
|
||||||
uint32_t image_token) {
|
uint32_t image_token) {
|
||||||
return Status("UnloadImage is not supported on the current platform");
|
return Status("UnloadImage is not supported on the current platform");
|
||||||
|
|
Loading…
Reference in New Issue