Skip to content

[libc] add dl_iterate_phdr and dladdr #121179

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions libc/config/linux/aarch64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.ctype.toupper

# dlfcn.h entrypoints
libc.src.dlfcn.dladdr
libc.src.dlfcn.dlclose
libc.src.dlfcn.dlerror
libc.src.dlfcn.dlopen
libc.src.dlfcn.dlsym

# link.h entrypoints
libc.src.link.dl_iterate_phdr

# errno.h entrypoints
libc.src.errno.errno

Expand Down
10 changes: 9 additions & 1 deletion libc/hdrgen/yaml/dlfcn.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ macros:
macro_value: null
- macro_name: RTLD_LOCAL
macro_value: null
types: []
types:
- type_name: Dl_info
enums: []
objects: []
functions:
Expand Down Expand Up @@ -37,3 +38,10 @@ functions:
arguments:
- type: void *__restrict
- type: const char *__restrict
- name: dladdr
standards:
- GNUExtensions
return_type: int
arguments:
- type: const void *
- type: Dl_info *
13 changes: 11 additions & 2 deletions libc/hdrgen/yaml/link.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@ header: link.h
standards:
- Linux
macros: []
types: []
types:
- type_name: struct_dl_phdr_info
- type_name: __dl_iterate_phdr_callback_t
enums: []
objects: []
functions: []
functions:
- name: dl_iterate_phdr
standards:
- Linux
return_type: int
arguments:
- type: __dl_iterate_phdr_callback_t
- type: void *
3 changes: 3 additions & 0 deletions libc/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ add_header_macro(
dlfcn.h
DEPENDS
.llvm-libc-macros.dlfcn_macros
.llvm-libc-types.Dl_info
.llvm_libc_common_h
)

Expand Down Expand Up @@ -444,6 +445,8 @@ add_header_macro(
link.h
DEPENDS
.llvm_libc_common_h
.llvm-libc-types.__dl_iterate_phdr_callback_t
.llvm-libc-types.struct_dl_phdr_info
.llvm-libc-macros.link_macros
)

Expand Down
3 changes: 3 additions & 0 deletions libc/include/llvm-libc-types/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
add_header(Dl_info HDR Dl_info.h)
add_header(off64_t HDR off64_t.h)
add_header(size_t HDR size_t.h)
add_header(ssize_t HDR ssize_t.h)
Expand Down Expand Up @@ -67,6 +68,8 @@ else()
endif()
add_header(stack_t HDR stack_t.h DEPENDS .size_t)
add_header(suseconds_t HDR suseconds_t.h)
add_header(struct_dl_phdr_info HDR struct_dl_phdr_info.h DEPENDS .size_t libc.include.llvm-libc-macros.link_macros)
add_header(__dl_iterate_phdr_callback_t HDR __dl_iterate_phdr_callback_t.h DEPENDS .size_t .struct_dl_phdr_info)
add_header(struct_flock HDR struct_flock.h DEPENDS .off_t .pid_t)
add_header(struct_flock64 HDR struct_flock64.h DEPENDS .off64_t .pid_t)
add_header(struct_f_owner_ex HDR struct_f_owner_ex.h DEPENDS .pid_t)
Expand Down
19 changes: 19 additions & 0 deletions libc/include/llvm-libc-types/Dl_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//===-- Definition of Dl_info type ----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_TYPES_DL_INFO_H
#define LLVM_LIBC_TYPES_DL_INFO_H

typedef struct {
const char *dli_fname;
void *dli_fbase;
const char *dli_sname;
void *dli_saddr;
} Dl_info;

#endif // LLVM_LIBC_TYPES_DL_INFO_H
18 changes: 18 additions & 0 deletions libc/include/llvm-libc-types/__dl_iterate_phdr_callback_t.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Definition of type __dl_iterate_phdr_callback_t -------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_TYPES___DL_ITERATE_PHDR_CALLBACK_T_H
#define LLVM_LIBC_TYPES___DL_ITERATE_PHDR_CALLBACK_T_H

#include "size_t.h"
#include "struct_dl_phdr_info.h"

typedef int (*__dl_iterate_phdr_callback_t)(struct dl_phdr_info *, size_t,
void *);

#endif // LLVM_LIBC_TYPES___DL_ITERATE_PHDR_CALLBACK_T_H
26 changes: 26 additions & 0 deletions libc/include/llvm-libc-types/struct_dl_phdr_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===-- Definition of type struct dl_phdr_info ----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_TYPES_STRUCT_DL_PHDR_INFO_H
#define LLVM_LIBC_TYPES_STRUCT_DL_PHDR_INFO_H

#include "../llvm-libc-macros/link-macros.h"
#include "size_t.h"

struct dl_phdr_info {
ElfW(Addr) dlpi_addr;
const char *dlpi_name;
const ElfW(Phdr) * dlpi_phdr;
ElfW(Half) dlpi_phnum;
unsigned long long dlpi_adds;
unsigned long long dlpi_subs;
size_t dlpi_tls_modid;
void *dlpi_tls_data;
};

#endif // LLVM_LIBC_TYPES_STRUCT_DL_PHDR_INFO_H
1 change: 1 addition & 0 deletions libc/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ add_subdirectory(dlfcn)
add_subdirectory(errno)
add_subdirectory(fenv)
add_subdirectory(inttypes)
add_subdirectory(link)
add_subdirectory(math)
add_subdirectory(stdbit)
add_subdirectory(stdfix)
Expand Down
10 changes: 10 additions & 0 deletions libc/src/dlfcn/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
add_entrypoint_object(
dladdr
SRCS
dladdr.cpp
HDRS
dladdr.h
DEPENDS
libc.include.dlfcn
)

add_entrypoint_object(
dlclose
SRCS
Expand Down
18 changes: 18 additions & 0 deletions libc/src/dlfcn/dladdr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation of dladdr -----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "dladdr.h"

#include "src/__support/common.h"
#include "src/__support/macros/config.h"

namespace LIBC_NAMESPACE_DECL {

LLVM_LIBC_FUNCTION(int, dladdr, (const void *, Dl_info *)) { return -1; }

} // namespace LIBC_NAMESPACE_DECL
21 changes: 21 additions & 0 deletions libc/src/dlfcn/dladdr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===-- Implementation header of dladdr ------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_DLFCN_DLADDR_H
#define LLVM_LIBC_SRC_DLFCN_DLADDR_H

#include "include/llvm-libc-types/Dl_info.h"
#include "src/__support/macros/config.h"

namespace LIBC_NAMESPACE_DECL {

int dladdr(const void *, Dl_info *);

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC_DLFCN_DLADDR_H
10 changes: 10 additions & 0 deletions libc/src/link/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
endif()

add_entrypoint_object(
dl_iterate_phdr
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.dl_iterate_phdr
)
21 changes: 21 additions & 0 deletions libc/src/link/dl_iterate_phdr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===-- Implementation header for dl_iterate_phdr ---------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_LINK_DL_ITERATE_PHDR_H
#define LLVM_LIBC_SRC_LINK_DL_ITERATE_PHDR_H

#include "include/llvm-libc-types/__dl_iterate_phdr_callback_t.h"
#include "src/__support/macros/config.h"

namespace LIBC_NAMESPACE_DECL {

int dl_iterate_phdr(__dl_iterate_phdr_callback_t callback, void *data);

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC_STRING_MEMCHR_H
11 changes: 11 additions & 0 deletions libc/src/link/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
add_entrypoint_object(
dl_iterate_phdr
SRCS
dl_iterate_phdr.cpp
HDRS
../dl_iterate_phdr.h
DEPENDS
libc.include.llvm-libc-types.__dl_iterate_phdr_callback_t
libc.include.llvm-libc-types.struct_dl_phdr_info
libc.include.llvm-libc-types.size_t
)
59 changes: 59 additions & 0 deletions libc/src/link/linux/dl_iterate_phdr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//===-- Implementation of dl_iterate_phdr ---------------------------------===//
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that this PR was just to make libunwind work (per PR description), hence dladdr being a stub, but we have a real implementation here for dl_iterate_phdr?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's because dl_iterate_phdr is simple enough to implement. dladdr will require more stuff like dlopen, dlclose, and dlsym to be implemented. Currently, there's TODO's for @izaakschroeder to work on this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just found this #97928

//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/link/dl_iterate_phdr.h"
#include "config/linux/app.h"
#include "include/llvm-libc-macros/sys-auxv-macros.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"

[[gnu::weak,
gnu::visibility("hidden")]] extern const ElfW(Dyn) _DYNAMIC[]; // NOLINT

#define AUX_CNT 38

namespace LIBC_NAMESPACE_DECL {

LLVM_LIBC_FUNCTION(int, dl_iterate_phdr,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks a lot like musl's src/ldso/dl_iterate_phdr.c. If that's the case, please provide some attribution, and also mention it in the commit message.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simply mentioning it comes from musl isn't sufficient -- musl's COPYRIGHT file imposes very specific requirements, as does LLVM's own license file:

llvm-project/LICENSE.TXT

Lines 224 to 234 in 814902a

==============================================================================
Software from third parties included in the LLVM Project:
==============================================================================
The LLVM Project contains third party software which is under different license
terms. All such code will be identified clearly using at least one of two
mechanisms:
1) It will be in a separate directory tree with its own `LICENSE.txt` or
`LICENSE` file at the top containing the specific license and restrictions
which apply to that software, or
2) It will contain specific license and restriction terms at the top of every
file.

MIT has very few requirements but what it does require has not been satisfied by the most recent push.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fun, I've not really had to deal with licensing things like this before. I'm not sure what exactly to do.

Copy link
Member

@thesamesam thesamesam Dec 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please research the topic before making further PRs to (any) projects -- it's important that you understand licencing and using code derived from another project without honouring their licence. I don't think I can explain the whole topic in a succinct comment here but there's a lot of resources online about it.

If you've made any PRs up to now to any project where you looked at the sources of another project or copied its implementation, you may need to speak to their maintainers too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only time I've copied other implementations like this. I tried figuring out what dl_iterate_phdrs but I didn't really understand it from the man page. Is there a way that this implementation could be changed enough that it then doesn't have a licensing problem?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The legal threshold for changing something enough that it then doesn't have a licensing problem is:

don't base the code on something with a licensing problem, understand the problem you are trying to solve well enough to write a clean-room implementation by hand, yourself, from scratch, without the aid of another implementation

But like I said, llvm's own LICENSE.TXT and musl's COPYRIGHT provide guidance on how to respect the license for a copy-pasted work (as long as the the terms of each license don't pose an onerous burden that the other license cannot abide by).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how that works. Musl is MIT, LLVM is Apache. I've tried reading the licenses but I don't understand them.

(__dl_iterate_phdr_callback_t callback, void *data)) {
// dl_iterate_phdr implementation based on Musl source
// "src/ldso/dl_iterate_phdr.c"
size_t *auxv_ptr = reinterpret_cast<size_t *>(app.auxv_ptr);
size_t aux[AUX_CNT] = {0};

for (size_t i = 0; auxv_ptr[i]; i += 2) {
if (auxv_ptr[i] < AUX_CNT) {
aux[auxv_ptr[i]] = auxv_ptr[i + 1];
}
}

void *p;
size_t n;
size_t base = 0;
for (p = (void *)aux[AT_PHDR], n = aux[AT_PHNUM]; n;
n--, p = reinterpret_cast<void *>((uintptr_t)p + aux[AT_PHENT])) {
ElfW(Phdr) *phdr = (ElfW(Phdr) *)p;
if (phdr->p_type == PT_PHDR)
base = aux[AT_PHDR] - phdr->p_vaddr;
if (phdr->p_type == PT_DYNAMIC && _DYNAMIC)
base = (size_t)_DYNAMIC - phdr->p_vaddr;
}

struct dl_phdr_info info;
info.dlpi_addr = base;
info.dlpi_name = "/proc/self/exe";
info.dlpi_phdr = (const ElfW(Phdr) *)aux[AT_PHDR];
info.dlpi_phnum = (ElfW(Half))aux[AT_PHNUM];
info.dlpi_adds = 0;
info.dlpi_subs = 0;
info.dlpi_tls_modid = 0;
info.dlpi_tls_data = 0;
return callback(&info, sizeof(struct dl_phdr_info), data);
}

} // namespace LIBC_NAMESPACE_DECL
Loading