Skip to content

Commit

Permalink
Add xdl_info().
Browse files Browse the repository at this point in the history
  • Loading branch information
caikelun committed Nov 9, 2022
1 parent 6ef0f9f commit 0e09289
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 34 deletions.
25 changes: 19 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

![](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)
![](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)
![](https://img.shields.io/badge/release-1.1.5-red.svg?style=flat)
![](https://img.shields.io/badge/release-1.2.0-red.svg?style=flat)
![](https://img.shields.io/badge/Android-4.1%20--%2013-blue.svg?style=flat)
![](https://img.shields.io/badge/arch-armeabi--v7a%20%7C%20arm64--v8a%20%7C%20x86%20%7C%20x86__64-blue.svg?style=flat)

Expand Down Expand Up @@ -61,7 +61,7 @@ android {
}
dependencies {
implementation 'io.hexhacking:xdl:1.1.5'
implementation 'io.hexhacking:xdl:1.2.0'
}
```

Expand Down Expand Up @@ -202,21 +202,21 @@ typedef struct
size_t dli_ssize;
const ElfW(Phdr) *dlpi_phdr;
size_t dlpi_phnum;
} xdl_info;
} xdl_info_t;

int xdl_addr(void *addr, xdl_info *info, void **cache);
int xdl_addr(void *addr, xdl_info_t *info, void **cache);
void xdl_addr_clean(void **cache);
```
`xdl_addr()` is similar to [`dladdr()`](https://man7.org/linux/man-pages/man3/dladdr.3.html). But there are a few differences:
* `xdl_addr()` can lookup not only dynamic link symbols, but also debugging symbols.
* `xdl_addr()` uses the `xdl_info` structure instead of the `Dl_info` structure, which contains more extended information: `dli_ssize` is the number of bytes occupied by the current symbol; `dlpi_phdr` points to the program headers array of the ELF where the current symbol is located; `dlpi_phnum` is the number of elements in the `dlpi_phdr` array.
* `xdl_addr()` uses the `xdl_info_t` structure instead of the `Dl_info` structure, which contains more extended information: `dli_ssize` is the number of bytes occupied by the current symbol; `dlpi_phdr` points to the program headers array of the ELF where the current symbol is located; `dlpi_phnum` is the number of elements in the `dlpi_phdr` array.
* `xdl_addr()` needs to pass an additional parameter (`cache`), which will cache the ELF handle opened during the execution of `xdl_addr()`. The purpose of caching is to make subsequent executions of `xdl_addr()` of the same ELF faster. When you do not need to execute `xdl_addr()`, please use `xdl_addr_clean()` to clear the cache. For example:
```C
void *cache = NULL;
xdl_info info;
xdl_info_t info;
xdl_addr(addr_1, &info, &cache);
xdl_addr(addr_2, &info, &cache);
xdl_addr(addr_3, &info, &cache);
Expand All @@ -241,6 +241,19 @@ int xdl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), voi
These flags are needed because these capabilities require additional execution time, and you don't always need them.
### 5. `xdl_info()`
```C
#define XDL_DI_DLINFO 1 // type of info: xdl_info_t
int xdl_info(void *handle, int request, void *info);
```

`xdl_info()` is similar to [`dlinfo()`](https://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html). `xdl_info()` obtains information about the dynamically loaded object referred to by `handle` (obtained by an earlier call to `xdl_open`).

The only `request` parameter currently supported is `XDL_DI_DLINFO`, which means to return data of type `xdl_info_t` through the `info` parameter (note that the values of `dli_sname`, `dli_saddr`, `dli_ssize` in the returned `xdl_info_t` at this time both are `0`).

On success, `xdl_info()` returns `0`. On failure, it returns `-1`.

## Support

Expand Down
33 changes: 23 additions & 10 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

![](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)
![](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)
![](https://img.shields.io/badge/release-1.1.5-red.svg?style=flat)
![](https://img.shields.io/badge/release-1.2.0-red.svg?style=flat)
![](https://img.shields.io/badge/Android-4.1%20--%2013-blue.svg?style=flat)
![](https://img.shields.io/badge/arch-armeabi--v7a%20%7C%20arm64--v8a%20%7C%20x86%20%7C%20x86__64-blue.svg?style=flat)

Expand Down Expand Up @@ -61,7 +61,7 @@ android {
}
dependencies {
implementation 'io.hexhacking:xdl:1.1.5'
implementation 'io.hexhacking:xdl:1.2.0'
}
```

Expand Down Expand Up @@ -142,7 +142,7 @@ void *xdl_open(const char *filename, int flags);
void *xdl_close(void *handle);
```
它们和 [`dlopen()`](https://man7.org/linux/man-pages/man3/dlopen.3.html) / [`dlclose()`](https://man7.org/linux/man-pages/man3/dlclose.3.html) 很相似。但是 `xdl_open()` 可以绕过 Android 7.0+ linker namespace 的限制。
它们和 [`dlopen()`](https://man7.org/linux/man-pages/man3/dlopen.3.html) / [`dlclose()`](https://man7.org/linux/man-pages/man3/dlclose.3.html) 类似。但是 `xdl_open()` 可以绕过 Android 7.0+ linker namespace 的限制。
根据 `flags` 参数值的不同,`xdl_open()` 的行为会有一些差异:
Expand Down Expand Up @@ -176,7 +176,7 @@ void *xdl_sym(void *handle, const char *symbol, size_t *symbol_size);
void *xdl_dsym(void *handle, const char *symbol, size_t *symbol_size);
```

它们和 [`dlsym()`](https://man7.org/linux/man-pages/man3/dlsym.3.html) 很相似。 它们都需要传递一个 `xdl_open()` 返回的 “handle”,和一个 null 结尾的符号名字,返回该符号在内存中的加载地址。
它们和 [`dlsym()`](https://man7.org/linux/man-pages/man3/dlsym.3.html) 类似。 它们都需要传递一个 `xdl_open()` 返回的 “handle”,和一个 null 结尾的符号名字,返回该符号在内存中的加载地址。

如果 `symbol_size` 参数不为 `NULL`,它将被赋值为“符号对应的内容在 ELF 中占用的字节数”,如果你不需要这个信息,传递 `NULL` 就可以了。

Expand All @@ -202,21 +202,21 @@ typedef struct
size_t dli_ssize;
const ElfW(Phdr) *dlpi_phdr;
size_t dlpi_phnum;
} xdl_info;
} xdl_info_t;

int xdl_addr(void *addr, xdl_info *info, void **cache);
int xdl_addr(void *addr, xdl_info_t *info, void **cache);
void xdl_addr_clean(void **cache);
```
`xdl_addr()` 和 [`dladdr()`](https://man7.org/linux/man-pages/man3/dladdr.3.html) 很相似。但有以下几点不同:
`xdl_addr()` 和 [`dladdr()`](https://man7.org/linux/man-pages/man3/dladdr.3.html) 类似。但有以下几点不同:
* `xdl_addr()` 不仅能查询动态链接符号,还能查询调试符号。
* `xdl_addr()` 使用 `dl_info` 结构体代替了 `Dl_info` 结构体,它包含了更多的扩展信息:`dli_ssize` 是当前符号所占用的字节数;`dlpi_phdr` 指向当前符号所在 ELF 的 program headers 数组;`dlpi_phnum` 是 `dlpi_phdr` 数组的元素个数。
* `xdl_addr()` 使用 `xdl_info_t` 结构体代替了 `Dl_info` 结构体,它包含了更多的扩展信息:`dli_ssize` 是当前符号所占用的字节数;`dlpi_phdr` 指向当前符号所在 ELF 的 program headers 数组;`dlpi_phnum` 是 `dlpi_phdr` 数组的元素个数。
* `xdl_addr()` 需要传递一个附加的参数(cache),其中会缓存 `xdl_addr()` 执行过程中打开的 ELF handle,缓存的目的是使后续对同一个 ELF 的 `xdl_addr()` 执行的更快。当不需要再执行 `xdl_addr()` 时,请使用 `xdl_addr_clean()` 清除缓存。举例:
```C
void *cache = NULL;
Dl_info info;
xdl_info_t info;
xdl_addr(addr_1, &info, &cache);
xdl_addr(addr_2, &info, &cache);
xdl_addr(addr_3, &info, &cache);
Expand All @@ -232,7 +232,7 @@ xdl_addr_clean(&cache);
int xdl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), void *data, int flags);
```
`xdl_iterate_phdr()` 和 [`dl_iterate_phdr()`](https://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html) 很相似。但是 `xdl_iterate_phdr()` 兼容 ARM32 平台的 Android 4.x 系统,并且总是包含 linker / linker64。
`xdl_iterate_phdr()` 和 [`dl_iterate_phdr()`](https://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html) 类似。但是 `xdl_iterate_phdr()` 兼容 ARM32 平台的 Android 4.x 系统,并且总是包含 linker / linker64。
`xdl_iterate_phdr()` 有一个额外的“flags”参数,一个或多个“flag”可以按位“或”后传递给它:
Expand All @@ -241,6 +241,19 @@ int xdl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), voi
需要这些 flags 的原因是,这些额外的能力也需要花费额外的执行时间,而你并不总是需要这些能力。
### 5. `xdl_info()`
```C
#define XDL_DI_DLINFO 1 // type of info: xdl_info_t
int xdl_info(void *handle, int request, void *info);
```

`xdl_info()`[`dlinfo()`](https://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html) 类似。`xdl_info()` 通过 `handle``xdl_open` 的返回值)来获取动态加载对象的信息。

目前唯一支持的 `request` 参数是 `XDL_DI_DLINFO`,表示通过 `info` 参数返回 `xdl_info_t` 类型的数据(注意,此时返回的 `xdl_info_t``dli_sname``dli_saddr``dli_ssize` 的值均为 `0`)。

成功时 `xdl_info()` 返回 `0`,失败时返回 `-1`

## 技术支持

Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ ext {

POM_GROUP_ID = "io.hexhacking"
POM_ARTIFACT_ID = "xdl"
POM_VERSION_NAME = "1.1.5"
POM_VERSION_NAME = "1.2.0"

POM_NAME = "xDL Android Lib"
POM_DESCRIPTION = "xDL is an enhanced implementation of the Android DL series functions."
Expand Down
33 changes: 20 additions & 13 deletions xdl/src/main/cpp/include/xdl.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
// Created by caikelun on 2020-10-04.

//
// xDL version: 1.1.5
// xDL version: 1.2.0
//
// xDL is an enhanced implementation of the Android DL series functions.
// For more information, documentation, and the latest version please check:
Expand All @@ -40,6 +40,18 @@
extern "C" {
#endif

typedef struct {
// same as Dl_info:
const char *dli_fname; // Pathname of shared object that contains address.
void *dli_fbase; // Address at which shared object is loaded.
const char *dli_sname; // Name of nearest symbol with address lower than addr.
void *dli_saddr; // Exact address of symbol named in dli_sname.
// added by xDL:
size_t dli_ssize; // Symbol size of nearest symbol with address lower than addr.
const ElfW(Phdr) *dlpi_phdr; // Pointer to array of ELF program headers for this object.
size_t dlpi_phnum; // Number of items in dlpi_phdr.
} xdl_info_t;

//
// Default value for flags in both xdl_open() and xdl_iterate_phdr().
//
Expand All @@ -58,18 +70,7 @@ void *xdl_dsym(void *handle, const char *symbol, size_t *symbol_size);
//
// Enhanced dladdr().
//
typedef struct {
// same as Dl_info:
const char *dli_fname; // Pathname of shared object that contains address.
void *dli_fbase; // Address at which shared object is loaded.
const char *dli_sname; // Name of nearest symbol with address lower than addr.
void *dli_saddr; // Exact address of symbol named in dli_sname.
// added by xDL:
size_t dli_ssize; // Symbol size of nearest symbol with address lower than addr.
const ElfW(Phdr) *dlpi_phdr; // Pointer to array of ELF program headers for this object.
size_t dlpi_phnum; // Number of items in dlpi_phdr.
} xdl_info;
int xdl_addr(void *addr, xdl_info *info, void **cache);
int xdl_addr(void *addr, xdl_info_t *info, void **cache);
void xdl_addr_clean(void **cache);

//
Expand All @@ -78,6 +79,12 @@ void xdl_addr_clean(void **cache);
#define XDL_FULL_PATHNAME 0x01
int xdl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), void *data, int flags);

//
// Custom dlinfo().
//
#define XDL_DI_DLINFO 1 // type of info: xdl_info_t
int xdl_info(void *handle, int request, void *info);

#ifdef __cplusplus
}
#endif
Expand Down
18 changes: 17 additions & 1 deletion xdl/src/main/cpp/xdl.c
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,7 @@ static ElfW(Sym) *xdl_dsym_by_addr(void *handle, void *addr) {
return NULL;
}

int xdl_addr(void *addr, xdl_info *info, void **cache) {
int xdl_addr(void *addr, xdl_info_t *info, void **cache) {
if (NULL == addr || NULL == info || NULL == cache) return 0;

memset(info, 0, sizeof(Dl_info));
Expand Down Expand Up @@ -851,3 +851,19 @@ int xdl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), voi

return xdl_iterate_phdr_impl(callback, data, flags);
}

int xdl_info(void *handle, int request, void *info) {
if (NULL == handle || XDL_DI_DLINFO != request || NULL == info) return -1;

xdl_t *self = (xdl_t *)handle;
xdl_info_t *dlinfo = (xdl_info_t *)info;

dlinfo->dli_fbase = (void *)self->load_bias;
dlinfo->dli_fname = self->pathname;
dlinfo->dli_sname = NULL;
dlinfo->dli_saddr = 0;
dlinfo->dli_ssize = 0;
dlinfo->dlpi_phdr = self->dlpi_phdr;
dlinfo->dlpi_phnum = (size_t)self->dlpi_phnum;
return 0;
}
1 change: 1 addition & 0 deletions xdl/src/main/cpp/xdl.map.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
xdl_addr;
xdl_addr_clean;
xdl_iterate_phdr;
xdl_info;

local:
*;
Expand Down
2 changes: 1 addition & 1 deletion xdl_sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ dependencies {
if (rootProject.ext.dependencyOnLocalLibrary) {
implementation project(':xdl')
} else {
implementation 'io.hexhacking:xdl:1.1.5'
implementation 'io.hexhacking:xdl:1.2.0'
}
}

Expand Down
13 changes: 11 additions & 2 deletions xdl_sample/src/main/cpp/sample.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,27 @@ static void sample_test_iterate(void) {

static void *sample_test_dlsym(const char *filename, const char *symbol, bool debug_symbol, void **cache,
bool try_force_dlopen) {
xdl_info_t info;

if (try_force_dlopen) {
void *linker_handle = dlopen(filename, RTLD_NOW);
LOG("--- dlopen(%s) : handle %" PRIxPTR, filename, (uintptr_t)linker_handle);
if (NULL != linker_handle) dlclose(linker_handle);
}

LOG("+++ xdl_open + %s + xdl_addr", debug_symbol ? "xdl_dsym" : "xdl_sym");
LOG("+++ xdl_open + xdl_info + %s + xdl_addr", debug_symbol ? "xdl_dsym" : "xdl_sym");

// xdl_open
void *handle = xdl_open(filename, try_force_dlopen ? XDL_TRY_FORCE_LOAD : XDL_DEFAULT);
LOG(">>> xdl_open(%s) : handle %" PRIxPTR, filename, (uintptr_t)handle);

// xdl_info
memset(&info, 0, sizeof(xdl_info_t));
xdl_info(handle, XDL_DI_DLINFO, &info);
LOG(">>> xdl_info(%" PRIxPTR ") : %" PRIxPTR " %s (phdr %" PRIxPTR ", phnum %zu)", (uintptr_t)handle,
(uintptr_t)info.dli_fbase, (NULL == info.dli_fname ? "(NULL)" : info.dli_fname),
(uintptr_t)info.dlpi_phdr, info.dlpi_phnum);

// xdl_dsym / xdl_sym
size_t symbol_size = 0;
void *symbol_addr = (debug_symbol ? xdl_dsym : xdl_sym)(handle, symbol, &symbol_size);
Expand All @@ -87,7 +96,7 @@ static void *sample_test_dlsym(const char *filename, const char *symbol, bool de
void *linker_handle = xdl_close(handle);

// xdl_addr
xdl_info info;
memset(&info, 0, sizeof(xdl_info_t));
if (0 == xdl_addr(symbol_addr, &info, cache))
LOG(">>> xdl_addr(%" PRIxPTR ") : FAILED", (uintptr_t)symbol_addr);
else
Expand Down

0 comments on commit 0e09289

Please sign in to comment.