forked from RobotLocomotion/drake
-
Notifications
You must be signed in to change notification settings - Fork 0
/
find_loaded_library.cc
118 lines (105 loc) · 4.07 KB
/
find_loaded_library.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include "drake/common/find_loaded_library.h"
#include "drake/common/drake_throw.h"
#include "drake/common/filesystem.h"
#ifdef __APPLE__
#include <dlfcn.h>
#include <mach-o/dyld.h>
#include <mach-o/dyld_images.h>
#else // Not __APPLE__
#include <libgen.h> // dirname
#include <string.h>
#include <unistd.h>
#include <link.h>
#include <linux/limits.h> // PATH_MAX
#endif
using std::string;
namespace drake {
#ifdef __APPLE__
// This code has been adapted from:
// https://stackoverflow.com/questions/4309117/determining-programmatically-what-modules-are-loaded-in-another-process-os-x/23229148#23229148
namespace {
// Reads memory from MacOS specific structures into an `unsigned char*`.
unsigned char * ReadProcessMemory(mach_vm_address_t addr,
mach_msg_type_number_t* size) {
vm_offset_t readMem;
kern_return_t kr = vm_read(mach_task_self(), addr, *size,
&readMem, size);
if (kr != KERN_SUCCESS) {
return NULL;
}
return (reinterpret_cast<unsigned char *>(readMem));
}
} // namespace
// Gets the list of all the dynamic libraries that have been loaded. Finds
// `library_name` in the list, and returns its absolute directory path.
// This function is specific to MacOS
std::optional<string> LoadedLibraryPath(const string& library_name) {
task_dyld_info dyld_info;
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
// Getinformation from current process.
if (task_info(mach_task_self(), TASK_DYLD_INFO,
reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS) {
// Recover list of dynamic libraries.
mach_msg_type_number_t size = sizeof(dyld_all_image_infos);
unsigned char* data =
ReadProcessMemory(dyld_info.all_image_info_addr, &size);
if (!data) {
return std::nullopt;
}
dyld_all_image_infos* infos =
reinterpret_cast<dyld_all_image_infos *>(data);
// Recover number of dynamic libraries in list.
mach_msg_type_number_t size2 =
sizeof(dyld_image_info) * infos->infoArrayCount;
unsigned char* info_addr = ReadProcessMemory(
reinterpret_cast<mach_vm_address_t>(infos->infoArray), &size2);
if (!info_addr) {
return std::nullopt;
}
dyld_image_info* info =
reinterpret_cast<dyld_image_info*>(info_addr);
// Loop over the dynamic libraries until `library_name` is found.
for (uint32_t i=0; i < infos->infoArrayCount; i++) {
const char * pos_slash = strrchr(info[i].imageFilePath, '/');
if (!strcmp(pos_slash + 1, library_name.c_str())) {
// Path is always absolute on MacOS.
return string(info[i].imageFilePath,
pos_slash - info[i].imageFilePath);
}
}
}
return std::nullopt;
}
#else // Not __APPLE__
// Gets the list of all the shared objects that have been loaded. Finds
// `library_name` in the list, and returns its absolute directory path.
// This function is specific to Linux.
std::optional<string> LoadedLibraryPath(const std::string& library_name) {
void* handle = dlopen(NULL, RTLD_NOW);
link_map *map;
dlinfo(handle, RTLD_DI_LINKMAP, &map);
// Loop over loaded shared objects until `library_name` is found.
while (map) {
// Avoid using `basename()` and `dirname()` implemented in `libgen.h`
// because as stated in `libgen.h` documentation [1], both functions
// may modify the content of the input c-string (which happened in the
// original implementation and resulted in a bug).
// [1] http://man7.org/linux/man-pages/man3/basename.3.html#DESCRIPTION
const char* pos_slash = strrchr(map->l_name, '/');
if (pos_slash && !strcmp(pos_slash + 1, library_name.c_str())) {
// Check if path is relative. If so, make it absolute.
if (map->l_name[0] != '/') {
std::string argv0 = filesystem::read_symlink({
"/proc/self/exe"}).string();
return string(dirname(&argv0[0])) + "/" +
string(map->l_name, pos_slash - map->l_name);
} else {
return string(map->l_name, pos_slash - map->l_name);
}
}
map = map->l_next;
}
return std::nullopt;
}
#endif
} // namespace drake