mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 20:40:05 +00:00
Add SystemTap static probes to the runtime linker. [BZ #14298]
This commit is contained in:
parent
9f98c16cfe
commit
815e6fa3e0
19
ChangeLog
19
ChangeLog
@ -1,3 +1,22 @@
|
|||||||
|
2012-07-27 Gary Benson <gbenson@redhat.com>
|
||||||
|
|
||||||
|
[BZ #14298]
|
||||||
|
* elf/rtld.c: Include <stap-probe.h>.
|
||||||
|
(dl_main): Added static probes "init_start" and "init_complete".
|
||||||
|
* elf/dl-load.c: Include <stap-probe.h>.
|
||||||
|
(lose): Take new parameter "nsid".
|
||||||
|
Added static probe "map_failed".
|
||||||
|
(_dl_map_object_from_fd): Pass namespace id to lose.
|
||||||
|
Added static probe "map_start".
|
||||||
|
(open_verify): Pass namespace id to lose.
|
||||||
|
* elf/dl-open.c: Include <stap-probe.h>.
|
||||||
|
(dl_open_worker) Added static probes "map_complete", "reloc_start"
|
||||||
|
and "reloc_complete".
|
||||||
|
* elf/dl-close.c: Include <stap-probe.h>.
|
||||||
|
(_dl_close_worker): Added static probes "unmap_start" and
|
||||||
|
"unmap_complete".
|
||||||
|
* elf/rtld-debugger-interface.txt: New file documenting the above.
|
||||||
|
|
||||||
2012-07-26 Roland McGrath <roland@hack.frob.com>
|
2012-07-26 Roland McGrath <roland@hack.frob.com>
|
||||||
|
|
||||||
* sunrpc/rpc_hout.c (pdeclaration): Call f_print with a "%s" format
|
* sunrpc/rpc_hout.c (pdeclaration): Call f_print with a "%s" format
|
||||||
|
7
NEWS
7
NEWS
@ -9,8 +9,8 @@ Version 2.17
|
|||||||
|
|
||||||
* The following bugs are resolved with this release:
|
* The following bugs are resolved with this release:
|
||||||
|
|
||||||
6778, 6808, 14042, 14151, 14154, 14157, 14173, 14283, 14328, 14331, 14337,
|
6778, 6808, 14042, 14151, 14154, 14157, 14173, 14283, 14298, 14328, 14331,
|
||||||
14347, 14349
|
14337, 14347, 14349
|
||||||
|
|
||||||
* Support for STT_GNU_IFUNC symbols added for s390 and s390x.
|
* Support for STT_GNU_IFUNC symbols added for s390 and s390x.
|
||||||
Optimized versions of memcpy, memset, and memcmp added for System z10 and
|
Optimized versions of memcpy, memset, and memcmp added for System z10 and
|
||||||
@ -21,6 +21,9 @@ Version 2.17
|
|||||||
returning NULL if running in a SUID/SGID process. This function replaces
|
returning NULL if running in a SUID/SGID process. This function replaces
|
||||||
the internal function __secure_getenv.
|
the internal function __secure_getenv.
|
||||||
|
|
||||||
|
* SystemTap static probes have been added into the dynamic linker.
|
||||||
|
Implemented by Gary Benson.
|
||||||
|
|
||||||
|
|
||||||
Version 2.16
|
Version 2.16
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sysdep-cancel.h>
|
#include <sysdep-cancel.h>
|
||||||
#include <tls.h>
|
#include <tls.h>
|
||||||
|
#include <stap-probe.h>
|
||||||
|
|
||||||
|
|
||||||
/* Type of the constructor functions. */
|
/* Type of the constructor functions. */
|
||||||
@ -468,6 +469,7 @@ _dl_close_worker (struct link_map *map)
|
|||||||
struct r_debug *r = _dl_debug_initialize (0, nsid);
|
struct r_debug *r = _dl_debug_initialize (0, nsid);
|
||||||
r->r_state = RT_DELETE;
|
r->r_state = RT_DELETE;
|
||||||
_dl_debug_state ();
|
_dl_debug_state ();
|
||||||
|
LIBC_PROBE (unmap_start, 2, nsid, r);
|
||||||
|
|
||||||
if (unload_global)
|
if (unload_global)
|
||||||
{
|
{
|
||||||
@ -737,6 +739,7 @@ _dl_close_worker (struct link_map *map)
|
|||||||
/* Notify the debugger those objects are finalized and gone. */
|
/* Notify the debugger those objects are finalized and gone. */
|
||||||
r->r_state = RT_CONSISTENT;
|
r->r_state = RT_CONSISTENT;
|
||||||
_dl_debug_state ();
|
_dl_debug_state ();
|
||||||
|
LIBC_PROBE (unmap_complete, 2, nsid, r);
|
||||||
|
|
||||||
/* Recheck if we need to retry, release the lock. */
|
/* Recheck if we need to retry, release the lock. */
|
||||||
out:
|
out:
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include <stackinfo.h>
|
#include <stackinfo.h>
|
||||||
#include <caller.h>
|
#include <caller.h>
|
||||||
#include <sysdep.h>
|
#include <sysdep.h>
|
||||||
|
#include <stap-probe.h>
|
||||||
|
|
||||||
#include <dl-dst.h>
|
#include <dl-dst.h>
|
||||||
|
|
||||||
@ -882,7 +883,7 @@ _dl_init_paths (const char *llp)
|
|||||||
static void
|
static void
|
||||||
__attribute__ ((noreturn, noinline))
|
__attribute__ ((noreturn, noinline))
|
||||||
lose (int code, int fd, const char *name, char *realname, struct link_map *l,
|
lose (int code, int fd, const char *name, char *realname, struct link_map *l,
|
||||||
const char *msg, struct r_debug *r)
|
const char *msg, struct r_debug *r, Lmid_t nsid)
|
||||||
{
|
{
|
||||||
/* The file might already be closed. */
|
/* The file might already be closed. */
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
@ -896,6 +897,7 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l,
|
|||||||
{
|
{
|
||||||
r->r_state = RT_CONSISTENT;
|
r->r_state = RT_CONSISTENT;
|
||||||
_dl_debug_state ();
|
_dl_debug_state ();
|
||||||
|
LIBC_PROBE (map_failed, 2, nsid, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
_dl_signal_error (code, name, NULL, msg);
|
_dl_signal_error (code, name, NULL, msg);
|
||||||
@ -934,7 +936,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
|
|||||||
errval = errno;
|
errval = errno;
|
||||||
call_lose:
|
call_lose:
|
||||||
lose (errval, fd, name, realname, l, errstring,
|
lose (errval, fd, name, realname, l, errstring,
|
||||||
make_consistent ? r : NULL);
|
make_consistent ? r : NULL, nsid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look again to see if the real name matched another already loaded. */
|
/* Look again to see if the real name matched another already loaded. */
|
||||||
@ -1041,6 +1043,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
|
|||||||
linking has not been used before. */
|
linking has not been used before. */
|
||||||
r->r_state = RT_ADD;
|
r->r_state = RT_ADD;
|
||||||
_dl_debug_state ();
|
_dl_debug_state ();
|
||||||
|
LIBC_PROBE (map_start, 2, nsid, r);
|
||||||
make_consistent = true;
|
make_consistent = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1736,7 +1739,7 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
|
|||||||
name = strdupa (realname);
|
name = strdupa (realname);
|
||||||
free (realname);
|
free (realname);
|
||||||
}
|
}
|
||||||
lose (errval, fd, name, NULL, NULL, errstring, NULL);
|
lose (errval, fd, name, NULL, NULL, errstring, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See whether the ELF header is what we expect. */
|
/* See whether the ELF header is what we expect. */
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <caller.h>
|
#include <caller.h>
|
||||||
#include <sysdep-cancel.h>
|
#include <sysdep-cancel.h>
|
||||||
#include <tls.h>
|
#include <tls.h>
|
||||||
|
#include <stap-probe.h>
|
||||||
|
|
||||||
#include <dl-dst.h>
|
#include <dl-dst.h>
|
||||||
|
|
||||||
@ -291,6 +292,7 @@ dl_open_worker (void *a)
|
|||||||
struct r_debug *r = _dl_debug_initialize (0, args->nsid);
|
struct r_debug *r = _dl_debug_initialize (0, args->nsid);
|
||||||
r->r_state = RT_CONSISTENT;
|
r->r_state = RT_CONSISTENT;
|
||||||
_dl_debug_state ();
|
_dl_debug_state ();
|
||||||
|
LIBC_PROBE (map_complete, 3, args->nsid, r, new);
|
||||||
|
|
||||||
/* Print scope information. */
|
/* Print scope information. */
|
||||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES, 0))
|
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES, 0))
|
||||||
@ -376,10 +378,19 @@ dl_open_worker (void *a)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int relocation_in_progress = 0;
|
||||||
|
|
||||||
for (size_t i = nmaps; i-- > 0; )
|
for (size_t i = nmaps; i-- > 0; )
|
||||||
{
|
{
|
||||||
l = maps[i];
|
l = maps[i];
|
||||||
|
|
||||||
|
if (! relocation_in_progress)
|
||||||
|
{
|
||||||
|
/* Notify the debugger that relocations are about to happen. */
|
||||||
|
LIBC_PROBE (reloc_start, 2, args->nsid, r);
|
||||||
|
relocation_in_progress = 1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SHARED
|
#ifdef SHARED
|
||||||
if (__builtin_expect (GLRO(dl_profile) != NULL, 0))
|
if (__builtin_expect (GLRO(dl_profile) != NULL, 0))
|
||||||
{
|
{
|
||||||
@ -544,6 +555,10 @@ cannot load any more object with static TLS"));
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Notify the debugger all new objects have been relocated. */
|
||||||
|
if (relocation_in_progress)
|
||||||
|
LIBC_PROBE (reloc_complete, 3, args->nsid, r, new);
|
||||||
|
|
||||||
/* Run the initializer functions of new objects. */
|
/* Run the initializer functions of new objects. */
|
||||||
_dl_init (new, args->argc, args->argv, args->env);
|
_dl_init (new, args->argc, args->argv, args->env);
|
||||||
|
|
||||||
|
122
elf/rtld-debugger-interface.txt
Normal file
122
elf/rtld-debugger-interface.txt
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
Standard debugger interface
|
||||||
|
===========================
|
||||||
|
|
||||||
|
The run-time linker exposes a rendezvous structure to allow debuggers
|
||||||
|
to interface with it. This structure, r_debug, is defined in link.h.
|
||||||
|
If the executable's dynamic section has a DT_DEBUG element, the
|
||||||
|
run-time linker sets that element's value to the address where this
|
||||||
|
structure can be found.
|
||||||
|
|
||||||
|
The r_debug structure contains (amongst others) the following fields:
|
||||||
|
|
||||||
|
struct link_map *r_map:
|
||||||
|
A linked list of loaded objects.
|
||||||
|
|
||||||
|
enum { RT_CONSISTENT, RT_ADD, RT_DELETE } r_state:
|
||||||
|
The current state of the r_map list. RT_CONSISTENT means that r_map
|
||||||
|
is not currently being modified and may safely be inspected. RT_ADD
|
||||||
|
means that an object is being added to r_map, and that the list is
|
||||||
|
not guaranteed to be consistent. Likewise RT_DELETE means that an
|
||||||
|
object is being removed from the list.
|
||||||
|
|
||||||
|
ElfW(Addr) r_brk:
|
||||||
|
The address of a function internal to the run-time linker which is
|
||||||
|
called whenever r_state is changed. The debugger should set a
|
||||||
|
breakpoint at this address if it wants to notice mapping changes.
|
||||||
|
|
||||||
|
This protocol is widely supported, but somewhat limited in that it
|
||||||
|
has no provision to provide access to multiple namespaces, and that
|
||||||
|
the notifications (via r_brk) only refer to changes to r_map--the
|
||||||
|
debugger is notified that a new object has been added, for instance,
|
||||||
|
but there is no way for the debugger to discover whether any of the
|
||||||
|
objects in the link-map have been relocated or not.
|
||||||
|
|
||||||
|
|
||||||
|
Probe-based debugger interface
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Systemtap is a dynamic tracing/instrumenting tool available on Linux.
|
||||||
|
Probes that are not fired at run time have close to zero overhead.
|
||||||
|
glibc contains a number of probes that debuggers can set breakpoints
|
||||||
|
on in order to notice certain events.
|
||||||
|
|
||||||
|
All rtld probes have the following arguments:
|
||||||
|
|
||||||
|
arg1: Lmid_t lmid:
|
||||||
|
The link-map ID of the link-map list that the object was loaded
|
||||||
|
into. This will be LM_ID_BASE for the application's main link-map
|
||||||
|
list, or some other value for different namespaces.
|
||||||
|
|
||||||
|
arg2: struct r_debug *r_debug:
|
||||||
|
A pointer to the r_debug structure containing the link-map list
|
||||||
|
that the object was loaded into. This will be the value stored in
|
||||||
|
DT_DEBUG for the application's main link-map list, or some other
|
||||||
|
value for different namespaces.
|
||||||
|
|
||||||
|
map_complete and reloc_complete may have the following additional
|
||||||
|
argument:
|
||||||
|
|
||||||
|
arg3: struct link_map *new:
|
||||||
|
A pointer which, if not NULL, points to the entry in the specified
|
||||||
|
r_debug structure's link-map list corresponding to the first new
|
||||||
|
object to have been mapped or relocated, with new->l_next pointing
|
||||||
|
to the link-map of the next new object to have been mapped or
|
||||||
|
relocated, and so on. Note that because `new' is an entry in a
|
||||||
|
larger list, new->l_prev (if not NULL) will point to what was the
|
||||||
|
last link-map in the link-map list prior to the new objects being
|
||||||
|
mapped or relocated.
|
||||||
|
|
||||||
|
The following probes are available:
|
||||||
|
|
||||||
|
init_start:
|
||||||
|
This is called once, when the linker is about to fill in the main
|
||||||
|
r_debug structure at application startup. init_start always has
|
||||||
|
lmid set to LM_ID_BASE and r_debug set to the value stored in
|
||||||
|
DT_DEBUG. r_debug is not guaranteed to be consistent until
|
||||||
|
init_complete is fired.
|
||||||
|
|
||||||
|
init_complete:
|
||||||
|
This is called once, when the linker has filled in the main
|
||||||
|
r_debug structure at application startup. init_complete always
|
||||||
|
has lmid set to LM_ID_BASE and r_debug set to the value stored
|
||||||
|
in DT_DEBUG. The r_debug structure is consistent and may be
|
||||||
|
inspected, and all objects in the link-map are guaranteed to
|
||||||
|
have been relocated.
|
||||||
|
|
||||||
|
map_start:
|
||||||
|
The linker is about to map new objects into the specified
|
||||||
|
namespace. The namespace's r_debug structure is not guaranteed
|
||||||
|
to be consistent until a corresponding map_complete is fired.
|
||||||
|
|
||||||
|
map_complete:
|
||||||
|
The linker has finished mapping new objects into the specified
|
||||||
|
namespace. The namespace's r_debug structure is consistent and
|
||||||
|
may be inspected, although objects in the namespace's link-map
|
||||||
|
are not guaranteed to have been relocated.
|
||||||
|
|
||||||
|
map_failed:
|
||||||
|
The linker failed while attempting to map new objects into
|
||||||
|
the specified namespace. The namespace's r_debug structure
|
||||||
|
is consistent and may be inspected.
|
||||||
|
|
||||||
|
reloc_start:
|
||||||
|
The linker is about to relocate all unrelocated objects in the
|
||||||
|
specified namespace. The namespace's r_debug structure is not
|
||||||
|
guaranteed to be consistent until a corresponding reloc_complete
|
||||||
|
is fired.
|
||||||
|
|
||||||
|
reloc_complete:
|
||||||
|
The linker has relocated all objects in the specified namespace.
|
||||||
|
The namespace's r_debug structure is consistent and may be
|
||||||
|
inspected, and all objects in the namespace's link-map are
|
||||||
|
guaranteed to have been relocated.
|
||||||
|
|
||||||
|
unmap_start:
|
||||||
|
The linker is about to remove objects from the specified
|
||||||
|
namespace. The namespace's r_debug structure is not guaranteed to
|
||||||
|
be consistent until a corresponding unmap_complete is fired.
|
||||||
|
|
||||||
|
unmap_complete:
|
||||||
|
The linker has finished removing objects into the specified
|
||||||
|
namespace. The namespace's r_debug structure is consistent and
|
||||||
|
may be inspected.
|
@ -39,6 +39,7 @@
|
|||||||
#include <dl-osinfo.h>
|
#include <dl-osinfo.h>
|
||||||
#include <dl-procinfo.h>
|
#include <dl-procinfo.h>
|
||||||
#include <tls.h>
|
#include <tls.h>
|
||||||
|
#include <stap-probe.h>
|
||||||
#include <stackinfo.h>
|
#include <stackinfo.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -1683,6 +1684,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
|
|||||||
/* We start adding objects. */
|
/* We start adding objects. */
|
||||||
r->r_state = RT_ADD;
|
r->r_state = RT_ADD;
|
||||||
_dl_debug_state ();
|
_dl_debug_state ();
|
||||||
|
LIBC_PROBE (init_start, 2, LM_ID_BASE, r);
|
||||||
|
|
||||||
/* Auditing checkpoint: we are ready to signal that the initial map
|
/* Auditing checkpoint: we are ready to signal that the initial map
|
||||||
is being constructed. */
|
is being constructed. */
|
||||||
@ -2402,6 +2404,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
|
|||||||
r = _dl_debug_initialize (0, LM_ID_BASE);
|
r = _dl_debug_initialize (0, LM_ID_BASE);
|
||||||
r->r_state = RT_CONSISTENT;
|
r->r_state = RT_CONSISTENT;
|
||||||
_dl_debug_state ();
|
_dl_debug_state ();
|
||||||
|
LIBC_PROBE (init_complete, 2, LM_ID_BASE, r);
|
||||||
|
|
||||||
#ifndef MAP_COPY
|
#ifndef MAP_COPY
|
||||||
/* We must munmap() the cache file. */
|
/* We must munmap() the cache file. */
|
||||||
|
Loading…
Reference in New Issue
Block a user