- pi_skip_method
Identifies how the procedure linkage table entry can be traversed. It will be set to one of the rd_skip_e values.
- pi_nstep
Identifies how many instructions to step over when RD_RESOLVE_STEP or RD_RESOLVE_TARGET_STEP are returned.
- pi_target
Specifies the address at which to set a breakpoint when RD_RESOLVE_TARGET_STEP or RD_RESOLVE_TARGET are returned.
- pi_baddr
The procedure linkage table destination address, added with RD_VERSION3. When the RD_FLG_PI_PLTBOUND flag of the pi_flags field is set, this element identifies the resolved (bound) destination address.
- pi_flags
A flags field, added with RD_VERSION3. The flag RD_FLG_PI_PLTBOUND identifies the procedure linkage entry as having been resolved (bound) to its destination address, which is available in the pi_baddr field.
The following scenarios are possible from the rd_plt_info_t return values:
The first call through this procedure linkage table must be resolved by the runtime linker. In this case, the rd_plt_info_t will contain:
{RD_RESOLVE_TARGET_STEP, M, <BREAK>, 0, 0}
The controlling process sets a breakpoint at BREAK and continues the target process. When the breakpoint is reached, the procedure linkage table entry processing has finished. The controlling process can then step M instructions to the destination function. Notice that the bound address (pi_baddr) has not been set since this is the first call through a procedure linkage table entry.
On the Nth time through this procedure linkage table, rd_plt_info_t will contain:
{RD_RESOLVE_STEP, M, 0, <BoundAddr>, RD_FLG_PI_PLTBOUND}
The procedure linkage table entry has already been resolved and the controlling process can step M instructions to the destination function. The address that the procedure linkage table entry is bound to is <BoundAddr> and the RD_FLG_PI_PLTBOUND bit has been set in the flags field.
Dynamic Object Padding
The default behavior of the runtime linker relies on the operating system to load dynamic objects where they can be most efficiently referenced. Some controlling processes benefit from the existence of padding around the objects loaded into memory of the target process. This interface enables a controlling process to request this padding.
- rd_objpad_enable()
This function enables or disables the padding of any subsequently loaded objects with the target process. Padding occurs on both sides of the loaded object.
rd_err_e rd_objpad_enable(struct rd_agent * rdap, size_t padsize);
padsize specifies the size of the padding, in bytes, to be preserved both before and after any objects loaded into memory. This padding is reserved as a memory mapping using mmap(2) with PROT_NONE permissions and the MAP_NORESERVE flag. Effectively, the runtime linker reserves areas of the virtual address space of the target process adjacent to any loaded objects. These areas can later be utilized by the controlling process.
A padsize of 0 disables any object padding for later objects.
Note - Reservations obtained using mmap(2) from /dev/zero with MAP_NORESERVE can be reported using the proc(1) facilities and by referring to the link-map information provided in rd_loadobj_t.
Debugger Import Interface
The imported interface that a controlling process must provide to librtld_db.so.1 is defined in /usr/include/proc_service.h. A sample implementation of these proc_service functions can be found in the rdb demonstration debugger. The rtld-debugger interface uses only a subset of the proc_service interfaces available. Future versions of the rtld-debugger interface might take advantage of additional proc_service interfaces without creating an incompatible change.
The following interfaces are currently being used by the rtld-debugger interface:
- ps_pauxv()
This function returns a pointer to a copy of the auxv vector.
ps_err_e ps_pauxv(const struct ps_prochandle * ph, auxv_t ** aux);
Because the auxv vector information is copied to an allocated structure, the pointer remains as long as the ps_prochandle is valid.
- ps_pread()
This function reads data from the target process.
ps_err_e ps_pread(const struct ps_prochandle * ph, paddr_t addr, char * buf, int size);
From address addr in the target process, size bytes are copied to buf.
- ps_pwrite()
This function writes data to the target process.
ps_err_e ps_pwrite(const struct ps_prochandle * ph, paddr_t addr, char * buf, int size);
size bytes from buf are copied into the target process at address addr.
- ps_plog()
This function is called with additional diagnostic information from the rtld-debugger interface.
void ps_plog(const char * fmt, ...);
The controlling process determines where, or if, to log this diagnostic information. The arguments to ps_plog() follow the printf(3C) format.
- ps_pglobal_lookup()
This function searches for the symbol in the target process.
ps_err_e ps_pglobal_lookup(const struct ps_prochandle * ph, const char * obj, const char * name, ulong_t * sym_addr);
The symbol named name is searched for within the object named obj within the target process ph. If the symbol is found, the symbol address is stored in sym_addr.
- ps_pglobal_sym()
This function searches for the symbol in the target process.
ps_err_e ps_pglobal_sym(const struct ps_prochandle * ph, const char * obj, const char * name, ps_sym_t * sym_desc);
The symbol named name is searched for within the object named obj within the target process ph. If the symbol is found, the symbol descriptor is stored in sym_desc.
In the event that the rtld-debugger interface needs to find symbols within the application or runtime linker prior to any link-map creation, the following reserved values for obj are available:
#define PS_OBJ_EXEC ((const char *)0x0) /* application id */ #define PS_OBJ_LDSO ((const char *)0x1) /* runtime linker id */ |
The controlling process can use the procfs file system for these objects, using the following pseudo code:
ioctl(.., PIOCNAUXV, ...) - obtain AUX vectors ldsoaddr = auxv[AT_BASE]; ldsofd = ioctl(..., PIOCOPENM, &ldsoaddr); /* process elf information found in ldsofd ... */ execfd = ioctl(.., PIOCOPENM, 0); /* process elf information found in execfd ... */ |
Once the file descriptors are found, the ELF files can be examined for their symbol information by the controlling program.