Event Notification
A controlling process can track certain events that occur within the scope of the runtime linker that. These events are:
- RD_PREINIT
The runtime linker has loaded and relocated all the dynamic objects and is about to start calling the .init sections of each object loaded.
- RD_POSTINIT
The runtime linker has finished calling all of the .init sections and is about to transfer control to the primary executable.
- RD_DLACTIVITY
The runtime linker has been invoked to either load or unload a dynamic object.
These events can be monitored using the following interface, defined in sys/link.h and rtld_db.h:
typedef enum { RD_NONE = 0, RD_PREINIT, RD_POSTINIT, RD_DLACTIVITY } rd_event_e; /* * Ways that the event notification can take place: */ typedef enum { RD_NOTIFY_BPT, RD_NOTIFY_AUTOBPT, RD_NOTIFY_SYSCALL } rd_notify_e; /* * Information on ways that the event notification can take place: */ typedef struct rd_notify { rd_notify_e type; union { psaddr_t bptaddr; long syscallno; } u; } rd_notify_t; |
The following functions track events:
- rd_event_enable()
This function enables (1) or disables (0) event monitoring.
rd_err_e rd_event_enable(struct rd_agent * rdap, int onoff);
Note - Presently, for performance reasons, the runtime linker ignores event disabling. The controlling process should not assume that a given break-point will not be reached because of the last call to this routine.
- rd_event_addr()
This function specifies how the controlling program will be notified of a given event.
rd_err_e rd_event_addr(rd_agent_t * rdap, rd_event_e event, rd_notify_t * notify);
Depending on the event type, the notification of the controlling process will take place by calling a benign, cheap system call that is identified by notify->u.syscallno, or executing a break point at the address specified by notify->u.bptaddr. The controlling process is responsible for tracing the system call or place the actual break-point.
When an event has occurred, additional information can be obtained by this interface, defined in rtld_db.h:
typedef enum { RD_NOSTATE = 0, RD_CONSISTENT, RD_ADD, RD_DELETE } rd_state_e; typedef struct rd_event_msg { rd_event_e type; union { rd_state_e state; } u; } rd_event_msg_t; |
The rd_state_e values are:
- RD_NOSTATE
There is no additional state information available.
- RD_CONSISTANT
The link-maps are in a stable state and can be examined.
- RD_ADD
A dynamic object is in the process of being loaded and the link-maps are not in a stable state. They should not be examined until the RD_CONSISTANT state is reached.
- RD_DELETE
A dynamic object is in the process of being deleted and the link-maps are not in a stable state. They should not be examined until the RD_CONSISTANT state is reached.
The rd_event_getmsg() function is used to obtain this event state information.
- rd_event_getmsg()
This function provides additional information concerning an event.
rd_err_e rd_event_getmsg(struct rd_agent * rdap, rd_event_msg_t * msg);
The following table shows the possible state for each of the different event types.
RD_PREINIT | RD_POSTINIT | RD_DLACTIVITY |
---|---|---|
RD_NOSTATE | RD_NOSTATE | RD_CONSISTANT |
|
| RD_ADD |
|
| RD_DELETE |
Procedure Linkage Table Skipping
The rtld-debugger interface enables a controlling process to skip over procedure linkage table entries. When a controlling process, such as a debugger, is asked to step into a function for the first time, the procedure linkage table processing, causes control to be passed to the runtime linker to search for the function definition.
The following interface enables a controlling process to step over the runtime linker's procedure linkage table processing. The controlling process can determine when a procedure linkage table entry is encountered based on external information provided in the ELF file.
Once a target process has stepped into a procedure linkage table entry, the process calls the rd_plt_resolution() interface:
- rd_plt_resolution()
This function returns the resolution state of the current procedure linkage table entry and information on how to skip it.
rd_err_e rd_plt_resolution(rd_agent_t * rdap, paddr_t pc, lwpid_t lwpid, paddr_t plt_base, rd_plt_info_t * rpi);
pc represents the first instruction of the procedure linkage table entry. lwpid provides the lwp identifier and plt_base provides the base address of the procedure linkage table. These three variables provide information sufficient for various architectures to process the procedure linkage table.
rpi provides detailed information regarding the procedure linkage table entry as defined in the following data structure, defined in rtld_db.h:
typedef enum { RD_RESOLVE_NONE, RD_RESOLVE_STEP, RD_RESOLVE_TARGET, RD_RESOLVE_TARGET_STEP } rd_skip_e; typedef struct rd_plt_info { rd_skip_e pi_skip_method; long pi_nstep; psaddr_t pi_target; psaddr_t pi_baddr; unsigned int pi_flags; } rd_plt_info_t; #define RD_FLG_PI_PLTBOUND 0x0001 |
The elements of this structure are: