forked from dkogan/ltrace
-
Notifications
You must be signed in to change notification settings - Fork 0
/
backend.h
458 lines (391 loc) · 19.5 KB
/
backend.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
/*
* This file is part of ltrace.
* Copyright (C) 2012,2013 Petr Machata, Red Hat Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifndef BACKEND_H
#define BACKEND_H
#include "forward.h"
#include "sysdep.h"
#include <gelf.h>
enum process_status {
PS_INVALID, /* Failure. */
PS_STOP, /* Job-control stop. */
PS_TRACING_STOP,
PS_SLEEPING,
PS_ZOMBIE,
PS_OTHER, /* Necessary other states can be added as needed. */
};
/*
* This file contains documentation of back end interface. Some of
* these may be implemented on an OS level (i.e. they are the same
* e.g. on all Linux architectures), some may differ per architecture
* on the same OS (e.g. a way to insert a breakpoint into the process
* image is a likely candidate).
*/
/* Convert a PID to a path to the corresponding binary. */
char *pid2name(pid_t pid);
/* Given a PID, find a leader of thread group. */
pid_t process_leader(pid_t pid);
/* Given a PID of leader thread, fill in PIDs of all the tasks. The
* function will initialize the pointer *RET_TASKS to a
* newly-allocated array, and will store number of elements in that
* array to *RET_N. You have to free that buffer when you don't need
* it anymore. */
int process_tasks(pid_t pid, pid_t **ret_tasks, size_t *ret_n);
/* Answer whether the process PID is stopped. Returns 0 when not
* stopped, 1 when stopped, or -1 when there was an error. */
int process_stopped(pid_t pid);
/* Answer a status of the task PID. See enum process_status. */
enum process_status process_status(pid_t pid);
/* Wait for PID to be ready for tracing. */
int wait_for_proc(pid_t pid);
/* Send a signal SIG to the task PID. */
int task_kill(pid_t pid, int sig);
/* Called after PID is attached, but before it is continued. */
void trace_set_options(struct process *proc);
/* Called after ltrace forks. Should attach the newly created child,
* in whose context this function is called. */
void trace_me(void);
/* Called when ltrace needs to attach to PID, such as when it attaches
* to a running process, whose PID is given on the command line. */
int trace_pid(pid_t pid);
/* Stop tracing PID. */
void untrace_pid(pid_t pid);
/* The back end may need to store arbitrary data to a process. This
* is a place where it can initialize PROC->arch_dep. XXX this should
* be dropped in favor of arhc_process_init on pmachata/libs. */
void get_arch_dep(struct process *proc);
/* Return current instruction pointer of PROC.
*
* XXX note that the IP must fit into an arch pointer. This prevents
* us to use 32-bit ltrace to trace 64-bit process, even on arches
* that would otherwise support this. Above we have a definition of
* arch_addr_t. This should be converted to an integral type and
* used for target addresses throughout. */
void *get_instruction_pointer(struct process *proc);
/* Set instruction pointer of PROC to ADDR. XXX see above. */
void set_instruction_pointer(struct process *proc, void *addr);
/* Return current stack pointer of PROC. XXX see above. */
void *get_stack_pointer(struct process *proc);
/* Find and return caller address, i.e. the address where the current
* function returns. */
void *get_return_addr(struct process *proc, void *stack_pointer);
/* Enable breakpoint SBP in process PROC. */
void enable_breakpoint(struct process *proc, struct breakpoint *sbp);
/* Disable breakpoint SBP in process PROC. */
void disable_breakpoint(struct process *proc, struct breakpoint *sbp);
/* Determine whether the event that we have just seen (and that is
* recorded in STATUS) was a syscall. If it was, return 1. If it was
* a return from syscall, return 2. In both cases, set *SYSNUM to the
* number of said syscall. If it wasn't a syscall, return 0. If
* there was an error, return -1. */
int syscall_p(struct process *proc, int status, int *sysnum);
/* Continue execution of the process with given PID. */
void continue_process(pid_t pid);
/* Called after we received a signal SIGNUM. Should do whatever
* book-keeping is necessary and continue the process if
* necessary. */
void continue_after_signal(pid_t pid, int signum);
/* Called after we received a system call SYSNUM. RET_P is 0 if this
* is system call, otherwise it's return from a system call. The
* callback should do whatever book-keeping is necessary and continue
* the process if necessary. */
void continue_after_syscall(struct process *proc, int sysnum, int ret_p);
/* Called after we hit a breakpoint SBP. Should do whatever
* book-keeping is necessary and then continue the process. */
void continue_after_breakpoint(struct process *proc, struct breakpoint *sbp);
/* Called after we received a vfork. Should do whatever book-keeping
* is necessary and continue the process if necessary. N.B. right
* now, with Linux/GNU the only back end, this is not necessary. I
* imagine other systems may be different. */
void continue_after_vfork(struct process *proc);
/* Called after the process exec's. Should do whatever book-keeping
* is necessary and then continue the process. */
void continue_after_exec(struct process *proc);
/* Called when trace_me or primary trace_pid fail. This may plug in
* any platform-specific knowledge of why it could be so. */
void trace_fail_warning(pid_t pid);
/* A pair of functions called to initiate a detachment request when
* ltrace is about to exit. Their job is to undo any effects that
* tracing had and eventually detach process, perhaps by way of
* installing a process handler.
*
* OS_LTRACE_EXITING_SIGHANDLER is called from a signal handler
* context right after the signal was captured. It returns 1 if the
* request was handled or 0 if it wasn't.
*
* If the call to OS_LTRACE_EXITING_SIGHANDLER didn't handle the
* request, OS_LTRACE_EXITING is called when the next event is
* generated. Therefore it's called in "safe" context, without
* re-entrancy concerns, but it's only called after an even is
* generated. */
int os_ltrace_exiting_sighandler(void);
void os_ltrace_exiting(void);
/* Should copy COUNT bytes from address ADDR of process PROC to local
* buffer BUF. */
size_t umovebytes(struct process *proc, arch_addr_t addr,
void *buf, size_t count);
/* Find out an address of symbol SYM in process PROC, and return.
* Returning NULL delays breakpoint insertion and enables heaps of
* arch-specific black magic that we should clean up some day.
*
* XXX the same points as for get_instruction_pointer apply. */
void *sym2addr(struct process *proc, struct library_symbol *sym);
/* Obtain address of PLT entry corresponding to relocation RELA in
* file LTE. This is NDX-th PLT entry in the file.
*
* XXX should this return arch_addr_t? */
GElf_Addr arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela);
/* Called at some point after we have attached to PROC. This callback
* should insert an introspection breakpoint for handling dynamic
* linker library loads. */
int linkmap_init(struct process *proc, arch_addr_t dyn_addr);
/* This should produce and return the next event of one of the traced
* processes. The returned pointer will not be freed by the core and
* should be either statically allocated, or the management should be
* done some other way. */
struct Event *next_event(void);
/* Called when process PROC was removed. */
void process_removed(struct process *proc);
/* This should extract entry point address and interpreter (dynamic
* linker) bias if possible. Returns 0 if there were no errors, -1
* otherwise. Sets *ENTRYP and *INTERP_BIASP to non-zero values if
* the corresponding value is known, or zero otherwise; this is not
* done for pointers that are NULL. */
int process_get_entry(struct process *proc,
arch_addr_t *entryp,
arch_addr_t *interp_biasp);
/* Optional callbacks
*
* Some callbacks are only available if backend (arch.h) has a certain
* define. If such a define is not present, default implementation
* (most often doing nothing at all) us used instead. This is used
* for gradual extensions of ltrace, so that backends that are not
* fully up to date, or that don't need certain functionality, keep
* working, while other backends take advantage of the optional
* features. */
/* The following callbacks have to be implemented in backend if arch.h
* defines ARCH_HAVE_LTELF_DATA. Those are used to init and destroy
* LTE->arch. arch_elf_init returns 0 on success or a negative value
* on failure. */
int arch_elf_init(struct ltelf *lte, struct library *lib);
void arch_elf_destroy(struct ltelf *lte);
/* The following callbacks have to be implemented in OS backend if
* os.h defines OS_HAVE_BREAKPOINT_DATA. Those are used to init,
* destroy, and clone SBP->os. os_breakpoint_init and
* os_breakpoint_clone return 0 on success or a negative value on
* failure. */
int os_breakpoint_init(struct process *proc, struct breakpoint *sbp);
void os_breakpoint_destroy(struct breakpoint *sbp);
int os_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp);
/* The following callbacks have to be implemented in backend if arch.h
* defines ARCH_HAVE_BREAKPOINT_DATA. Those are used to init,
* destroy, and clone SBP->arch. arch_breakpoint_init and
* arch_breakpoint_clone return 0 on success or a negative value on
* failure. */
int arch_breakpoint_init(struct process *proc, struct breakpoint *sbp);
void arch_breakpoint_destroy(struct breakpoint *sbp);
int arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp);
/* The following callbacks have to be implemented in OS backend if
* os.h defines OS_HAVE_LIBRARY_DATA. Those are used to init, destroy
* and clone LIB->os. os_library_init and os_library_clone return 0
* on success or a negative value on failure. */
int os_library_init(struct library *lib);
void os_library_destroy(struct library *lib);
int os_library_clone(struct library *retp, struct library *lib);
/* The following callbacks have to be implemented in backend if arch.h
* defines ARCH_HAVE_LIBRARY_DATA. Those are used to init, destroy
* and clone LIB->arch. arch_library_init and arch_library_clone
* return 0 on success or a negative value on failure. */
int arch_library_init(struct library *lib);
void arch_library_destroy(struct library *lib);
int arch_library_clone(struct library *retp, struct library *lib);
/* The following callbacks have to be implemented in OS backend if
* os.h defines OS_HAVE_LIBRARY_SYMBOL_DATA. Those are used to init,
* destroy and clone LIBSYM->os. os_library_symbol_init and
* os_library_symbol_clone return 0 on success or a negative value on
* failure. */
int os_library_symbol_init(struct library_symbol *libsym);
void os_library_symbol_destroy(struct library_symbol *libsym);
int os_library_symbol_clone(struct library_symbol *retp,
struct library_symbol *libsym);
/* The following callbacks have to be implemented in backend if arch.h
* defines ARCH_HAVE_LIBRARY_SYMBOL_DATA. Those are used to init,
* destroy and clone LIBSYM->arch. arch_library_symbol_init and
* arch_library_symbol_clone return 0 on success or a negative value
* on failure. */
int arch_library_symbol_init(struct library_symbol *libsym);
void arch_library_symbol_destroy(struct library_symbol *libsym);
int arch_library_symbol_clone(struct library_symbol *retp,
struct library_symbol *libsym);
/* The following callbacks have to be implemented in OS backend if
* os.h defines OS_HAVE_PROCESS_DATA. The protocol is same as for,
* respectively, arch_process_init, arch_process_destroy,
* arch_process_clone and arch_process_exec. */
int os_process_init(struct process *proc);
void os_process_destroy(struct process *proc);
int os_process_clone(struct process *retp, struct process *proc);
int os_process_exec(struct process *proc);
/* The following callbacks have to be implemented in backend if arch.h
* defines ARCH_HAVE_PROCESS_DATA. Those are used to init, destroy
* and clone PROC->arch. arch_process_exec is called to update
* PROC->arch in case that PROC underwent an exec. See notes at
* process_init, process_destroy, process_clone and process_exec in
* proc.h. */
int arch_process_init(struct process *proc);
void arch_process_destroy(struct process *proc);
int arch_process_clone(struct process *retp, struct process *proc);
int arch_process_exec(struct process *proc);
/* The following callback has to be implemented in backend if arch.h
* defines ARCH_HAVE_GET_SYM_INFO.
*
* This is called for every PLT relocation RELA in ELF file LTE (which
* is named FILENAME), that ltrace is about to add. The corresponding
* PLT entry is for SYM_INDEX-th relocation in the file. This call is
* supposed to initialize SYM and RELA. It returns 0 if there were no
* errors and given symbol should be used, 1 if the symbol should not
* be used, or a negative value if there were errors. */
int arch_get_sym_info(struct ltelf *lte, const char *filename, size_t sym_index,
GElf_Rela *rela, GElf_Sym *sym);
enum plt_status {
PLT_FAIL,
PLT_OK,
PLT_DEFAULT,
};
/* The following callback has to be implemented in OS backend if os.h
* defines OS_HAVE_ADD_PLT_ENTRY.
*
* This is called for every PLT relocation R in ELF file LTE, that
* ltrace is about to add to a library constructed in process PROC.
* The corresponding PLT entry is for symbol called NAME, and it's
* I-th relocation in the file.
*
* If this function returns PLT_DEFAULT, PLT address is obtained by
* calling arch_plt_sym_val, and symbol is allocated. If PLT_OK or
* PLT_DEFAULT are returned, the chain of symbols passed back in RET
* is added to library under construction. */
enum plt_status os_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
const char *name, GElf_Rela *rela,
size_t i, struct library_symbol **ret);
/* Like os_elf_add_plt_entry, but tied to ARCH_HAVE_ADD_PLT_ENTRY in
* arch.h. The arch callback is called first. If it returns
* PLT_DEFAULT, the os callback is called next. */
enum plt_status arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
const char *name, GElf_Rela *rela,
size_t i, struct library_symbol **ret);
/* The following callback has to be implemented in OS backend if os.h
* defines OS_HAVE_ADD_FUNC_ENTRY.
*
* This is called for every symbol in ltrace is about to add to the
* library constructed for LTE in process PROC.
*
* If this function returns PLT_DEFAULT, then if there is a
* pre-existing symbol, its name may be updated if the newly-found
* name is shorter. Otherwise a new symbol is created.
*
* If PLT_OK or PLT_DEFAULT are returned, the chain of symbols passed
* back in RET is added to library under construction. */
enum plt_status os_elf_add_func_entry(struct process *proc, struct ltelf *lte,
const GElf_Sym *sym,
arch_addr_t addr, const char *name,
struct library_symbol **ret);
/* Like os_elf_add_func_entry, but tied to ARCH_HAVE_ADD_FUNC_ENTRY in
* arch.h. The arch callback is called first. If it returns
* PLT_DEFAULT, the os callback is called next. */
enum plt_status arch_elf_add_func_entry(struct process *proc, struct ltelf *lte,
const GElf_Sym *sym,
arch_addr_t addr, const char *name,
struct library_symbol **ret);
/* This callback needs to be implemented if arch.h defines
* ARCH_HAVE_DYNLINK_DONE. It is called after the dynamic linker is
* done with the process start-up. */
void arch_dynlink_done(struct process *proc);
/* This callback needs to be implemented if arch.h defines
* ARCH_HAVE_SYMBOL_RET. It is called after a traced call returns. */
void arch_symbol_ret(struct process *proc, struct library_symbol *libsym);
/* This callback needs to be implemented if arch.h defines
* ARCH_HAVE_FIND_DL_DEBUG.
* It is called by generic code to find the address of the dynamic
* linkers debug structure.
* DYN_ADDR holds the address of the dynamic section.
* If the debug area is found, return 0 and fill in the address in *RET.
* If the debug area is not found, return a negative value. */
int arch_find_dl_debug(struct process *proc, arch_addr_t dyn_addr,
arch_addr_t *ret);
/* This is called to obtain a list of directories to search when
* loading config files. The callback sets *RETP to a pointer to the
* first element of a NULL-terminated array of directory names. It's
* legitimate to set *RETP to NULL to indicate there are no
* directories. The function returns 0 on success or a negative value
* on a failure.
*
* If PRIVATE is set, the list in *RETP should contain only user's own
* directories (presumably under HOME if there's any such thing on the
* given OS). Otherwise only system directories should be reported.
*
* The directories don't have to exist. Directories passed in -F are
* handled separately by the caller and this callback shouldn't
* concern itself with it. */
int os_get_config_dirs(int private, const char ***retp);
/* This is called to obtain list of legacy config files to import, if
* any. A reference to initialized vector of char* is passed in.
*
* This returns 0 on success, in which case strings from *RETP (if
* any) are interpreted as files names. These files belong to the
* caller and will eventually be freed.
*
* Returns a negative value for failure, in which case *RETP contents
* are not consulted in any way. */
int os_get_ltrace_conf_filenames(struct vect *retp);
/* If arch.h defines ARCH_HAVE_FETCH_ARG, the following callbacks have
* to be implemented: arch_fetch_arg_init, arch_fetch_arg_clone,
* arch_fetch_arg_done, arch_fetch_arg_next and arch_fetch_retval.
* See fetch.h for details. */
/* If arch.h defines both ARCH_HAVE_FETCH_ARG and
* ARCH_HAVE_FETCH_PACK, the following callbacks have to be
* implemented: arch_fetch_param_pack_start,
* arch_fetch_param_pack_end. See fetch.h for details. */
enum sw_singlestep_status {
SWS_FAIL,
SWS_OK,
SWS_HW,
};
struct sw_singlestep_data;
/* The following callback has to be implemented in backend if arch.h
* defines ARCH_HAVE_SW_SINGLESTEP.
*
* This is called before the OS backend requests hardware singlestep.
* arch_sw_singlestep should consider whether a singlestep needs to be
* done in software. If not, it returns SWS_HW. Otherwise it needs
* to add one or several breakpoints by calling ADD_CB. When it is
* done, it continues the process as appropriate, and answers either
* SWS_OK, or SWS_FAIL, depending on how it went.
*
* PROC is the process that should perform the singlestep, BP the
* breakpoint that we are singlestepping over. ADD_CB is a callback
* to request adding breakpoints that should trap the process after
* it's continued. The arguments to ADD_CB are the address where the
* breakpoint should be added, and DATA. ADD_CB returns 0 on success
* or a negative value on failure. It is expected that
* arch_sw_singlestep returns SWS_FAIL if ADD_CB returns error. */
enum sw_singlestep_status arch_sw_singlestep(struct process *proc,
struct breakpoint *bp,
int (*add_cb)(arch_addr_t addr,
struct sw_singlestep_data *),
struct sw_singlestep_data *data);
#endif /* BACKEND_H */