Austin Group Defect Tracker

Aardvark Mark IV


Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0000993 [1003.1(2008)/Issue 7] Base Definitions and Headers Editorial Clarification Requested 2015-10-18 10:22 2020-09-07 09:06
Reporter EdSchouten View Status public  
Assigned To ajosey
Priority normal Resolution Open  
Status Under Review  
Name Ed Schouten
Organization Nuxi
User Reference
Section dlfcn.h
Page Number n/a
Line Number n/a
Interp Status ---
Final Accepted Text
Summary 0000993: Standardizing dladdr()
Description Though POSIX already standardizes the <dlfcn.h> functions to load shared libraries at runtime, it does not standardize the dladdr() function. My observation is that this function is used in a couple of important places, to generate backtraces or to improve error messages. It seems to be implemented universally as far as I know, always using the same prototype:

typedef struct {
  const char *dli_fname; // Pathname of shared object.
  void *dli_fbase; // Base address of shared object.
  const char *dli_sname; // Name of nearest symbol.
  void *dli_saddr; // Address of nearest symbol.
} Dl_info;

int dladdr(const void *, Dl_info *);
Desired Action Due to its universal adoption, would it make sense to standardize it?
Tags No tags attached.
Attached Files

- Relationships

-  Notes
(0002882)
wahern (reporter)
2015-11-04 20:01

It's missing completely on AIX.

I've only ever used the dli_fname member (from modules which attempt to reopen and pin themselves in memory). FWIW, that at least appears to work the same from FreeBSD, Linux/glibc, Linux/musl, NetBSD, OpenBSD, OS X, and Solaris.
(0002883)
shware_systems (reporter)
2015-11-05 14:00

Also FWIW, while a function like this may make writing a generic debugger easier, as a legitimate purpose, its primary use in an application that I can see would be for reverse engineering a module that's been obfuscated and as such it constitutes a security hole. If it were to be included in the standard as a formalization of common practice I would hope it be as part of an option group, not a candidate for the base set of interfaces, and visible only when NDEBUG is defined similar to the assert macros.
(0002886)
EdSchouten (updater)
2015-11-05 18:17

I'm not sure I agree with this reasoning. The information that is returned by dladdr() is in many cases already public knowledge.

- You can also extract this information outside of the process using the nm(1) utility.
- Even if your system does not provide this function, but does provide the dl_iterate_phdr() function (present on many systems that use ELF), you can just search for the .dynsym section and parse the symbol entries manually.
(0002891)
dalias (reporter)
2015-11-06 16:33

In regard to comment 2883, the only security model in the standard is the user/group system. While additional security models are permitted (see "appropriate privileges" etc.), anything "DRM-like" is not a security measure by any stretch of the word and there is no precedent for attempting to offer such snake oil. However the whole issue is irrelevant to dladdr. An implementation wanting to attempt such futile measures could simply have dladdr fail for such modules. (Then, the user need only patch the module to make it start working again, or implement their own unencumbered but nonportable dladdr that only works on the particular implementation they need it on.)

In regard to comment 2886, dl_iterate_phdr is also not provided in the standard and thus not a substitute for dladdr. Even if it were provided, however, there are implementations in which dl_iterate_phdr does not provide sufficient information to implement dladdr on top of it. In particular, for any implementation using function descriptors that are dynamically allocated (ELF/FDPIC ABIs), the headers lack sufficient information to determine the identity of a function pointer; additional runtime state known only to the dynamic linker is needed.
(0003236)
nico (reporter)
2016-05-27 16:07

dladdr() is extremely useful, and no, nm(1) and other such tools don't help.

Suppose that you have a library for parsing configuration files where you want to open a configuration file by relative path -- relative to the *caller*'s object. First, you need the return address (and since there's no portable way to get, an address given by the caller). Next you call dladdr(), obtain the caller's object (or executable) path, and now you can find the absolute path given that configuration file relative path. There is no portable way to do this without dladdr() or similar because the caller may not know its path due to its being intended to be relocatable!

Making applications relocatable (that is, not tied to an absolute install path) is difficult. dladdr(), along with $ORIGIN, helps a lot.

POSIX should provide more interfaces to make it possible to write relocatable code.

There are other uses of dladdr(), naturally. Reflection/introspection, for example, especially in codebases that pass around function pointer tables obtained or filled with dlsym() on objects loaded with dlopen() -- this is a case where the information is available in other ways, but where arranging to make that available conveniently may not be easy without much refactoring.

I can probably think of other uses of dladdr(). Making relocation easier seems quite compelling to me.
(0003237)
nico (reporter)
2016-05-27 16:13

The hoops that we jump through to make code relocatable! Anyone who has had to use libtool has some idea (e.g., abuse LD_LIBRARY_PATH in order to run built-but-not-yet-installed artifacts). There is also Conda (which binary-edits install paths in build artifacts at install time). There are libraries to help find files by path relative to the application's install path (which can generally be determined via getauxval() or, failing that, main()'s argv[0]), but doing so relative to *objects* (as opposed to the executable) really does require dladdr().
(0003300)
Don Cragun (manager)
2016-07-21 15:23

We will ask The Open Group if they would like to sponsor this additional interface.

In the future, it would be nice if requests like this included text to be included in the standard, rather than hoping a sponsor organization will not only approve the suggestion but also take the additional effort to create all of the needed documentation.
(0004974)
geoffclare (manager)
2020-09-07 09:06
edited on: 2020-09-07 09:14

Suggested changes to go into The Open Group company review...

Page and line numbers are for the 2016/2018 edition.

On page 233 line 7838 section <dlfcn.h>, add:
The <dlfcn.h> header shall define the Dl_info_t structure type, which shall include at least the following members:
const char *dli_fname  Pathname of mapped object file.
void       *dli_fbase  Base of mapped address range.
const char *dli_sname  Symbol name or null pointer.
void       *dli_saddr  Symbol address or null pointer. 

On page 233 line 7848 section <dlfcn.h>, insert:
int dladdr(const void *restrict, Dl_info_t *restrict);

On page 233 line 7859 section <dlfcn.h>, add dladdr() to SEE ALSO.

On page 475 line 16317 section 2.2.2 The Name Space, change:
RTLD_
to:
RTLD_, dli_

On page 2053 insert a new dladdr page:

NAME
dladdr -- get information relating to an address

SYNOPSIS
#include <dlfcn.h>

int dladdr(const void *restrict addr, Dl_info_t *restrict dlip);

DESCRIPTION
The dladdr() function shall determine whether the address specified by addr is located within the address range occupied by a mapped object. The mapped objects examined shall include any executable object files that have previously been loaded by a call to dlopen() and for which dlclose() has not subsequently been called, and any shared library files that were loaded as dependencies of the executable file from which the current process image was loaded; they may also include any executable object files that have previously been loaded by a call to dlopen() and for which dlclose() has subsequently been called, the executable file from which the current process image was loaded, and implementation-defined additional mapped objects (for example, all regular files mapped using mmap() might be included). If the specified address is within the mapped address range of one of these mapped objects and the object contains a symbol table, the symbol table shall be searched for a symbol (a function identifier or a data object identifier) that has the largest address less than or equal to the specified address.

If the address specified by addr is within the mapped address range of one of the examined mapped objects, the structure pointed to by dlip shall be populated as follows:
  • The value of the dli_fname member shall be set to point to the pathname of the mapped object. (This might no longer resolve to the file that was mapped, for example if it was a link that has subsequently been removed or renamed.)
  • The value of the dli_fbase member shall be set to the base of the address range occupied by the mapped object.
  • The value of the dli_sname member shall be set to point to the name of the symbol that has the largest address less than or equal to the specified address, or to a null pointer if no such symbol was found.
  • If dli_sname is set to a null pointer, the value of the dli_saddr member shall also be set to a null pointer. Otherwise, if dli_sname names a function identifier, dli_saddr shall bet set to the address of the function converted from type pointer to function to type pointer to void; otherwise, dli_saddr shall be set to the address of the data object named by dli_sname converted from a pointer to the type of the data object to a pointer to void.

RETURN VALUE
Upon successful completion, a non-zero value shall be returned. If the specified address is not located within the address range occupied by an examined mapped object, or if an error occurs, zero shall be returned. More detailed diagnostic information shall be available through dlerror().

ERRORS
No errors are defined.

EXAMPLES
None.

APPLICATION USAGE
The Dl_info_t members may point to addresses within the mapped object. These pointers can become invalid if the object is unmapped (for example, loaded executable objects may be unloaded by dlclose()).

If dli_sname names a function identifier, the value of dli_saddr can be converted back to type pointer to function using a cast in the manner shown in the dlsym() EXAMPLES section. Note that this conversion is not defined by the ISO C standard. This standard requires this conversion to work correctly on conforming implementations.

RATIONALE
None.

FUTURE DIRECTIONS
None.

SEE ALSO
dlclose(), dlerror(), dlopen(), dlsym()

XBD <dlfcn.h>

CHANGE HISTORY
First released in Issue 8.

Add dladdr() to the SEE ALSO section for each function page listed in the dladdr() SEE ALSO above.

On page 3791 line 130067 section E.1, add dladdr() to the POSIX_DYNAMIC_LINKING subprofile group.


- Issue History
Date Modified Username Field Change
2015-10-18 10:22 EdSchouten New Issue
2015-10-18 10:22 EdSchouten Status New => Under Review
2015-10-18 10:22 EdSchouten Assigned To => ajosey
2015-10-18 10:22 EdSchouten Name => Ed Schouten
2015-10-18 10:22 EdSchouten Organization => Nuxi
2015-10-18 10:22 EdSchouten Section => dlfcn.h
2015-10-18 10:22 EdSchouten Page Number => n/a
2015-10-18 10:22 EdSchouten Line Number => n/a
2015-11-04 20:01 wahern Note Added: 0002882
2015-11-05 14:00 shware_systems Note Added: 0002883
2015-11-05 18:17 EdSchouten Note Added: 0002886
2015-11-06 16:33 dalias Note Added: 0002891
2016-05-27 16:07 nico Note Added: 0003236
2016-05-27 16:13 nico Note Added: 0003237
2016-07-21 15:23 Don Cragun Note Added: 0003300
2016-09-14 14:24 emaste Issue Monitored: emaste
2020-09-07 09:06 geoffclare Note Added: 0004974
2020-09-07 09:07 geoffclare Note Edited: 0004974
2020-09-07 09:14 geoffclare Note Edited: 0004974


Mantis 1.1.6[^]
Copyright © 2000 - 2008 Mantis Group
Powered by Mantis Bugtracker