1 /* Trace calls through PLTs and show caller, callee, and parameters.
2 Copyright (C) 2011 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 #include <sys/param.h>
33 extern const char *__progname
;
34 extern const char *__progname_full
;
37 /* List of objects to trace calls from. */
38 static const char *fromlist
;
39 /* List of objects to trace calls to. */
40 static const char *tolist
;
42 /* If non-zero, also trace returns of the calls. */
44 /* If non-zero print PID for each line. */
47 /* The output stream to use. */
48 static FILE *out_file
;
52 match_pid (pid_t pid
, const char *which
)
54 if (which
== NULL
|| which
[0] == '\0')
61 unsigned long n
= strtoul (which
, &endp
, 0);
62 return *endp
== '\0' && n
== pid
;
69 fromlist
= getenv ("SOTRUSS_FROMLIST");
70 if (fromlist
!= NULL
&& fromlist
[0] == '\0')
72 tolist
= getenv ("SOTRUSS_TOLIST");
73 if (tolist
!= NULL
&& tolist
[0] == '\0')
75 do_exit
= (getenv ("SOTRUSS_EXIT") ?: "")[0] != '\0';
77 /* Determine whether this process is supposed to be traced and if
78 yes, whether we should print into a file. */
79 const char *which_process
= getenv ("SOTRUSS_WHICH");
80 pid_t pid
= getpid ();
82 if (match_pid (pid
, which_process
))
84 const char *out_filename
= getenv ("SOTRUSS_OUTNAME");
86 if (out_filename
!= NULL
&& out_filename
[0] != 0)
88 size_t out_filename_len
= strlen (out_filename
) + 12;
89 char fullname
[out_filename_len
];
90 char *endp
= stpcpy (fullname
, out_filename
);
91 if (which_process
== NULL
|| which_process
[0] == '\0')
92 snprintf (endp
, 12, ".%lu", (unsigned long int) pid
);
94 out_fd
= open (fullname
, O_RDWR
| O_CREAT
| O_TRUNC
, 0666);
100 /* If we do not write into a file write to stderr. Duplicate the
101 descriptor so that we can keep printing in case the program
102 closes stderr. Try first to allocate a descriptor with a value
103 usually not used as to minimize interference with the
107 out_fd
= fcntl (STDERR_FILENO
, F_DUPFD
, 1000);
109 out_fd
= dup (STDERR_FILENO
);
114 /* Convert file descriptor into a stream. */
115 out_file
= fdopen (out_fd
, "w");
116 if (out_file
!= NULL
)
117 setlinebuf (out_file
);
122 /* Audit interface verification. We also initialize everything if
123 everything checks out OK. */
125 la_version (unsigned int v
)
127 if (v
!= LAV_CURRENT
)
128 error (1, 0, "cannot handle interface version %u", v
);
136 /* Check whether a file name is on the colon-separated list of file
139 match_file (const char *list
, const char *name
, size_t name_len
,
145 const char *cp
= list
;
148 if (strncmp (cp
, name
, name_len
) == 0
149 && (cp
[name_len
] == ':' || cp
[name_len
] == '\0'))
152 cp
= strchr (cp
, ':');
161 la_objopen (struct link_map
*map
, Lmid_t lmid
, uintptr_t *cookie
)
163 if (out_file
== NULL
)
166 const char *full_name
= map
->l_name
?: "";
167 if (full_name
[0] == '\0')
168 full_name
= __progname_full
;
169 size_t full_name_len
= strlen (full_name
);
170 const char *base_name
= basename (full_name
);
171 if (base_name
[0] == '\0')
172 base_name
= __progname
;
173 size_t base_name_len
= strlen (base_name
);
176 const char *print_name
= NULL
;
177 for (struct libname_list
*l
= map
->l_libname
; l
!= NULL
; l
= l
->next
)
179 if (print_name
== NULL
|| (print_name
[0] == '/' && l
->name
[0] != '/'))
180 print_name
= l
->name
;
182 if (fromlist
!= NULL
)
183 result
|= match_file (fromlist
, l
->name
, strlen (l
->name
),
187 result
|= match_file (tolist
, l
->name
, strlen (l
->name
),LA_FLG_BINDTO
);
190 if (print_name
== NULL
)
191 print_name
= base_name
;
192 if (print_name
[0] == '\0')
193 print_name
= __progname
;
195 /* We cannot easily get to the object name in the PLT handling
196 functions. Use the cookie to get the string pointer passed back
198 *cookie
= (uintptr_t) print_name
;
200 /* The object name has to be on the list of objects to trace calls
201 from or that list must be empty. In the latter case we trace
202 only calls from the main binary. */
203 if (fromlist
== NULL
)
204 result
|= map
->l_name
[0] == '\0' ? LA_FLG_BINDFROM
: 0;
206 result
|= (match_file (fromlist
, full_name
, full_name_len
,
208 | match_file (fromlist
, base_name
, base_name_len
,
211 /* The object name has to be on the list of objects to trace calls
212 to or that list must be empty. In the latter case we trace
213 calls toall objects. */
215 result
|= LA_FLG_BINDTO
;
217 result
|= (match_file (tolist
, full_name
, full_name_len
, LA_FLG_BINDTO
)
218 | match_file (tolist
, base_name
, base_name_len
, LA_FLG_BINDTO
));
224 #if __ELF_NATIVE_CLASS == 32
225 # define la_symbind la_symbind32
226 typedef Elf32_Sym Elf_Sym
;
228 # define la_symbind la_symbind64
229 typedef Elf64_Sym Elf_Sym
;
233 la_symbind (Elf_Sym
*sym
, unsigned int ndx
, uintptr_t *refcook
,
234 uintptr_t *defcook
, unsigned int *flags
, const char *symname
)
237 *flags
= LA_SYMB_NOPLTEXIT
;
239 return sym
->st_value
;
244 print_enter (uintptr_t *refcook
, uintptr_t *defcook
, const char *symname
,
245 unsigned long int reg1
, unsigned long int reg2
,
246 unsigned long int reg3
, unsigned int flags
)
248 char buf
[3 * sizeof (pid_t
) + 3];
251 snprintf (buf
, sizeof (buf
), "%5ld: ", (long int) getpid ());
253 fprintf (out_file
, "%s%15s -> %-15s:%s%s(0x%lx, 0x%lx, 0x%lx)\n",
254 buf
, (char *) *refcook
, (char *) *defcook
,
255 (flags
& LA_SYMB_NOPLTEXIT
) ? "*" : " ", symname
, reg1
, reg2
, reg3
);
261 la_i86_gnu_pltenter (Elf32_Sym
*sym
__attribute__ ((unused
)),
262 unsigned int ndx
__attribute__ ((unused
)),
263 uintptr_t *refcook
, uintptr_t *defcook
,
264 La_i86_regs
*regs
, unsigned int *flags
,
265 const char *symname
, long int *framesizep
)
267 unsigned long int *sp
= (unsigned long int *) regs
->lr_esp
;
269 print_enter (refcook
, defcook
, symname
, sp
[1], sp
[2], sp
[3], *flags
);
271 /* No need to copy anything, we will not need the parameters in any case. */
274 return sym
->st_value
;
276 #elif defined __x86_64__
278 la_x86_64_gnu_pltenter (Elf64_Sym
*sym
__attribute__ ((unused
)),
279 unsigned int ndx
__attribute__ ((unused
)),
280 uintptr_t *refcook
, uintptr_t *defcook
,
281 La_x86_64_regs
*regs
, unsigned int *flags
,
282 const char *symname
, long int *framesizep
)
284 print_enter (refcook
, defcook
, symname
,
285 regs
->lr_rdi
, regs
->lr_rsi
, regs
->lr_rdx
, *flags
);
287 /* No need to copy anything, we will not need the parameters in any case. */
290 return sym
->st_value
;
292 #elif !defined HAVE_ARCH_PLTENTER
293 # warning "pltenter for architecture not supported"
298 print_exit (uintptr_t *refcook
, uintptr_t *defcook
, const char *symname
,
299 unsigned long int reg
)
301 char buf
[3 * sizeof (pid_t
) + 3];
304 snprintf (buf
, sizeof (buf
), "%5ld: ", (long int) getpid ());
306 fprintf (out_file
, "%s%15s -> %-15s:%s%s - 0x%lu\n",
307 buf
, (char *) *refcook
, (char *) *defcook
, " ", symname
, reg
);
313 la_i86_gnu_pltexit (Elf32_Sym
*sym
, unsigned int ndx
, uintptr_t *refcook
,
314 uintptr_t *defcook
, const struct La_i86_regs
*inregs
,
315 struct La_i86_retval
*outregs
, const char *symname
)
317 print_exit (refcook
, defcook
, symname
, outregs
->lrv_eax
);
321 #elif defined __x86_64__
323 la_x86_64_gnu_pltexit (Elf64_Sym
*sym
, unsigned int ndx
, uintptr_t *refcook
,
324 uintptr_t *defcook
, const struct La_x86_64_regs
*inregs
,
325 struct La_x86_64_retval
*outregs
, const char *symname
)
327 print_exit (refcook
, defcook
, symname
, outregs
->lrv_rax
);
331 #elif !defined HAVE_ARCH_PLTEXIT
332 # warning "pltexit for architecture not supported"