Skip to content

Commit

Permalink
Fix "process load/unload" on android
Browse files Browse the repository at this point in the history
On android the symbols exposed by libdl (dlopen, dlclose, dlerror)
prefixed by "__dl_". This change moves the handling of process
load/unload to the platform object and override it for android to
handle the special prefix.

Differential revision: http://reviews.llvm.org/D11465

llvm-svn: 254504
  • Loading branch information
Tamas Berghammer committed Dec 2, 2015
1 parent 8b5dc2c commit 3cb132a
Show file tree
Hide file tree
Showing 11 changed files with 352 additions and 265 deletions.
34 changes: 33 additions & 1 deletion lldb/include/lldb/Target/Platform.h
Expand Up @@ -987,9 +987,41 @@ class ModuleCache;
virtual uint32_t
GetDefaultMemoryCacheLineSize() { return 0; }

//------------------------------------------------------------------
/// Load a shared library into this process.
///
/// Try and load a shared library into the current process. This
/// call might fail in the dynamic loader plug-in says it isn't safe
/// to try and load shared libraries at the moment.
///
/// @param[in] process
/// The process to load the image.
///
/// @param[in] image_spec
/// The image file spec that points to the shared library that
/// you want to load.
///
/// @param[out] error
/// An error object that gets filled in with any errors that
/// might occur when trying to load the shared library.
///
/// @return
/// A token that represents the shared library that can be
/// later used to unload the shared library. A value of
/// LLDB_INVALID_IMAGE_TOKEN will be returned if the shared
/// library can't be opened.
//------------------------------------------------------------------
virtual uint32_t
LoadImage (lldb_private::Process* process,
const lldb_private::FileSpec& image_spec,
lldb_private::Error& error);

virtual Error
UnloadImage (lldb_private::Process* process, uint32_t image_token);

protected:
bool m_is_host;
// Set to true when we are able to actually set the OS version while
// Set to true when we are able to actually set the OS version while
// being connected. For remote platforms, we might set the version ahead
// of time before we actually connect and this version might change when
// we actually connect to a remote platform. For the host platform this
Expand Down
36 changes: 9 additions & 27 deletions lldb/include/lldb/Target/Process.h
Expand Up @@ -1234,33 +1234,6 @@ class Process :
virtual lldb::addr_t
GetImageInfoAddress ();

//------------------------------------------------------------------
/// Load a shared library into this process.
///
/// Try and load a shared library into the current process. This
/// call might fail in the dynamic loader plug-in says it isn't safe
/// to try and load shared libraries at the moment.
///
/// @param[in] image_spec
/// The image file spec that points to the shared library that
/// you want to load.
///
/// @param[out] error
/// An error object that gets filled in with any errors that
/// might occur when trying to load the shared library.
///
/// @return
/// A token that represents the shared library that can be
/// later used to unload the shared library. A value of
/// LLDB_INVALID_IMAGE_TOKEN will be returned if the shared
/// library can't be opened.
//------------------------------------------------------------------
virtual uint32_t
LoadImage (const FileSpec &image_spec, Error &error);

virtual Error
UnloadImage (uint32_t image_token);

//------------------------------------------------------------------
/// Called when the process is about to broadcast a public stop.
///
Expand Down Expand Up @@ -3160,6 +3133,15 @@ class Process :
return Error("Not supported");
}

size_t
AddImageToken(lldb::addr_t image_ptr);

lldb::addr_t
GetImagePtrFromToken(size_t token) const;

void
ResetImageToken(size_t token);

protected:
void
SetState (lldb::EventSP &event_sp);
Expand Down
Expand Up @@ -182,7 +182,6 @@ def test_dyld_library_path(self):

@skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
@skipUnlessListedRemote(['android'])
@expectedFailureAndroid # dlopen and dlclose prefixed with "__dl_" on android causing JIT compilation issues
@skipIfWindows # Windows doesn't have dlopen and friends, dynamic libraries work differently
def test_lldb_process_load_and_unload_commands(self):
"""Test that lldb process load/unload command work correctly."""
Expand All @@ -205,21 +204,24 @@ def test_lldb_process_load_and_unload_commands(self):
shlib_dir = lldb.remote_platform.GetWorkingDirectory()
else:
shlib_dir = self.mydir
# Make sure that a_function does not exist at this point.
self.expect("image lookup -n a_function", "a_function should not exist yet",
error=True, matching=False,
patterns = ["1 match found .* %s" % shlib_dir])

if lldb.remote_platform:
dylibName = os.path.join(shlib_dir, 'libloadunload_a.so')
elif self.platformIsDarwin():
if self.platformIsDarwin():
dylibName = 'libloadunload_a.dylib'
else:
dylibName = 'libloadunload_a.so'

if lldb.remote_platform:
dylibPath = os.path.join(shlib_dir, dylibName)
else:
dylibPath = dylibName

# Make sure that a_function does not exist at this point.
self.expect("image lookup -n a_function", "a_function should not exist yet",
error=True, matching=False, patterns = ["1 match found"])

# Use lldb 'process load' to load the dylib.
self.expect("process load %s" % dylibName, "%s loaded correctly" % dylibName,
patterns = ['Loading "%s".*ok' % dylibName,
self.expect("process load %s" % dylibPath, "%s loaded correctly" % dylibPath,
patterns = ['Loading "%s".*ok' % dylibPath,
'Image [0-9]+ loaded'])

# Search for and match the "Image ([0-9]+) loaded" pattern.
Expand All @@ -234,7 +236,7 @@ def test_lldb_process_load_and_unload_commands(self):

# Now we should have an entry for a_function.
self.expect("image lookup -n a_function", "a_function should now exist",
patterns = ["1 match found .*%s" % shlib_dir])
patterns = ["1 match found .*%s" % dylibName])

# Use lldb 'process unload' to unload the dylib.
self.expect("process unload %s" % index, "%s unloaded correctly" % dylibName,
Expand Down
6 changes: 4 additions & 2 deletions lldb/source/API/SBProcess.cpp
Expand Up @@ -1297,7 +1297,8 @@ SBProcess::LoadImage (lldb::SBFileSpec &sb_image_spec, lldb::SBError &sb_error)
if (stop_locker.TryLock(&process_sp->GetRunLock()))
{
Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
return process_sp->LoadImage (*sb_image_spec, sb_error.ref());
PlatformSP platform_sp = process_sp->GetTarget().GetPlatform();
return platform_sp->LoadImage (process_sp.get(), *sb_image_spec, sb_error.ref());
}
else
{
Expand All @@ -1322,7 +1323,8 @@ SBProcess::UnloadImage (uint32_t image_token)
if (stop_locker.TryLock(&process_sp->GetRunLock()))
{
Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
sb_error.SetError (process_sp->UnloadImage (image_token));
PlatformSP platform_sp = process_sp->GetTarget().GetPlatform();
sb_error.SetError (platform_sp->UnloadImage (process_sp.get(), image_token));
}
else
{
Expand Down
7 changes: 4 additions & 3 deletions lldb/source/Commands/CommandObjectProcess.cpp
Expand Up @@ -1204,8 +1204,9 @@ class CommandObjectProcessLoad : public CommandObjectParsed
Error error;
const char *image_path = command.GetArgumentAtIndex(i);
FileSpec image_spec (image_path, false);
process->GetTarget().GetPlatform()->ResolveRemotePath(image_spec, image_spec);
uint32_t image_token = process->LoadImage(image_spec, error);
PlatformSP platform = process->GetTarget().GetPlatform();
platform->ResolveRemotePath(image_spec, image_spec);
uint32_t image_token = platform->LoadImage(process, image_spec, error);
if (image_token != LLDB_INVALID_IMAGE_TOKEN)
{
result.AppendMessageWithFormat ("Loading \"%s\"...ok\nImage %u loaded.\n", image_path, image_token);
Expand Down Expand Up @@ -1267,7 +1268,7 @@ class CommandObjectProcessUnload : public CommandObjectParsed
}
else
{
Error error (process->UnloadImage(image_token));
Error error (process->GetTarget().GetPlatform()->UnloadImage(process, image_token));
if (error.Success())
{
result.AppendMessageWithFormat ("Unloading shared library with index %u...ok\n", image_token);
Expand Down
90 changes: 90 additions & 0 deletions lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
Expand Up @@ -13,7 +13,9 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/StringConvert.h"
#include "Utility/UriParser.h"
Expand Down Expand Up @@ -374,3 +376,91 @@ PlatformAndroid::GetRemoteOSVersion ()
m_update_os_version = 0;
return m_major_os_version != 0;
}

uint32_t
PlatformAndroid::LoadImage(lldb_private::Process* process, const FileSpec& image_spec, Error& error)
{
char path[PATH_MAX];
image_spec.GetPath(path, sizeof(path));

StreamString expr;
expr.Printf(R"(
struct __lldb_dlopen_result { void *image_ptr; const char *error_str; } the_result;
the_result.image_ptr = __dl_dlopen ("%s", 2);
if (the_result.image_ptr == (void*)0x0)
the_result.error_str = __dl_dlerror();
else
the_result.error_str = (const char*)0x0;
the_result;
)",
path);
const char *prefix = R"(
extern "C" void* __dl_dlopen(const char* path, int mode);
extern "C" const char *__dl_dlerror(void);
)";
lldb::ValueObjectSP result_valobj_sp;
error = EvaluateLibdlExpression(process, expr.GetData(), prefix, result_valobj_sp);
if (error.Fail())
return LLDB_INVALID_IMAGE_TOKEN;

error = result_valobj_sp->GetError();
if (error.Fail())
return LLDB_INVALID_IMAGE_TOKEN;

Scalar scalar;
ValueObjectSP image_ptr_sp = result_valobj_sp->GetChildAtIndex(0, true);
if (!image_ptr_sp || !image_ptr_sp->ResolveValue(scalar))
{
error.SetErrorStringWithFormat("unable to load '%s'", path);
return LLDB_INVALID_IMAGE_TOKEN;
}

addr_t image_ptr = scalar.ULongLong(LLDB_INVALID_ADDRESS);
if (image_ptr != 0 && image_ptr != LLDB_INVALID_ADDRESS)
return process->AddImageToken(image_ptr);

if (image_ptr == 0)
{
ValueObjectSP error_str_sp = result_valobj_sp->GetChildAtIndex(1, true);
if (error_str_sp && error_str_sp->IsCStringContainer(true))
{
DataBufferSP buffer_sp(new DataBufferHeap(10240,0));
size_t num_chars = error_str_sp->ReadPointedString (buffer_sp, error, 10240).first;
if (error.Success() && num_chars > 0)
error.SetErrorStringWithFormat("dlopen error: %s", buffer_sp->GetBytes());
else
error.SetErrorStringWithFormat("dlopen failed for unknown reasons.");
return LLDB_INVALID_IMAGE_TOKEN;
}
}
error.SetErrorStringWithFormat("unable to load '%s'", path);
return LLDB_INVALID_IMAGE_TOKEN;
}

Error
PlatformAndroid::UnloadImage (lldb_private::Process* process, uint32_t image_token)
{
const addr_t image_addr = process->GetImagePtrFromToken(image_token);
if (image_addr == LLDB_INVALID_ADDRESS)
return Error("Invalid image token");

StreamString expr;
expr.Printf("__dl_dlclose((void*)0x%" PRIx64 ")", image_addr);
const char *prefix = "extern \"C\" int __dl_dlclose(void* handle);\n";
lldb::ValueObjectSP result_valobj_sp;
Error error = EvaluateLibdlExpression(process, expr.GetData(), prefix, result_valobj_sp);
if (error.Fail())
return error;

if (result_valobj_sp->GetError().Fail())
return result_valobj_sp->GetError();

Scalar scalar;
if (result_valobj_sp->ResolveValue(scalar))
{
if (scalar.UInt(1))
return Error("expression failed: \"%s\"", expr.GetData());
process->ResetImageToken(image_token);
}
return Error();
}
8 changes: 8 additions & 0 deletions lldb/source/Plugins/Platform/Android/PlatformAndroid.h
Expand Up @@ -84,6 +84,14 @@ namespace platform_android {
uint32_t
GetDefaultMemoryCacheLineSize() override;

uint32_t
LoadImage (lldb_private::Process* process,
const lldb_private::FileSpec& image_spec,
lldb_private::Error& error) override;

lldb_private::Error
UnloadImage (lldb_private::Process* process, uint32_t image_token) override;

protected:
const char *
GetCacheHostname () override;
Expand Down

0 comments on commit 3cb132a

Please sign in to comment.