6473 lines
206 KiB
Diff
6473 lines
206 KiB
Diff
diff --git a/Makefile.am b/Makefile.am
|
|
index 6e46949..c3356de 100644
|
|
--- a/Makefile.am
|
|
+++ b/Makefile.am
|
|
@@ -60,7 +60,8 @@ libltrace_la_SOURCES = \
|
|
zero.c \
|
|
lens.c \
|
|
lens_default.c \
|
|
- lens_enum.c
|
|
+ lens_enum.c \
|
|
+ memstream.c
|
|
|
|
libltrace_la_LIBADD = \
|
|
$(libelf_LIBS) \
|
|
@@ -112,7 +113,8 @@ noinst_HEADERS = \
|
|
zero.h \
|
|
lens.h \
|
|
lens_default.h \
|
|
- lens_enum.h
|
|
+ lens_enum.h \
|
|
+ memstream.h
|
|
|
|
dist_man1_MANS = ltrace.1
|
|
dist_man5_MANS = ltrace.conf.5
|
|
diff --git a/backend.h b/backend.h
|
|
index 89c05c3..cfac65e 100644
|
|
--- a/backend.h
|
|
+++ b/backend.h
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
* This file is part of ltrace.
|
|
- * Copyright (C) 2012 Petr Machata, Red Hat Inc.
|
|
+ * 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
|
|
@@ -27,12 +27,12 @@
|
|
#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. */
|
|
+ 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. */
|
|
};
|
|
|
|
/*
|
|
@@ -70,7 +70,7 @@ int wait_for_proc(pid_t 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);
|
|
+void trace_set_options(struct process *proc);
|
|
|
|
/* Called after ltrace forks. Should attach the newly created child,
|
|
* in whose context this function is called. */
|
|
@@ -86,7 +86,7 @@ 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);
|
|
+void get_arch_dep(struct process *proc);
|
|
|
|
/* Return current instruction pointer of PROC.
|
|
*
|
|
@@ -95,34 +95,34 @@ void get_arch_dep(struct Process *proc);
|
|
* 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);
|
|
+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);
|
|
+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);
|
|
+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);
|
|
+void *get_return_addr(struct process *proc, void *stack_pointer);
|
|
|
|
/* Adjust PROC so that when the current function returns, it returns
|
|
* to ADDR. */
|
|
-void set_return_addr(struct Process *proc, void *addr);
|
|
+void set_return_addr(struct process *proc, void *addr);
|
|
|
|
/* Enable breakpoint SBP in process PROC. */
|
|
-void enable_breakpoint(struct Process *proc, struct breakpoint *sbp);
|
|
+void enable_breakpoint(struct process *proc, struct breakpoint *sbp);
|
|
|
|
/* Disable breakpoint SBP in process PROC. */
|
|
-void disable_breakpoint(struct Process *proc, struct breakpoint *sbp);
|
|
+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);
|
|
+int syscall_p(struct process *proc, int status, int *sysnum);
|
|
|
|
/* Continue execution of the process with given PID. */
|
|
void continue_process(pid_t pid);
|
|
@@ -136,17 +136,21 @@ void continue_after_signal(pid_t pid, int signum);
|
|
* 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);
|
|
+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);
|
|
+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);
|
|
+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. */
|
|
@@ -171,14 +175,14 @@ 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, void *addr, void *buf, size_t count);
|
|
+size_t umovebytes(struct process *proc, void *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);
|
|
+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.
|
|
@@ -189,7 +193,7 @@ 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);
|
|
+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
|
|
@@ -198,14 +202,14 @@ int linkmap_init(struct Process *proc, arch_addr_t dyn_addr);
|
|
struct Event *next_event(void);
|
|
|
|
/* Called when process PROC was removed. */
|
|
-void process_removed(struct Process *proc);
|
|
+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,
|
|
+int process_get_entry(struct process *proc,
|
|
arch_addr_t *entryp,
|
|
arch_addr_t *interp_biasp);
|
|
|
|
@@ -232,7 +236,7 @@ void arch_elf_destroy(struct ltelf *lte);
|
|
* 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);
|
|
+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);
|
|
|
|
@@ -259,19 +263,19 @@ int arch_library_symbol_clone(struct library_symbol *retp,
|
|
* 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);
|
|
+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 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);
|
|
+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 callback has to be implemented in backend if arch.h
|
|
* defines ARCH_HAVE_GET_SYM_INFO.
|
|
@@ -289,9 +293,9 @@ 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,
|
|
+ PLT_FAIL,
|
|
+ PLT_OK,
|
|
+ PLT_DEFAULT,
|
|
};
|
|
|
|
/* The following callback has to be implemented in backend if arch.h
|
|
@@ -302,22 +306,22 @@ enum plt_status {
|
|
* 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
|
|
+ * 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 arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
|
|
+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);
|
|
|
|
/* 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 startup. */
|
|
-void arch_dynlink_done(struct Process *proc);
|
|
+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);
|
|
+void arch_symbol_ret(struct process *proc, struct library_symbol *libsym);
|
|
|
|
|
|
/* This callback needs to be implemented if arch.h defines
|
|
@@ -327,7 +331,7 @@ void arch_symbol_ret(struct Process *proc, struct library_symbol *libsym);
|
|
* 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,
|
|
+int arch_find_dl_debug(struct process *proc, arch_addr_t dyn_addr,
|
|
arch_addr_t *ret);
|
|
|
|
/* If arch.h defines ARCH_HAVE_FETCH_ARG, the following callbacks have
|
|
@@ -340,4 +344,34 @@ int arch_find_dl_debug(struct Process *proc, arch_addr_t dyn_addr,
|
|
* 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 */
|
|
diff --git a/breakpoint.h b/breakpoint.h
|
|
index 7cd914e..18af7a9 100644
|
|
--- a/breakpoint.h
|
|
+++ b/breakpoint.h
|
|
@@ -41,14 +41,12 @@
|
|
|
|
#include "sysdep.h"
|
|
#include "library.h"
|
|
-
|
|
-struct Process;
|
|
-struct breakpoint;
|
|
+#include "forward.h"
|
|
|
|
struct bp_callbacks {
|
|
- void (*on_hit)(struct breakpoint *bp, struct Process *proc);
|
|
- void (*on_continue)(struct breakpoint *bp, struct Process *proc);
|
|
- void (*on_retract)(struct breakpoint *bp, struct Process *proc);
|
|
+ void (*on_hit)(struct breakpoint *bp, struct process *proc);
|
|
+ void (*on_continue)(struct breakpoint *bp, struct process *proc);
|
|
+ void (*on_retract)(struct breakpoint *bp, struct process *proc);
|
|
};
|
|
|
|
struct breakpoint {
|
|
@@ -61,11 +59,11 @@ struct breakpoint {
|
|
};
|
|
|
|
/* Call on-hit handler of BP, if any is set. */
|
|
-void breakpoint_on_hit(struct breakpoint *bp, struct Process *proc);
|
|
+void breakpoint_on_hit(struct breakpoint *bp, struct process *proc);
|
|
|
|
/* Call on-continue handler of BP. If none is set, call
|
|
* continue_after_breakpoint. */
|
|
-void breakpoint_on_continue(struct breakpoint *bp, struct Process *proc);
|
|
+void breakpoint_on_continue(struct breakpoint *bp, struct process *proc);
|
|
|
|
/* Call on-retract handler of BP, if any is set. This should be
|
|
* called before the breakpoints are destroyed. The reason for a
|
|
@@ -74,21 +72,21 @@ void breakpoint_on_continue(struct breakpoint *bp, struct Process *proc);
|
|
* be called every time we disable the breakpoint, which is too often
|
|
* (a breakpoint has to be disabled every time that we need to execute
|
|
* the instruction underneath it). */
|
|
-void breakpoint_on_retract(struct breakpoint *bp, struct Process *proc);
|
|
+void breakpoint_on_retract(struct breakpoint *bp, struct process *proc);
|
|
|
|
/* Initialize a breakpoint structure. That doesn't actually realize
|
|
* the breakpoint. The breakpoint is initially assumed to be
|
|
* disabled. orig_value has to be set separately. CBS may be
|
|
* NULL. */
|
|
-int breakpoint_init(struct breakpoint *bp, struct Process *proc,
|
|
+int breakpoint_init(struct breakpoint *bp, struct process *proc,
|
|
arch_addr_t addr, struct library_symbol *libsym);
|
|
|
|
/* Make a clone of breakpoint BP into the area of memory pointed to by
|
|
* RETP. The original breakpoint was assigned to process OLD_PROC,
|
|
* the cloned breakpoint will be attached to process NEW_PROC.
|
|
* Returns 0 on success or a negative value on failure. */
|
|
-int breakpoint_clone(struct breakpoint *retp, struct Process *new_proc,
|
|
- struct breakpoint *bp, struct Process *old_proc);
|
|
+int breakpoint_clone(struct breakpoint *retp, struct process *new_proc,
|
|
+ struct breakpoint *bp, struct process *old_proc);
|
|
|
|
/* Set callbacks. If CBS is non-NULL, then BP->cbs shall be NULL. */
|
|
void breakpoint_set_callbacks(struct breakpoint *bp, struct bp_callbacks *cbs);
|
|
@@ -98,12 +96,12 @@ void breakpoint_destroy(struct breakpoint *bp);
|
|
|
|
/* Call enable_breakpoint the first time it's called. Returns 0 on
|
|
* success and a negative value on failure. */
|
|
-int breakpoint_turn_on(struct breakpoint *bp, struct Process *proc);
|
|
+int breakpoint_turn_on(struct breakpoint *bp, struct process *proc);
|
|
|
|
/* Call disable_breakpoint when turned off the same number of times
|
|
* that it was turned on. Returns 0 on success and a negative value
|
|
* on failure. */
|
|
-int breakpoint_turn_off(struct breakpoint *bp, struct Process *proc);
|
|
+int breakpoint_turn_off(struct breakpoint *bp, struct process *proc);
|
|
|
|
/* Utility function that does what typically needs to be done when a
|
|
* breakpoint is to be inserted. It checks whether there is another
|
|
@@ -113,7 +111,7 @@ int breakpoint_turn_off(struct breakpoint *bp, struct Process *proc);
|
|
* added as well as preexisting breakpoints, it then calls
|
|
* BREAKPOINT_TURN_ON. If anything fails, it cleans up and returns
|
|
* NULL. Otherwise it returns the breakpoint for ADDR. */
|
|
-struct breakpoint *insert_breakpoint(struct Process *proc, void *addr,
|
|
+struct breakpoint *insert_breakpoint(struct process *proc, void *addr,
|
|
struct library_symbol *libsym);
|
|
|
|
/* Name of a symbol associated with BP. May be NULL. */
|
|
@@ -127,12 +125,12 @@ struct library *breakpoint_library(const struct breakpoint *bp);
|
|
* - proc_remove_breakpoint
|
|
* - breakpoint_destroy
|
|
* XXX */
|
|
-void delete_breakpoint(struct Process *proc, void *addr);
|
|
+void delete_breakpoint(struct process *proc, void *addr);
|
|
|
|
/* XXX some of the following belongs to proc.h/proc.c. */
|
|
-struct breakpoint *address2bpstruct(struct Process *proc, void *addr);
|
|
-void enable_all_breakpoints(struct Process *proc);
|
|
-void disable_all_breakpoints(struct Process *proc);
|
|
-int breakpoints_init(struct Process *proc);
|
|
+struct breakpoint *address2bpstruct(struct process *proc, void *addr);
|
|
+void enable_all_breakpoints(struct process *proc);
|
|
+void disable_all_breakpoints(struct process *proc);
|
|
+int breakpoints_init(struct process *proc);
|
|
|
|
#endif /* BREAKPOINT_H */
|
|
diff --git a/breakpoints.c b/breakpoints.c
|
|
index 258be93..8db4e26 100644
|
|
--- a/breakpoints.c
|
|
+++ b/breakpoints.c
|
|
@@ -42,7 +42,7 @@
|
|
|
|
#ifndef ARCH_HAVE_TRANSLATE_ADDRESS
|
|
int
|
|
-arch_translate_address_dyn(struct Process *proc,
|
|
+arch_translate_address_dyn(struct process *proc,
|
|
arch_addr_t addr, arch_addr_t *ret)
|
|
{
|
|
*ret = addr;
|
|
@@ -60,7 +60,7 @@ arch_translate_address(struct ltelf *lte,
|
|
#endif
|
|
|
|
void
|
|
-breakpoint_on_hit(struct breakpoint *bp, struct Process *proc)
|
|
+breakpoint_on_hit(struct breakpoint *bp, struct process *proc)
|
|
{
|
|
assert(bp != NULL);
|
|
if (bp->cbs != NULL && bp->cbs->on_hit != NULL)
|
|
@@ -68,7 +68,7 @@ breakpoint_on_hit(struct breakpoint *bp, struct Process *proc)
|
|
}
|
|
|
|
void
|
|
-breakpoint_on_continue(struct breakpoint *bp, struct Process *proc)
|
|
+breakpoint_on_continue(struct breakpoint *bp, struct process *proc)
|
|
{
|
|
assert(bp != NULL);
|
|
if (bp->cbs != NULL && bp->cbs->on_continue != NULL)
|
|
@@ -78,7 +78,7 @@ breakpoint_on_continue(struct breakpoint *bp, struct Process *proc)
|
|
}
|
|
|
|
void
|
|
-breakpoint_on_retract(struct breakpoint *bp, struct Process *proc)
|
|
+breakpoint_on_retract(struct breakpoint *bp, struct process *proc)
|
|
{
|
|
assert(bp != NULL);
|
|
if (bp->cbs != NULL && bp->cbs->on_retract != NULL)
|
|
@@ -88,7 +88,7 @@ breakpoint_on_retract(struct breakpoint *bp, struct Process *proc)
|
|
/*****************************************************************************/
|
|
|
|
struct breakpoint *
|
|
-address2bpstruct(Process *proc, void *addr)
|
|
+address2bpstruct(struct process *proc, void *addr)
|
|
{
|
|
assert(proc != NULL);
|
|
assert(proc->breakpoints != NULL);
|
|
@@ -99,7 +99,7 @@ address2bpstruct(Process *proc, void *addr)
|
|
|
|
#ifndef ARCH_HAVE_BREAKPOINT_DATA
|
|
int
|
|
-arch_breakpoint_init(struct Process *proc, struct breakpoint *sbp)
|
|
+arch_breakpoint_init(struct process *proc, struct breakpoint *sbp)
|
|
{
|
|
return 0;
|
|
}
|
|
@@ -117,7 +117,7 @@ arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp)
|
|
#endif
|
|
|
|
static void
|
|
-breakpoint_init_base(struct breakpoint *bp, struct Process *proc,
|
|
+breakpoint_init_base(struct breakpoint *bp, struct process *proc,
|
|
arch_addr_t addr, struct library_symbol *libsym)
|
|
{
|
|
bp->cbs = NULL;
|
|
@@ -132,7 +132,7 @@ breakpoint_init_base(struct breakpoint *bp, struct Process *proc,
|
|
* static lookups of various sections in the ELF file. We shouldn't
|
|
* need process for anything. */
|
|
int
|
|
-breakpoint_init(struct breakpoint *bp, struct Process *proc,
|
|
+breakpoint_init(struct breakpoint *bp, struct process *proc,
|
|
arch_addr_t addr, struct library_symbol *libsym)
|
|
{
|
|
breakpoint_init_base(bp, proc, addr, libsym);
|
|
@@ -156,8 +156,8 @@ breakpoint_destroy(struct breakpoint *bp)
|
|
}
|
|
|
|
int
|
|
-breakpoint_clone(struct breakpoint *retp, struct Process *new_proc,
|
|
- struct breakpoint *bp, struct Process *old_proc)
|
|
+breakpoint_clone(struct breakpoint *retp, struct process *new_proc,
|
|
+ struct breakpoint *bp, struct process *old_proc)
|
|
{
|
|
struct library_symbol *libsym = NULL;
|
|
if (bp->libsym != NULL) {
|
|
@@ -175,7 +175,7 @@ breakpoint_clone(struct breakpoint *retp, struct Process *new_proc,
|
|
}
|
|
|
|
int
|
|
-breakpoint_turn_on(struct breakpoint *bp, struct Process *proc)
|
|
+breakpoint_turn_on(struct breakpoint *bp, struct process *proc)
|
|
{
|
|
bp->enabled++;
|
|
if (bp->enabled == 1) {
|
|
@@ -186,7 +186,7 @@ breakpoint_turn_on(struct breakpoint *bp, struct Process *proc)
|
|
}
|
|
|
|
int
|
|
-breakpoint_turn_off(struct breakpoint *bp, struct Process *proc)
|
|
+breakpoint_turn_off(struct breakpoint *bp, struct process *proc)
|
|
{
|
|
bp->enabled--;
|
|
if (bp->enabled == 0)
|
|
@@ -196,10 +196,10 @@ breakpoint_turn_off(struct breakpoint *bp, struct Process *proc)
|
|
}
|
|
|
|
struct breakpoint *
|
|
-insert_breakpoint(struct Process *proc, void *addr,
|
|
+insert_breakpoint(struct process *proc, void *addr,
|
|
struct library_symbol *libsym)
|
|
{
|
|
- Process *leader = proc->leader;
|
|
+ struct process *leader = proc->leader;
|
|
|
|
/* Only the group leader should be getting the breakpoints and
|
|
* thus have ->breakpoint initialized. */
|
|
@@ -243,11 +243,11 @@ insert_breakpoint(struct Process *proc, void *addr,
|
|
}
|
|
|
|
void
|
|
-delete_breakpoint(Process *proc, void *addr)
|
|
+delete_breakpoint(struct process *proc, void *addr)
|
|
{
|
|
debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr);
|
|
|
|
- Process * leader = proc->leader;
|
|
+ struct process *leader = proc->leader;
|
|
assert(leader != NULL);
|
|
|
|
struct breakpoint *sbp = dict_find_entry(leader->breakpoints, addr);
|
|
@@ -285,13 +285,14 @@ breakpoint_library(const struct breakpoint *bp)
|
|
static void
|
|
enable_bp_cb(void *addr, void *sbp, void *proc)
|
|
{
|
|
- debug(DEBUG_FUNCTION, "enable_bp_cb(pid=%d)", ((Process *)proc)->pid);
|
|
+ debug(DEBUG_FUNCTION, "enable_bp_cb(pid=%d)",
|
|
+ ((struct process *)proc)->pid);
|
|
if (((struct breakpoint *)sbp)->enabled)
|
|
enable_breakpoint(proc, sbp);
|
|
}
|
|
|
|
void
|
|
-enable_all_breakpoints(Process *proc)
|
|
+enable_all_breakpoints(struct process *proc)
|
|
{
|
|
debug(DEBUG_FUNCTION, "enable_all_breakpoints(pid=%d)", proc->pid);
|
|
|
|
@@ -305,13 +306,15 @@ enable_all_breakpoints(Process *proc)
|
|
static void
|
|
disable_bp_cb(void *addr, void *sbp, void *proc)
|
|
{
|
|
- debug(DEBUG_FUNCTION, "disable_bp_cb(pid=%d)", ((Process *)proc)->pid);
|
|
+ debug(DEBUG_FUNCTION, "disable_bp_cb(pid=%d)",
|
|
+ ((struct process *)proc)->pid);
|
|
if (((struct breakpoint *)sbp)->enabled)
|
|
disable_breakpoint(proc, sbp);
|
|
}
|
|
|
|
void
|
|
-disable_all_breakpoints(Process *proc) {
|
|
+disable_all_breakpoints(struct process *proc)
|
|
+{
|
|
debug(DEBUG_FUNCTION, "disable_all_breakpoints(pid=%d)", proc->pid);
|
|
assert(proc->leader == proc);
|
|
dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc);
|
|
@@ -330,7 +333,7 @@ struct entry_breakpoint {
|
|
};
|
|
|
|
static void
|
|
-entry_breakpoint_on_hit(struct breakpoint *a, struct Process *proc)
|
|
+entry_breakpoint_on_hit(struct breakpoint *a, struct process *proc)
|
|
{
|
|
struct entry_breakpoint *bp = (void *)a;
|
|
if (proc == NULL || proc->leader == NULL)
|
|
@@ -342,7 +345,7 @@ entry_breakpoint_on_hit(struct breakpoint *a, struct Process *proc)
|
|
}
|
|
|
|
int
|
|
-entry_breakpoint_init(struct Process *proc,
|
|
+entry_breakpoint_init(struct process *proc,
|
|
struct entry_breakpoint *bp, arch_addr_t addr,
|
|
struct library *lib)
|
|
{
|
|
@@ -360,7 +363,7 @@ entry_breakpoint_init(struct Process *proc,
|
|
}
|
|
|
|
int
|
|
-breakpoints_init(Process *proc)
|
|
+breakpoints_init(struct process *proc)
|
|
{
|
|
debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid);
|
|
|
|
diff --git a/configure.ac b/configure.ac
|
|
index 20c84f4..47bd87e 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -21,9 +21,9 @@
|
|
# 02110-1301 USA
|
|
|
|
# Process this file with autoconf to produce a configure script.
|
|
-AC_PREREQ(2.65)
|
|
+AC_PREREQ([2.65])
|
|
|
|
-AC_INIT([ltrace],[0.7.2],[ltrace-devel@lists.alioth.debian.org])
|
|
+AC_INIT([ltrace],[0.7.90-git],[ltrace-devel@lists.alioth.debian.org])
|
|
AC_CONFIG_HEADERS([config.h])
|
|
AC_CONFIG_SRCDIR(libltrace.c)
|
|
AC_CONFIG_MACRO_DIR([config/m4])
|
|
@@ -245,23 +246,48 @@ AC_CHECK_SIZEOF([long])
|
|
|
|
|
|
# Checks for library functions.
|
|
-AC_FUNC_ERROR_AT_LINE
|
|
AC_FUNC_FORK
|
|
AC_CHECK_FUNCS([ \
|
|
alarm \
|
|
atexit \
|
|
- getcwd \
|
|
gettimeofday \
|
|
memset \
|
|
- mkdir \
|
|
- rmdir \
|
|
strchr \
|
|
strdup \
|
|
strerror \
|
|
+ strsignal \
|
|
strtol \
|
|
strtoul \
|
|
])
|
|
|
|
+#
|
|
+# Define HAVE_OPEN_MEMSTREAM if open_memstream is available. glibc
|
|
+# before 2.10, eglibc and uClibc all need _GNU_SOURCE defined for
|
|
+# open_memstream to become visible, so check for that as well. If
|
|
+# unavailable, require that tmpfile be present. There's no
|
|
+# HAVE_TMPFILE, as we plain require that to be present as a fallback.
|
|
+#
|
|
+AC_CHECK_FUNCS([open_memstream], [],
|
|
+ [AC_MSG_CHECKING([for open_memstream with _GNU_SOURCE])
|
|
+ AC_LINK_IFELSE(
|
|
+ [AC_LANG_PROGRAM([[#define _GNU_SOURCE 1
|
|
+ #include <stdio.h>]],
|
|
+ [[char *buf; size_t sz;
|
|
+ return open_memstream(&buf, &sz) != 0;]])],
|
|
+
|
|
+ [AC_MSG_RESULT([yes])
|
|
+ AC_DEFINE([HAVE_OPEN_MEMSTREAM], [1],
|
|
+ [Define if open_memstream exists.])],
|
|
+
|
|
+ [AC_MSG_RESULT([no])
|
|
+ AC_CHECK_FUNC([tmpfile], [],
|
|
+ [AC_MSG_ERROR(
|
|
+ [Either open_memstream or tmpfile required.])])])])
|
|
+
|
|
+#
|
|
+# Define HAVE_GETOPT_LONG if that is available.
|
|
+#
|
|
+AC_CHECK_HEADER([getopt.h], [AC_CHECK_FUNCS([getopt_long])])
|
|
|
|
#
|
|
# Debugging
|
|
diff --git a/debug.c b/debug.c
|
|
index 1b03189..ce220fe 100644
|
|
--- a/debug.c
|
|
+++ b/debug.c
|
|
@@ -1,5 +1,6 @@
|
|
/*
|
|
* This file is part of ltrace.
|
|
+ * Copyright (C) 2012 Petr Machata, Red Hat Inc.
|
|
* Copyright (C) 2003,2008,2009 Juan Cespedes
|
|
* Copyright (C) 2006 Ian Wienand
|
|
*
|
|
@@ -23,6 +24,7 @@
|
|
#include <stdarg.h>
|
|
|
|
#include "common.h"
|
|
+#include "backend.h"
|
|
|
|
void
|
|
debug_(int level, const char *file, int line, const char *fmt, ...) {
|
|
@@ -40,95 +42,26 @@ debug_(int level, const char *file, int line, const char *fmt, ...) {
|
|
fflush(options.output);
|
|
}
|
|
|
|
-/*
|
|
- * The following section provides a way to print things, like hex dumps,
|
|
- * with out using buffered output. This was written by Steve Munroe of IBM.
|
|
- */
|
|
-
|
|
-#include <stdio.h>
|
|
-#include <errno.h>
|
|
-#include <unistd.h>
|
|
-#include <stdlib.h>
|
|
-#include <sys/ptrace.h>
|
|
-
|
|
-static int
|
|
-xwritehexl(long i) {
|
|
- int rc = 0;
|
|
- char text[17];
|
|
- int j;
|
|
- unsigned long temp = (unsigned long)i;
|
|
-
|
|
- for (j = 15; j >= 0; j--) {
|
|
- char c;
|
|
- c = (char)((temp & 0x0f) + '0');
|
|
- if (c > '9') {
|
|
- c = (char)(c + ('a' - '9' - 1));
|
|
- }
|
|
- text[j] = c;
|
|
- temp = temp >> 4;
|
|
- }
|
|
-
|
|
- rc = write(1, text, 16);
|
|
- return rc;
|
|
-}
|
|
-
|
|
-static int
|
|
-xwritec(char c) {
|
|
- char temp = c;
|
|
- char *text = &temp;
|
|
- int rc = 0;
|
|
- rc = write(1, text, 1);
|
|
- return rc;
|
|
-}
|
|
-
|
|
-static int
|
|
-xwritecr(void) {
|
|
- return xwritec('\n');
|
|
-}
|
|
-
|
|
static int
|
|
-xwritedump(void *ptr, long addr, int len) {
|
|
- int rc = 0;
|
|
- long *tprt = (long *)ptr;
|
|
- int i;
|
|
-
|
|
- for (i = 0; i < len; i += 8) {
|
|
- xwritehexl(addr);
|
|
- xwritec('-');
|
|
- xwritec('>');
|
|
- xwritehexl(*tprt++);
|
|
- xwritecr();
|
|
+xwritedump(long *ptr, arch_addr_t addr, size_t count)
|
|
+{
|
|
+ size_t i;
|
|
+ for (i = 0; i < count; ++i) {
|
|
+ if (fprintf(stderr, "%p->%0*lx\n",
|
|
+ addr, 2 * (int)sizeof(long), ptr[i]) < 0)
|
|
+ return -1;
|
|
addr += sizeof(long);
|
|
}
|
|
|
|
- return rc;
|
|
+ return 0;
|
|
}
|
|
|
|
int
|
|
-xinfdump(long pid, void *ptr, int len) {
|
|
- int rc;
|
|
- int i;
|
|
- long wrdcnt;
|
|
- long *infwords;
|
|
- long addr;
|
|
-
|
|
- wrdcnt = len / sizeof(long) + 1;
|
|
- infwords = malloc(wrdcnt * sizeof(long));
|
|
- if (!infwords) {
|
|
- perror("ltrace: malloc");
|
|
- exit(1);
|
|
- }
|
|
- addr = (long)ptr;
|
|
-
|
|
- addr = ((addr + sizeof(long) - 1) / sizeof(long)) * sizeof(long);
|
|
-
|
|
- for (i = 0; i < wrdcnt; ++i) {
|
|
- infwords[i] = ptrace(PTRACE_PEEKTEXT, pid, (void *)addr, NULL);
|
|
- addr += sizeof(long);
|
|
- }
|
|
-
|
|
- rc = xwritedump(infwords, (long)ptr, len);
|
|
-
|
|
- free(infwords);
|
|
- return rc;
|
|
+xinfdump(struct process *proc, arch_addr_t addr, size_t length)
|
|
+{
|
|
+ unsigned char buf[length];
|
|
+ size_t got = umovebytes(proc, addr, buf, length);
|
|
+ if (got == (size_t)-1)
|
|
+ return -1;
|
|
+ return xwritedump((long *)buf, addr, got / sizeof(long));
|
|
}
|
|
diff --git a/debug.h b/debug.h
|
|
index 4775d2f..542dda5 100644
|
|
--- a/debug.h
|
|
+++ b/debug.h
|
|
@@ -1,5 +1,6 @@
|
|
/*
|
|
* This file is part of ltrace.
|
|
+ * Copyright (C) 2012 Petr Machata, Red Hat Inc.
|
|
* Copyright (C) 2003,2009 Juan Cespedes
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
@@ -21,6 +22,9 @@
|
|
#ifndef _DEBUG_H
|
|
#define _DEBUG_H
|
|
|
|
+#include "backend.h"
|
|
+#include "forward.h"
|
|
+
|
|
/* debug levels:
|
|
*/
|
|
enum {
|
|
@@ -32,8 +36,10 @@ enum {
|
|
void debug_(int level, const char *file, int line,
|
|
const char *fmt, ...) __attribute__((format(printf,4,5)));
|
|
|
|
-int xinfdump(long, void *, int);
|
|
+/* Dump LENGTH bytes of memory starting on address ADDR of inferior
|
|
+ * PID. */
|
|
+int xinfdump(struct process *proc, arch_addr_t addr, size_t length);
|
|
|
|
-# define debug(level, expr...) debug_(level, __FILE__, __LINE__, expr)
|
|
+#define debug(level, expr...) debug_(level, __FILE__, __LINE__, expr)
|
|
|
|
#endif
|
|
diff --git a/expr.c b/expr.c
|
|
index 32860fd..552a53c 100644
|
|
--- a/expr.c
|
|
+++ b/expr.c
|
|
@@ -21,7 +21,6 @@
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
-#include <error.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "expr.h"
|
|
@@ -327,12 +326,11 @@ expr_eval_constant(struct expr_node *node, long *valuep)
|
|
struct expr_node *
|
|
expr_self(void)
|
|
{
|
|
- static struct expr_node *node = NULL;
|
|
- if (node == NULL) {
|
|
- node = malloc(sizeof(*node));
|
|
- if (node == NULL)
|
|
- error(1, errno, "malloc expr_self");
|
|
- expr_init_self(node);
|
|
+ static struct expr_node *nodep = NULL;
|
|
+ if (nodep == NULL) {
|
|
+ static struct expr_node node;
|
|
+ expr_init_self(&node);
|
|
+ nodep = &node;
|
|
}
|
|
- return node;
|
|
+ return nodep;
|
|
}
|
|
diff --git a/fetch.c b/fetch.c
|
|
index 88966a5..cbceefb 100644
|
|
--- a/fetch.c
|
|
+++ b/fetch.c
|
|
@@ -27,18 +27,18 @@
|
|
#include "type.h"
|
|
|
|
#ifdef ARCH_HAVE_FETCH_ARG
|
|
-struct fetch_context *arch_fetch_arg_init(enum tof type, struct Process *proc,
|
|
+struct fetch_context *arch_fetch_arg_init(enum tof type, struct process *proc,
|
|
struct arg_type_info *ret_info);
|
|
|
|
-struct fetch_context *arch_fetch_arg_clone(struct Process *proc,
|
|
+struct fetch_context *arch_fetch_arg_clone(struct process *proc,
|
|
struct fetch_context *context);
|
|
|
|
int arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
|
|
- struct Process *proc, struct arg_type_info *info,
|
|
+ struct process *proc, struct arg_type_info *info,
|
|
struct value *valuep);
|
|
|
|
int arch_fetch_retval(struct fetch_context *ctx, enum tof type,
|
|
- struct Process *proc, struct arg_type_info *info,
|
|
+ struct process *proc, struct arg_type_info *info,
|
|
struct value *valuep);
|
|
|
|
void arch_fetch_arg_done(struct fetch_context *context);
|
|
@@ -53,7 +53,7 @@ void arch_fetch_param_pack_end(struct fetch_context *context);
|
|
#else
|
|
/* Fall back to gimme_arg. */
|
|
|
|
-long gimme_arg(enum tof type, struct Process *proc, int arg_num,
|
|
+long gimme_arg(enum tof type, struct process *proc, int arg_num,
|
|
struct arg_type_info *info);
|
|
|
|
struct fetch_context {
|
|
@@ -61,14 +61,14 @@ struct fetch_context {
|
|
};
|
|
|
|
struct fetch_context *
|
|
-arch_fetch_arg_init(enum tof type, struct Process *proc,
|
|
+arch_fetch_arg_init(enum tof type, struct process *proc,
|
|
struct arg_type_info *ret_info)
|
|
{
|
|
return calloc(sizeof(struct fetch_context), 1);
|
|
}
|
|
|
|
struct fetch_context *
|
|
-arch_fetch_arg_clone(struct Process *proc, struct fetch_context *context)
|
|
+arch_fetch_arg_clone(struct process *proc, struct fetch_context *context)
|
|
{
|
|
struct fetch_context *ret = malloc(sizeof(*ret));
|
|
if (ret == NULL)
|
|
@@ -78,7 +78,7 @@ arch_fetch_arg_clone(struct Process *proc, struct fetch_context *context)
|
|
|
|
int
|
|
arch_fetch_arg_next(struct fetch_context *context, enum tof type,
|
|
- struct Process *proc,
|
|
+ struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep)
|
|
{
|
|
long l = gimme_arg(type, proc, context->argnum++, info);
|
|
@@ -88,7 +88,7 @@ arch_fetch_arg_next(struct fetch_context *context, enum tof type,
|
|
|
|
int
|
|
arch_fetch_retval(struct fetch_context *context, enum tof type,
|
|
- struct Process *proc,
|
|
+ struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep)
|
|
{
|
|
long l = gimme_arg(type, proc, -1, info);
|
|
@@ -118,21 +118,21 @@ arch_fetch_param_pack_end(struct fetch_context *context)
|
|
#endif
|
|
|
|
struct fetch_context *
|
|
-fetch_arg_init(enum tof type, struct Process *proc,
|
|
+fetch_arg_init(enum tof type, struct process *proc,
|
|
struct arg_type_info *ret_info)
|
|
{
|
|
return arch_fetch_arg_init(type, proc, ret_info);
|
|
}
|
|
|
|
struct fetch_context *
|
|
-fetch_arg_clone(struct Process *proc, struct fetch_context *context)
|
|
+fetch_arg_clone(struct process *proc, struct fetch_context *context)
|
|
{
|
|
return arch_fetch_arg_clone(proc, context);
|
|
}
|
|
|
|
int
|
|
fetch_arg_next(struct fetch_context *context, enum tof type,
|
|
- struct Process *proc,
|
|
+ struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep)
|
|
{
|
|
return arch_fetch_arg_next(context, type, proc, info, valuep);
|
|
@@ -140,7 +140,7 @@ fetch_arg_next(struct fetch_context *context, enum tof type,
|
|
|
|
int
|
|
fetch_retval(struct fetch_context *context, enum tof type,
|
|
- struct Process *proc,
|
|
+ struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep)
|
|
{
|
|
return arch_fetch_retval(context, type, proc, info, valuep);
|
|
diff --git a/fetch.h b/fetch.h
|
|
index 2a13214..3a1644a 100644
|
|
--- a/fetch.h
|
|
+++ b/fetch.h
|
|
@@ -38,24 +38,24 @@ struct fetch_context;
|
|
|
|
/* Initialize argument fetching. Returns NULL on failure. RET_INFO
|
|
* is the return type of the function. */
|
|
-struct fetch_context *fetch_arg_init(enum tof type, struct Process *proc,
|
|
+struct fetch_context *fetch_arg_init(enum tof type, struct process *proc,
|
|
struct arg_type_info *ret_info);
|
|
|
|
/* Make a clone of context. */
|
|
-struct fetch_context *fetch_arg_clone(struct Process *proc,
|
|
+struct fetch_context *fetch_arg_clone(struct process *proc,
|
|
struct fetch_context *context);
|
|
|
|
/* Load next argument. The function returns 0 on success or a
|
|
* negative value on failure. The extracted value is stored in
|
|
* *VALUEP. */
|
|
int fetch_arg_next(struct fetch_context *context, enum tof type,
|
|
- struct Process *proc,
|
|
+ struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep);
|
|
|
|
/* Load return value. The function returns 0 on success or a negative
|
|
* value on failure. The extracted value is stored in *VALUEP. */
|
|
int fetch_retval(struct fetch_context *context, enum tof type,
|
|
- struct Process *proc,
|
|
+ struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep);
|
|
|
|
/* Destroy fetch context. CONTEXT shall be the same memory location
|
|
@@ -74,15 +74,15 @@ void fetch_param_pack_end(struct fetch_context *context);
|
|
/* The following callbacks have to be implemented in backend if arch.h
|
|
* defines ARCH_HAVE_FETCH_ARG. These backend callbacks correspond to
|
|
* above functions. */
|
|
-struct fetch_context *arch_fetch_arg_init(enum tof type, struct Process *proc,
|
|
+struct fetch_context *arch_fetch_arg_init(enum tof type, struct process *proc,
|
|
struct arg_type_info *ret_info);
|
|
-struct fetch_context *arch_fetch_arg_clone(struct Process *proc,
|
|
+struct fetch_context *arch_fetch_arg_clone(struct process *proc,
|
|
struct fetch_context *context);
|
|
int arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
|
|
- struct Process *proc, struct arg_type_info *info,
|
|
+ struct process *proc, struct arg_type_info *info,
|
|
struct value *valuep);
|
|
int arch_fetch_retval(struct fetch_context *ctx, enum tof type,
|
|
- struct Process *proc, struct arg_type_info *info,
|
|
+ struct process *proc, struct arg_type_info *info,
|
|
struct value *valuep);
|
|
void arch_fetch_arg_done(struct fetch_context *context);
|
|
|
|
diff --git a/forward.h b/forward.h
|
|
index 85a0630..d334339 100644
|
|
--- a/forward.h
|
|
+++ b/forward.h
|
|
@@ -21,7 +21,7 @@
|
|
/* Important types defined in other header files are declared
|
|
here. */
|
|
struct Event;
|
|
-struct Process;
|
|
+struct process;
|
|
struct arg_type_info;
|
|
struct breakpoint;
|
|
struct expr_node;
|
|
diff --git a/glob.c b/glob.c
|
|
index 9af633f..b26637f 100644
|
|
--- a/glob.c
|
|
+++ b/glob.c
|
|
@@ -180,7 +180,7 @@ glob_to_regex(const char *glob, char **retp)
|
|
goto fail;
|
|
}
|
|
*retp = buf;
|
|
- return REG_NOERROR;
|
|
+ return 0;
|
|
}
|
|
|
|
int
|
|
@@ -188,7 +188,7 @@ globcomp(regex_t *preg, const char *glob, int cflags)
|
|
{
|
|
char *regex = NULL;
|
|
int status = glob_to_regex(glob, ®ex);
|
|
- if (status != REG_NOERROR)
|
|
+ if (status != 0)
|
|
return status;
|
|
assert(regex != NULL);
|
|
status = regcomp(preg, regex, cflags);
|
|
diff --git a/handle_event.c b/handle_event.c
|
|
index 42a7a05..9dbb696 100644
|
|
--- a/handle_event.c
|
|
+++ b/handle_event.c
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
* This file is part of ltrace.
|
|
- * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
|
|
+ * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
|
|
* Copyright (C) 2010 Arnaud Patard, Mandriva SA
|
|
* Copyright (C) 1998,2001,2002,2003,2004,2007,2008,2009 Juan Cespedes
|
|
* Copyright (C) 2008 Luis Machado, IBM Corporation
|
|
@@ -54,20 +54,20 @@ static void handle_exec(Event *event);
|
|
static void handle_breakpoint(Event *event);
|
|
static void handle_new(Event *event);
|
|
|
|
-static void callstack_push_syscall(Process *proc, int sysnum);
|
|
-static void callstack_push_symfunc(Process *proc,
|
|
+static void callstack_push_syscall(struct process *proc, int sysnum);
|
|
+static void callstack_push_symfunc(struct process *proc,
|
|
struct library_symbol *sym);
|
|
/* XXX Stack maintenance should be moved to a dedicated module, or to
|
|
* proc.c, and push/pop should be visible outside this module. For
|
|
* now, because we need this in proc.c, this is non-static. */
|
|
-void callstack_pop(struct Process *proc);
|
|
+void callstack_pop(struct process *proc);
|
|
|
|
-static char * shortsignal(Process *proc, int signum);
|
|
-static char * sysname(Process *proc, int sysnum);
|
|
-static char * arch_sysname(Process *proc, int sysnum);
|
|
+static char *shortsignal(struct process *proc, int signum);
|
|
+static char *sysname(struct process *proc, int sysnum);
|
|
+static char *arch_sysname(struct process *proc, int sysnum);
|
|
|
|
static Event *
|
|
-call_handler(Process * proc, Event * event)
|
|
+call_handler(struct process *proc, Event *event)
|
|
{
|
|
assert(proc != NULL);
|
|
|
|
@@ -256,7 +256,7 @@ handle_clone(Event *event)
|
|
{
|
|
debug(DEBUG_FUNCTION, "handle_clone(pid=%d)", event->proc->pid);
|
|
|
|
- struct Process *proc = malloc(sizeof(*proc));
|
|
+ struct process *proc = malloc(sizeof(*proc));
|
|
if (proc == NULL) {
|
|
fail:
|
|
free(proc);
|
|
@@ -297,12 +297,11 @@ handle_clone(Event *event)
|
|
}
|
|
|
|
static void
|
|
-handle_new(Event * event) {
|
|
- Process * proc;
|
|
-
|
|
+handle_new(Event *event)
|
|
+{
|
|
debug(DEBUG_FUNCTION, "handle_new(pid=%d)", event->e_un.newpid);
|
|
|
|
- proc = pid2proc(event->e_un.newpid);
|
|
+ struct process *proc = pid2proc(event->e_un.newpid);
|
|
if (!proc) {
|
|
pending_new_insert(event->e_un.newpid);
|
|
} else {
|
|
@@ -317,7 +316,8 @@ handle_new(Event * event) {
|
|
}
|
|
|
|
static char *
|
|
-shortsignal(Process *proc, int signum) {
|
|
+shortsignal(struct process *proc, int signum)
|
|
+{
|
|
static char *signalent0[] = {
|
|
#include "signalent.h"
|
|
};
|
|
@@ -341,7 +341,8 @@ shortsignal(Process *proc, int signum) {
|
|
}
|
|
|
|
static char *
|
|
-sysname(Process *proc, int sysnum) {
|
|
+sysname(struct process *proc, int sysnum)
|
|
+{
|
|
static char result[128];
|
|
static char *syscalent0[] = {
|
|
#include "syscallent.h"
|
|
@@ -369,7 +370,8 @@ sysname(Process *proc, int sysnum) {
|
|
}
|
|
|
|
static char *
|
|
-arch_sysname(Process *proc, int sysnum) {
|
|
+arch_sysname(struct process *proc, int sysnum)
|
|
+{
|
|
static char result[128];
|
|
static char *arch_syscalent[] = {
|
|
#include "arch_syscallent.h"
|
|
@@ -388,6 +390,10 @@ arch_sysname(Process *proc, int sysnum) {
|
|
}
|
|
}
|
|
|
|
+#ifndef HAVE_STRSIGNAL
|
|
+# define strsignal(SIGNUM) "???"
|
|
+#endif
|
|
+
|
|
static void
|
|
handle_signal(Event *event) {
|
|
debug(DEBUG_FUNCTION, "handle_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
|
|
@@ -420,8 +426,8 @@ handle_exit_signal(Event *event) {
|
|
}
|
|
|
|
static void
|
|
-output_syscall(struct Process *proc, const char *name, enum tof tof,
|
|
- void (*output)(enum tof, struct Process *,
|
|
+output_syscall(struct process *proc, const char *name, enum tof tof,
|
|
+ void (*output)(enum tof, struct process *,
|
|
struct library_symbol *))
|
|
{
|
|
struct library_symbol syscall;
|
|
@@ -432,13 +438,13 @@ output_syscall(struct Process *proc, const char *name, enum tof tof,
|
|
}
|
|
|
|
static void
|
|
-output_syscall_left(struct Process *proc, const char *name)
|
|
+output_syscall_left(struct process *proc, const char *name)
|
|
{
|
|
output_syscall(proc, name, LT_TOF_SYSCALL, &output_left);
|
|
}
|
|
|
|
static void
|
|
-output_syscall_right(struct Process *proc, const char *name)
|
|
+output_syscall_right(struct process *proc, const char *name)
|
|
{
|
|
output_syscall(proc, name, LT_TOF_SYSCALLR, &output_right);
|
|
}
|
|
@@ -457,8 +463,9 @@ handle_syscall(Event *event) {
|
|
}
|
|
|
|
static void
|
|
-handle_exec(Event * event) {
|
|
- Process * proc = event->proc;
|
|
+handle_exec(Event *event)
|
|
+{
|
|
+ struct process *proc = event->proc;
|
|
|
|
/* Save the PID so that we can use it after unsuccessful
|
|
* process_exec. */
|
|
@@ -479,18 +486,7 @@ handle_exec(Event * event) {
|
|
goto untrace;
|
|
}
|
|
|
|
- continue_process(proc->pid);
|
|
-
|
|
- /* After the exec, we expect to hit the first executable
|
|
- * instruction.
|
|
- *
|
|
- * XXX TODO It would be nice to have this removed, but then we
|
|
- * need to do that also for initial call to wait_for_proc in
|
|
- * execute_program. In that case we could generate a
|
|
- * EVENT_FIRST event or something, or maybe this could somehow
|
|
- * be rolled into EVENT_NEW. */
|
|
- wait_for_proc(proc->pid);
|
|
- continue_process(proc->pid);
|
|
+ continue_after_exec(proc);
|
|
}
|
|
|
|
static void
|
|
@@ -510,7 +506,8 @@ handle_arch_syscall(Event *event) {
|
|
struct timeval current_time_spent;
|
|
|
|
static void
|
|
-calc_time_spent(Process *proc) {
|
|
+calc_time_spent(struct process *proc)
|
|
+{
|
|
struct timeval tv;
|
|
struct timezone tz;
|
|
struct timeval diff;
|
|
@@ -568,7 +565,7 @@ handle_arch_sysret(Event *event) {
|
|
}
|
|
|
|
static void
|
|
-output_right_tos(struct Process *proc)
|
|
+output_right_tos(struct process *proc)
|
|
{
|
|
size_t d = proc->callstack_depth;
|
|
struct callstack_element *elem = &proc->callstack[d - 1];
|
|
@@ -577,7 +574,7 @@ output_right_tos(struct Process *proc)
|
|
}
|
|
|
|
#ifndef ARCH_HAVE_SYMBOL_RET
|
|
-void arch_symbol_ret(struct Process *proc, struct library_symbol *libsym)
|
|
+void arch_symbol_ret(struct process *proc, struct library_symbol *libsym)
|
|
{
|
|
}
|
|
#endif
|
|
@@ -587,7 +584,7 @@ handle_breakpoint(Event *event)
|
|
{
|
|
int i, j;
|
|
struct breakpoint *sbp;
|
|
- Process *leader = event->proc->leader;
|
|
+ struct process *leader = event->proc->leader;
|
|
void *brk_addr = event->e_un.brk_addr;
|
|
|
|
/* The leader has terminated. */
|
|
@@ -682,7 +679,8 @@ handle_breakpoint(Event *event)
|
|
}
|
|
|
|
static void
|
|
-callstack_push_syscall(Process *proc, int sysnum) {
|
|
+callstack_push_syscall(struct process *proc, int sysnum)
|
|
+{
|
|
struct callstack_element *elem;
|
|
|
|
debug(DEBUG_FUNCTION, "callstack_push_syscall(pid=%d, sysnum=%d)", proc->pid, sysnum);
|
|
@@ -707,7 +705,8 @@ callstack_push_syscall(Process *proc, int sysnum) {
|
|
}
|
|
|
|
static void
|
|
-callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
|
|
+callstack_push_symfunc(struct process *proc, struct library_symbol *sym)
|
|
+{
|
|
struct callstack_element *elem;
|
|
|
|
debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name);
|
|
@@ -734,7 +733,7 @@ callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
|
|
}
|
|
|
|
void
|
|
-callstack_pop(struct Process *proc)
|
|
+callstack_pop(struct process *proc)
|
|
{
|
|
struct callstack_element *elem;
|
|
assert(proc->callstack_depth > 0);
|
|
diff --git a/libltrace.c b/libltrace.c
|
|
index 559edfa..b69a0c9 100644
|
|
--- a/libltrace.c
|
|
+++ b/libltrace.c
|
|
@@ -21,6 +21,7 @@
|
|
|
|
#include "config.h"
|
|
|
|
+#include <limits.h>
|
|
#include <sys/param.h>
|
|
#include <sys/wait.h>
|
|
#include <errno.h>
|
|
@@ -40,13 +41,13 @@ char *command = NULL;
|
|
int exiting = 0; /* =1 if a SIGINT or SIGTERM has been received */
|
|
|
|
static enum callback_status
|
|
-stop_non_p_processes(Process *proc, void *data)
|
|
+stop_non_p_processes(struct process *proc, void *data)
|
|
{
|
|
int stop = 1;
|
|
|
|
struct opt_p_t *it;
|
|
for (it = opt_p; it != NULL; it = it->next) {
|
|
- Process * p_proc = pid2proc(it->pid);
|
|
+ struct process *p_proc = pid2proc(it->pid);
|
|
if (p_proc == NULL) {
|
|
printf("stop_non_p_processes: %d terminated?\n", it->pid);
|
|
continue;
|
|
@@ -141,7 +142,7 @@ ltrace_init(int argc, char **argv) {
|
|
do_close_elf(<e);
|
|
|
|
pid_t pid = execute_program(command, argv);
|
|
- struct Process *proc = open_program(command, pid);
|
|
+ struct process *proc = open_program(command, pid);
|
|
if (proc == NULL) {
|
|
fprintf(stderr, "couldn't open program '%s': %s\n",
|
|
command, strerror(errno));
|
|
diff --git a/library.c b/library.c
|
|
index 594472b..b5f6386 100644
|
|
--- a/library.c
|
|
+++ b/library.c
|
|
@@ -412,7 +412,7 @@ library_add_symbol(struct library *lib, struct library_symbol *first)
|
|
}
|
|
|
|
enum callback_status
|
|
-library_named_cb(struct Process *proc, struct library *lib, void *name)
|
|
+library_named_cb(struct process *proc, struct library *lib, void *name)
|
|
{
|
|
if (name == lib->soname
|
|
|| strcmp(lib->soname, (char *)name) == 0)
|
|
@@ -422,7 +422,7 @@ library_named_cb(struct Process *proc, struct library *lib, void *name)
|
|
}
|
|
|
|
enum callback_status
|
|
-library_with_key_cb(struct Process *proc, struct library *lib, void *keyp)
|
|
+library_with_key_cb(struct process *proc, struct library *lib, void *keyp)
|
|
{
|
|
return lib->key == *(arch_addr_t *)keyp ? CBS_STOP : CBS_CONT;
|
|
}
|
|
diff --git a/library.h b/library.h
|
|
index 555fa80..74e1df2 100644
|
|
--- a/library.h
|
|
+++ b/library.h
|
|
@@ -23,12 +23,11 @@
|
|
#define _LIBRARY_H_
|
|
|
|
#include <stdint.h>
|
|
+
|
|
#include "callback.h"
|
|
+#include "forward.h"
|
|
#include "sysdep.h"
|
|
|
|
-struct Process;
|
|
-struct library;
|
|
-
|
|
enum toplt {
|
|
LS_TOPLT_NONE = 0, /* PLT not used for this symbol. */
|
|
LS_TOPLT_EXEC, /* PLT for this symbol is executable. */
|
|
@@ -195,7 +194,7 @@ void library_add_symbol(struct library *lib, struct library_symbol *sym);
|
|
|
|
/* A function that can be used as proc_each_library callback. Looks
|
|
* for a library with the name passed in DATA. PROC is ignored. */
|
|
-enum callback_status library_named_cb(struct Process *proc,
|
|
+enum callback_status library_named_cb(struct process *proc,
|
|
struct library *lib, void *name);
|
|
|
|
/* A function that can be used as proc_each_library callback. Looks
|
|
@@ -203,7 +202,7 @@ enum callback_status library_named_cb(struct Process *proc,
|
|
*
|
|
* NOTE: The key is passed as a POINTER to arch_addr_t (that
|
|
* because in general, arch_addr_t doesn't fit in void*). */
|
|
-enum callback_status library_with_key_cb(struct Process *proc,
|
|
+enum callback_status library_with_key_cb(struct process *proc,
|
|
struct library *lib, void *keyp);
|
|
|
|
/* XXX this should really be in backend.h (as on pmachata/revamp
|
|
@@ -220,7 +219,7 @@ int arch_translate_address(struct ltelf *lte,
|
|
arch_addr_t addr, arch_addr_t *ret);
|
|
/* This is the same function as arch_translate_address, except it's
|
|
* used at the point that we don't have ELF available anymore. */
|
|
-int arch_translate_address_dyn(struct Process *proc,
|
|
+int arch_translate_address_dyn(struct process *proc,
|
|
arch_addr_t addr, arch_addr_t *ret);
|
|
|
|
#endif /* _LIBRARY_H_ */
|
|
diff --git a/ltrace-elf.c b/ltrace-elf.c
|
|
index c571d2a..1d0f769 100644
|
|
--- a/ltrace-elf.c
|
|
+++ b/ltrace-elf.c
|
|
@@ -40,6 +40,7 @@
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
+#include <strings.h>
|
|
#include <unistd.h>
|
|
|
|
#include "backend.h"
|
|
@@ -64,7 +65,7 @@ arch_elf_destroy(struct ltelf *lte)
|
|
#endif
|
|
|
|
int
|
|
-default_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
|
|
+default_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
|
|
const char *a_name, GElf_Rela *rela, size_t ndx,
|
|
struct library_symbol **ret)
|
|
{
|
|
@@ -101,11 +102,11 @@ default_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
|
|
|
|
#ifndef ARCH_HAVE_ADD_PLT_ENTRY
|
|
enum plt_status
|
|
-arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
|
|
+arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
|
|
const char *a_name, GElf_Rela *rela, size_t ndx,
|
|
struct library_symbol **ret)
|
|
{
|
|
- return plt_default;
|
|
+ return PLT_DEFAULT;
|
|
}
|
|
#endif
|
|
|
|
@@ -540,7 +541,7 @@ mark_chain_latent(struct library_symbol *libsym)
|
|
}
|
|
|
|
static int
|
|
-populate_plt(struct Process *proc, const char *filename,
|
|
+populate_plt(struct process *proc, const char *filename,
|
|
struct ltelf *lte, struct library *lib,
|
|
int latent_plts)
|
|
{
|
|
@@ -565,14 +566,14 @@ populate_plt(struct Process *proc, const char *filename,
|
|
struct library_symbol *libsym = NULL;
|
|
switch (arch_elf_add_plt_entry(proc, lte, name,
|
|
&rela, i, &libsym)) {
|
|
- case plt_default:
|
|
+ case PLT_DEFAULT:
|
|
if (default_elf_add_plt_entry(proc, lte, name,
|
|
&rela, i, &libsym) < 0)
|
|
/* fall-through */
|
|
- case plt_fail:
|
|
+ case PLT_FAIL:
|
|
return -1;
|
|
/* fall-through */
|
|
- case plt_ok:
|
|
+ case PLT_OK:
|
|
if (libsym != NULL) {
|
|
/* If we are adding those symbols just
|
|
* for tracing exports, mark them all
|
|
@@ -614,7 +615,7 @@ symbol_with_address(struct library_symbol *sym, void *addrptr)
|
|
}
|
|
|
|
static int
|
|
-populate_this_symtab(struct Process *proc, const char *filename,
|
|
+populate_this_symtab(struct process *proc, const char *filename,
|
|
struct ltelf *lte, struct library *lib,
|
|
Elf_Data *symtab, const char *strtab, size_t size,
|
|
struct library_exported_name **names)
|
|
@@ -777,7 +778,7 @@ populate_this_symtab(struct Process *proc, const char *filename,
|
|
}
|
|
|
|
static int
|
|
-populate_symtab(struct Process *proc, const char *filename,
|
|
+populate_symtab(struct process *proc, const char *filename,
|
|
struct ltelf *lte, struct library *lib,
|
|
int symtabs, int exports)
|
|
{
|
|
@@ -802,7 +803,7 @@ populate_symtab(struct Process *proc, const char *filename,
|
|
}
|
|
|
|
static int
|
|
-read_module(struct library *lib, struct Process *proc,
|
|
+read_module(struct library *lib, struct process *proc,
|
|
const char *filename, GElf_Addr bias, int main)
|
|
{
|
|
struct ltelf lte = {};
|
|
@@ -942,7 +943,7 @@ fail:
|
|
}
|
|
|
|
int
|
|
-ltelf_read_library(struct library *lib, struct Process *proc,
|
|
+ltelf_read_library(struct library *lib, struct process *proc,
|
|
const char *filename, GElf_Addr bias)
|
|
{
|
|
return read_module(lib, proc, filename, bias, 0);
|
|
@@ -950,7 +951,7 @@ ltelf_read_library(struct library *lib, struct Process *proc,
|
|
|
|
|
|
struct library *
|
|
-ltelf_read_main_binary(struct Process *proc, const char *path)
|
|
+ltelf_read_main_binary(struct process *proc, const char *path)
|
|
{
|
|
struct library *lib = malloc(sizeof(*lib));
|
|
if (lib == NULL)
|
|
diff --git a/ltrace-elf.h b/ltrace-elf.h
|
|
index 1a1321e..b76d1eb 100644
|
|
--- a/ltrace-elf.h
|
|
+++ b/ltrace-elf.h
|
|
@@ -26,11 +26,9 @@
|
|
|
|
#include <gelf.h>
|
|
#include <stdlib.h>
|
|
-#include "sysdep.h"
|
|
|
|
-struct Process;
|
|
-struct library;
|
|
-struct library_symbol;
|
|
+#include "forward.h"
|
|
+#include "sysdep.h"
|
|
|
|
/* XXX Ok, the original idea was to separate the low-level ELF data
|
|
* from the abstract "struct library" object, but we use some of the
|
|
@@ -73,21 +71,21 @@ void do_close_elf(struct ltelf *lte);
|
|
/* XXX is it possible to put breakpoints in VDSO and VSYSCALL
|
|
* pseudo-libraries? For now we assume that all libraries can be
|
|
* opened via a filesystem. BASE is ignored for ET_EXEC files. */
|
|
-int ltelf_read_library(struct library *lib, struct Process *proc,
|
|
+int ltelf_read_library(struct library *lib, struct process *proc,
|
|
const char *filename, GElf_Addr bias);
|
|
|
|
/* Create a library object representing the main binary. The entry
|
|
* point address is stored to *ENTRYP. */
|
|
-struct library *ltelf_read_main_binary(struct Process *proc, const char *path);
|
|
+struct library *ltelf_read_main_binary(struct process *proc, const char *path);
|
|
|
|
/* Create a default PLT entry. This can be used instead (or in
|
|
- * addition to) returning plt_default from arch_elf_add_plt_entry.
|
|
+ * addition to) returning PLT_DEFAULT from arch_elf_add_plt_entry.
|
|
* RET shall be initialized, the created symbol will be added to the
|
|
* beginning of the linked list at *RET. This function doesn't add
|
|
* the symbol to LTE. arch_elf_add_plt_entry has the chance to adjust
|
|
- * symbol internals to its liking, and then return either plt_default
|
|
- * or plt_ok. */
|
|
-int default_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
|
|
+ * symbol internals to its liking, and then return either PLT_DEFAULT
|
|
+ * or PLT_OK. */
|
|
+int default_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
|
|
const char *a_name, GElf_Rela *rela, size_t ndx,
|
|
struct library_symbol **ret);
|
|
|
|
diff --git a/ltrace.1 b/ltrace.1
|
|
index 8b459ee..7f3c5bc 100644
|
|
--- a/ltrace.1
|
|
+++ b/ltrace.1
|
|
@@ -1,5 +1,5 @@
|
|
.\" -*-nroff-*-
|
|
-.\" Copyright (c) 2012 Petr Machata, Red Hat Inc.
|
|
+.\" Copyright (c) 2012, 2013 Petr Machata, Red Hat Inc.
|
|
.\" Copyright (c) 1997-2005 Juan Cespedes <cespedes@debian.org>
|
|
.\"
|
|
.\" This program is free software; you can redistribute it and/or
|
|
@@ -17,13 +17,65 @@
|
|
.\" Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
.\" 02110-1301 USA
|
|
.\"
|
|
-.TH LTRACE "1" "October 2012" "" "User Commands"
|
|
+.TH LTRACE "1" "January 2013" "" "User Commands"
|
|
.SH NAME
|
|
ltrace \- A library call tracer
|
|
|
|
.SH SYNOPSIS
|
|
+.\"
|
|
+.\" ---------------------------------------------------------------------------
|
|
+.\"
|
|
+.PP
|
|
.B ltrace
|
|
-.I "[-bCfghiLrStttV] [-a column] [-A maxelts] [-D level] [-e expr] [-l library_pattern] [-n nr] [-o filename] [-p pid] ... [-s strsize] [-u username] [-w count] [-x extern] ... [--align=column] [--debug=level] [--demangle] [--help] [--indent=nr] [--library=library_pattern] [--no-signals] [--output=filename] [--version] [--where=NR] [command [arg ...]]"
|
|
+.\"
|
|
+.\" What events to trace:
|
|
+.\"
|
|
+[\-e \fIfilter\fR|\-L] [\-l|\-\-library=\fIlibrary_pattern\fR]
|
|
+[\-x \fIfilter\fR] [\-S] [\-b|\-\-no-signals]
|
|
+.\"
|
|
+.\" What to display with each event:
|
|
+.\"
|
|
+[\-i] [\-w|\-\-where=\fInr\fR] [\-r|\-t|\-tt|\-ttt] [\-T]
|
|
+.\"
|
|
+.\" Output formatting:
|
|
+.\"
|
|
+[\-F \fIfilename\fR]
|
|
+[\-A \fImaxelts\fR] [\-s \fIstrsize\fR] [\-C|\-\-demangle]
|
|
+[\-a|\-\-align \fIcolumn\fR] [\-n|\-\-indent \fInr\fR]
|
|
+[\-o|\-\-output \fIfilename\fR]
|
|
+.\"
|
|
+.\" Various:
|
|
+.\"
|
|
+[\-D|\-\-debug \fImask\fR] [\-u \fIusername\fR]
|
|
+.\"
|
|
+.\" What processes to trace:
|
|
+.\"
|
|
+[\-f] [\-p \fIpid\fR] [[\-\-] \fIcommand [arg ...]\fR]
|
|
+.\"
|
|
+.\" ---------------------------------------------------------------------------
|
|
+.\"
|
|
+.PP
|
|
+.BR ltrace " -c"
|
|
+.\"
|
|
+.\" What events to trace:
|
|
+.\"
|
|
+[\-e \fIfilter\fR|\-L] [\-l|\-\-library=\fIlibrary_pattern\fR]
|
|
+[\-x \fIfilter\fR] [\-S]
|
|
+.\"
|
|
+.\" Output formatting:
|
|
+.\"
|
|
+[\-o|\-\-output \fIfilename\fR]
|
|
+.\"
|
|
+.\" What processes to trace:
|
|
+.\"
|
|
+[\-f] [\-p \fIpid\fR] [[\-\-] \fIcommand [arg ...]\fR]
|
|
+.\"
|
|
+.\" ---------------------------------------------------------------------------
|
|
+.\"
|
|
+.PP
|
|
+.BR ltrace " \-V|\-\-version"
|
|
+.PP
|
|
+.BR ltrace " \-h|\-\-help"
|
|
|
|
.SH DESCRIPTION
|
|
.B ltrace
|
|
@@ -38,77 +90,51 @@ Its use is very similar to
|
|
.BR strace(1) .
|
|
|
|
.SH OPTIONS
|
|
-.TP
|
|
-.I \-a, \-\-align column
|
|
+.PP
|
|
+.IP "\-a, \-\-align \fIcolumn"
|
|
Align return values in a specific
|
|
.IR column
|
|
(default column is 5/8 of screen width).
|
|
-.TP
|
|
-.I \-A maxelts
|
|
+.IP "\-A \fImaxelts"
|
|
Maximum number of array elements to print before suppressing the rest
|
|
with an ellipsis ("..."). This also limits number of recursive
|
|
structure expansions.
|
|
-.TP
|
|
-.I \-b, \-\-no-signals
|
|
+.IP "\-b, \-\-no-signals"
|
|
Disable printing of signals recieved by the traced process.
|
|
-.TP
|
|
-.I \-c
|
|
-Count time and calls for each library call and report a summary on program exit.
|
|
-.TP
|
|
-.I \-C, \-\-demangle
|
|
+.IP \-c
|
|
+Count time and calls for each library call and report a summary on
|
|
+program exit.
|
|
+.IP "\-C, \-\-demangle"
|
|
Decode (demangle) low-level symbol names into user-level names.
|
|
Besides removing any initial underscore prefix used by the system,
|
|
this makes C++ function names readable.
|
|
-.TP
|
|
-.I \-D, \-\-debug level
|
|
-Show debugging output of
|
|
-.B ltrace
|
|
-itself.
|
|
-.I level
|
|
-must be a sum of some of the following numbers:
|
|
-.RS
|
|
-.TP
|
|
-.B 01
|
|
-DEBUG_GENERAL. Shows helpful progress information
|
|
-.TP
|
|
-.B 010
|
|
-DEBUG_EVENT. Shows every event received by a traced program
|
|
-.TP
|
|
-.B 020
|
|
-DEBUG_PROCESS. Shows every action
|
|
-.B ltrace
|
|
-carries upon a traced process
|
|
-.TP
|
|
-.B 040
|
|
-DEBUG_FUNCTION. Shows every entry to internal functions
|
|
-.RE
|
|
-.TP
|
|
-.I \-e filter
|
|
+.IP "\-D, \-\-debug \fRmask\fI"
|
|
+Show debugging output of \fBltrace\fR itself. \fImask\fR is a number
|
|
+with internal meaning that's not really well defined at all.
|
|
+\fImask\fR of 77 shows all debug messages, which is what you usually
|
|
+need.
|
|
+.IP "\-e \fIfilter"
|
|
A qualifying expression which modifies which library calls to trace.
|
|
The format of the filter expression is described in the section
|
|
\fBFILTER EXPRESSIONS\fR. If more than one \-e option appears on the
|
|
command line, the library calls that match any of them are traced. If
|
|
no \-e is given, \fB@MAIN\fR is assumed as a default.
|
|
-.TP
|
|
-.I \-f
|
|
+.IP \-f
|
|
Trace child processes as they are created by
|
|
currently traced processes as a result of the fork(2)
|
|
or clone(2) system calls.
|
|
The new process is attached immediately.
|
|
-.TP
|
|
-.I \-F
|
|
+.IP "\-F \fIfilename"
|
|
Load an alternate config file. Normally, /etc/ltrace.conf and
|
|
-~/.ltrace.conf will be read (the latter only if it exists).
|
|
-Use this option to load the given file or files instead of
|
|
-those two default files.
|
|
-.TP
|
|
-.I \-h, \-\-help
|
|
+~/.ltrace.conf will be read (the latter only if it exists). Use this
|
|
+option to load the given file or files instead of those two default
|
|
+files. See ltrace.conf(5) for details on the syntax of ltrace
|
|
+configuration files.
|
|
+.IP "\-h, \-\-help"
|
|
Show a summary of the options to ltrace and exit.
|
|
-.TP
|
|
-.I \-i
|
|
+.IP \-i
|
|
Print the instruction pointer at the time of the library call.
|
|
-.TP
|
|
-.I \-l, \-\-library library_pattern
|
|
+.IP "\-l, \-\-library \fIlibrary_pattern"
|
|
Display only calls to functions implemented by libraries that match
|
|
.I library_pattern.
|
|
Multiple library patters can be specified with several instances of
|
|
@@ -120,71 +146,55 @@ the selected libraries, there's no actual guarantee that the call
|
|
won't be directed elsewhere due to e.g. LD_PRELOAD or simply
|
|
dependency ordering. If you want to make sure that symbols in given
|
|
library are actually called, use \fB-x @\fIlibrary_pattern\fR instead.
|
|
-.TP
|
|
-.I \-L
|
|
+.IP \-L
|
|
When no -e option is given, don't assume the default action of
|
|
\fB@MAIN\fR.
|
|
-.TP
|
|
-.I \-n, \-\-indent nr
|
|
-Indent trace output by
|
|
-.I nr
|
|
-number of spaces for each new nested call. Using this option makes
|
|
-the program flow visualization easy to follow.
|
|
-.TP
|
|
-.I \-o, \-\-output filename
|
|
-Write the trace output to the file
|
|
-.I filename
|
|
-rather than to stderr.
|
|
-.TP
|
|
-.I \-p pid
|
|
-Attach to the process with the process ID
|
|
-.I pid
|
|
-and begin tracing.
|
|
-.TP
|
|
-.I \-r
|
|
-Print a relative timestamp with each line of the trace.
|
|
-This records the time difference between the beginning of
|
|
-successive lines.
|
|
-.TP
|
|
-.I \-s strsize
|
|
+.IP "\-n, \-\-indent \fInr"
|
|
+Indent trace output by \fInr\fR spaces for each level of call
|
|
+nesting. Using this option makes the program flow visualization easy
|
|
+to follow. This indents uselessly also functions that never return,
|
|
+such as service functions for throwing exceptions in the C++ runtime.
|
|
+.IP "\-o, \-\-output \fIfilename"
|
|
+Write the trace output to the file \fIfilename\fR rather than to
|
|
+stderr.
|
|
+.IP "\-p \fIpid"
|
|
+Attach to the process with the process ID \fIpid\fR and begin tracing.
|
|
+This option can be used together with passing a command to execute.
|
|
+It is possible to attach to several processes by passing more than one
|
|
+option \-p.
|
|
+.IP \-r
|
|
+Print a relative timestamp with each line of the trace. This records
|
|
+the time difference between the beginning of successive lines.
|
|
+.IP "\-s \fIstrsize"
|
|
Specify the maximum string size to print (the default is 32).
|
|
-.TP
|
|
-.I \-S
|
|
+.IP \-S
|
|
Display system calls as well as library calls
|
|
-.TP
|
|
-.I \-t
|
|
+.IP \-t
|
|
Prefix each line of the trace with the time of day.
|
|
-.TP
|
|
-.I \-tt
|
|
+.IP \-tt
|
|
If given twice, the time printed will include the microseconds.
|
|
-.TP
|
|
-.I \-ttt
|
|
+.IP \-ttt
|
|
If given thrice, the time printed will include the microseconds and
|
|
the leading portion will be printed as the number of seconds since the
|
|
epoch.
|
|
-.TP
|
|
-.I \-T
|
|
+.IP \-T
|
|
Show the time spent inside each call. This records the time difference
|
|
between the beginning and the end of each call.
|
|
-.TP
|
|
-.I \-u username
|
|
+.IP "\-u \fIusername"
|
|
Run command with the userid, groupid and supplementary groups of
|
|
.IR username .
|
|
This option is only useful when running as root and enables the
|
|
correct execution of setuid and/or setgid binaries.
|
|
-.TP
|
|
-.I \-w, --where NR
|
|
-Show backtrace of NR stack frames for each traced function. This option enabled
|
|
-only if libunwind support was enabled at compile time.
|
|
-.TP
|
|
-.I \-x filter
|
|
+.IP "\-w, --where \fInr"
|
|
+Show backtrace of \fInr\fR stack frames for each traced function. This
|
|
+option enabled only if libunwind support was enabled at compile time.
|
|
+.IP "\-x \fIfilter"
|
|
A qualifying expression which modifies which symbol table entry points
|
|
to trace. The format of the filter expression is described in the
|
|
section \fBFILTER EXPRESSIONS\fR. If more than one \-x option appears
|
|
on the command line, the symbols that match any of them are traced.
|
|
No entry points are traced if no \-x is given.
|
|
-.TP
|
|
-.I \-V, \-\-version
|
|
+.IP "\-V, \-\-version"
|
|
Show the version number of ltrace and exit.
|
|
|
|
.SH FILTER EXPRESSIONS
|
|
@@ -235,7 +245,8 @@ path name.
|
|
|
|
The first rule may lack a sign, in which case \fB+\fR is assumed. If,
|
|
on the other hand, the first rule has a \fB-\fR sign, it is as if
|
|
-there was another rule \fB@*\fR in front of it.
|
|
+there was another rule \fB@\fR in front of it, which has the effect of
|
|
+tracing complement of given rule.
|
|
|
|
The above rules are used to construct the set of traced symbols. Each
|
|
candidate symbol is passed through the chain of above rules.
|
|
diff --git a/ltrace.h b/ltrace.h
|
|
index ee7e27b..3e714a8 100644
|
|
--- a/ltrace.h
|
|
+++ b/ltrace.h
|
|
@@ -44,7 +44,7 @@ enum Event_type {
|
|
typedef struct Event Event;
|
|
struct Event {
|
|
struct Event * next;
|
|
- struct Process * proc;
|
|
+ struct process *proc;
|
|
Event_type type;
|
|
union {
|
|
int ret_val; /* EVENT_EXIT */
|
|
diff --git a/ltrace.spec b/ltrace.spec
|
|
deleted file mode 100644
|
|
index 3740190..0000000
|
|
--- a/ltrace.spec
|
|
+++ /dev/null
|
|
@@ -1,164 +0,0 @@
|
|
-Summary: Tracks runtime library calls from dynamically linked executables.
|
|
-Name: ltrace
|
|
-Version: 0.3.36
|
|
-Release: 4.2
|
|
-Source: ftp://ftp.debian.org/debian/pool/main/l/ltrace/ltrace_%{version}.orig.tar.gz
|
|
-Patch1: ftp://ftp.debian.org/debian/pool/main/l/ltrace/ltrace_0.3.36-2.diff.gz
|
|
-Patch2: ltrace-ppc64.patch
|
|
-Patch3: ltrace-ppc64-2.patch
|
|
-Patch4: ltrace-s390x.patch
|
|
-Patch5: ltrace-syscallent-update.patch
|
|
-Patch6: ltrace-fixes.patch
|
|
-Patch7: ltrace-ia64.patch
|
|
-License: GPL
|
|
-Group: Development/Debuggers
|
|
-ExclusiveArch: i386 x86_64 ia64 ppc ppc64 s390 s390x alpha sparc
|
|
-Prefix: %{_prefix}
|
|
-BuildRoot: /var/tmp/%{name}-root
|
|
-BuildRequires: elfutils-libelf-devel
|
|
-
|
|
-%description
|
|
-Ltrace is a debugging program which runs a specified command until the
|
|
-command exits. While the command is executing, ltrace intercepts and
|
|
-records both the dynamic library calls called by the executed process
|
|
-and the signals received by the executed process. Ltrace can also
|
|
-intercept and print system calls executed by the process.
|
|
-
|
|
-You should install ltrace if you need a sysadmin tool for tracking the
|
|
-execution of processes.
|
|
-
|
|
-%prep
|
|
-%setup -q
|
|
-%patch1 -p1
|
|
-%patch2 -p1
|
|
-%patch3 -p1
|
|
-%patch4 -p1
|
|
-%patch5 -p1
|
|
-%patch6 -p1
|
|
-%patch7 -p1
|
|
-sed -i -e 's/-o root -g root//' Makefile.in
|
|
-
|
|
-%build
|
|
-export CC="gcc`echo $RPM_OPT_FLAGS | sed -n 's/^.*\(-m[36][124]\).*$/ \1/p'`"
|
|
-%configure CC="$CC"
|
|
-make
|
|
-
|
|
-%install
|
|
-make DESTDIR=$RPM_BUILD_ROOT mandir=%{_mandir} install
|
|
-rm -f ChangeLog; mv -f debian/changelog ChangeLog
|
|
-rm -rf $RPM_BUILD_ROOT/%{_prefix}/doc
|
|
-
|
|
-%clean
|
|
-rm -rf $RPM_BUILD_ROOT
|
|
-
|
|
-%files
|
|
-%defattr(-,root,root)
|
|
-%doc COPYING README TODO BUGS ChangeLog
|
|
-%{_prefix}/bin/ltrace
|
|
-%{_mandir}/man1/ltrace.1*
|
|
-%config /etc/ltrace.conf
|
|
-
|
|
-%changelog
|
|
-* Fri Feb 10 2006 Jesse Keating <jkeating@redhat.com> - 0.3.36-4.2
|
|
-- bump again for double-long bug on ppc(64)
|
|
-
|
|
-* Tue Feb 07 2006 Jesse Keating <jkeating@redhat.com> - 0.3.36-4.1
|
|
-- rebuilt for new gcc4.1 snapshot and glibc changes
|
|
-
|
|
-* Mon Jan 9 2006 Jakub Jelinek <jakub@redhat.com> 0.3.36-4
|
|
-- added ppc64 and s390x support (IBM)
|
|
-- added ia64 support (Ian Wienand)
|
|
-
|
|
-* Sat Mar 5 2005 Jakub Jelinek <jakub@redhat.com> 0.3.36-3
|
|
-- rebuilt with GCC 4
|
|
-
|
|
-* Tue Dec 14 2004 Jakub Jelinek <jakub@redhat.com> 0.3.36-2
|
|
-- make x86_64 ltrace trace both 32-bit and 64-bit binaries (#141955,
|
|
- IT#55600)
|
|
-- fix tracing across execve
|
|
-- fix printf-style format handling on 64-bit arches
|
|
-
|
|
-* Thu Nov 18 2004 Jakub Jelinek <jakub@redhat.com> 0.3.36-1
|
|
-- update to 0.3.36
|
|
-
|
|
-* Mon Oct 11 2004 Jakub Jelinek <jakub@redhat.com> 0.3.35-1
|
|
-- update to 0.3.35
|
|
-- update syscall tables from latest kernel source
|
|
-
|
|
-* Tue Jun 15 2004 Elliot Lee <sopwith@redhat.com>
|
|
-- rebuilt
|
|
-
|
|
-* Tue Jun 8 2004 Jakub Jelinek <jakub@redhat.com> 0.3.32-3
|
|
-- buildreq elfutils-libelf-devel (#124921)
|
|
-
|
|
-* Thu Apr 22 2004 Jakub Jelinek <jakub@redhat.com> 0.3.32-2
|
|
-- fix demangling
|
|
-
|
|
-* Thu Apr 22 2004 Jakub Jelinek <jakub@redhat.com> 0.3.32-1
|
|
-- update to 0.3.32
|
|
- - fix dict.c assertion (#114359)
|
|
- - x86_64 support
|
|
-- rewrite elf.[ch] using libelf
|
|
-- don't rely on st_value of SHN_UNDEF symbols in binaries,
|
|
- instead walk .rel{,a}.plt and compute the addresses (#115299)
|
|
-- fix x86-64 support
|
|
-- some ltrace.conf additions
|
|
-- some format string printing fixes
|
|
-
|
|
-* Fri Feb 13 2004 Elliot Lee <sopwith@redhat.com>
|
|
-- rebuilt
|
|
-
|
|
-* Mon Feb 3 2003 Jakub Jelinek <jakub@redhat.com> 0.3.29-1
|
|
-- update to 0.3.29
|
|
-
|
|
-* Wed Jan 22 2003 Tim Powers <timp@redhat.com>
|
|
-- rebuilt
|
|
-
|
|
-* Sun Sep 1 2002 Jakub Jelinek <jakub@redhat.com> 0.3.10-12
|
|
-- add a bunch of missing functions to ltrace.conf
|
|
- (like strlen, ugh)
|
|
-
|
|
-* Fri Jun 21 2002 Tim Powers <timp@redhat.com>
|
|
-- automated rebuild
|
|
-
|
|
-* Tue May 28 2002 Phil Knirsch <pknirsch@redhat.com>
|
|
-- Added the 'official' s390 patch.
|
|
-
|
|
-* Thu May 23 2002 Tim Powers <timp@redhat.com>
|
|
-- automated rebuild
|
|
-
|
|
-* Wed Jan 09 2002 Tim Powers <timp@redhat.com>
|
|
-- automated rebuild
|
|
-
|
|
-* Fri Jul 20 2001 Jakub Jelinek <jakub@redhat.com>
|
|
-- fix stale symlink in documentation directory (#47749)
|
|
-
|
|
-* Sun Jun 24 2001 Elliot Lee <sopwith@redhat.com>
|
|
-- Bump release + rebuild.
|
|
-
|
|
-* Thu Aug 2 2000 Tim Waugh <twaugh@redhat.com>
|
|
-- fix off-by-one problem in checking syscall number
|
|
-
|
|
-* Wed Jul 12 2000 Prospector <bugzilla@redhat.com>
|
|
-- automatic rebuild
|
|
-
|
|
-* Mon Jun 19 2000 Matt Wilson <msw@redhat.com>
|
|
-- rebuilt for next release
|
|
-- patched Makefile.in to take a hint on mandir (patch2)
|
|
-- use %%{_mandir} and %%makeinstall
|
|
-
|
|
-* Wed Feb 02 2000 Cristian Gafton <gafton@redhat.com>
|
|
-- fix description
|
|
-
|
|
-* Fri Jan 7 2000 Jeff Johnson <jbj@redhat.com>
|
|
-- update to 0.3.10.
|
|
-- include (but don't apply) sparc patch from Jakub Jellinek.
|
|
-
|
|
-* Sun Mar 21 1999 Cristian Gafton <gafton@redhat.com>
|
|
-- auto rebuild in the new build environment (release 2)
|
|
-
|
|
-* Fri Mar 12 1999 Jeff Johnson <jbj@redhat.com>
|
|
-- update to 0.3.6.
|
|
-
|
|
-* Mon Sep 21 1998 Preston Brown <pbrown@redhat.com>
|
|
-- upgraded to 0.3.4
|
|
diff --git a/memstream.c b/memstream.c
|
|
new file mode 100644
|
|
index 0000000..ac3f31a
|
|
--- /dev/null
|
|
+++ b/memstream.c
|
|
@@ -0,0 +1,73 @@
|
|
+/*
|
|
+ * This file is part of ltrace.
|
|
+ * Copyright (C) 2012 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
|
|
+ */
|
|
+
|
|
+/* _GNU_SOURCE may be necessary for open_memstream visibility (see
|
|
+ * configure.ac), and there's no harm defining it just in case. */
|
|
+#define _GNU_SOURCE
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+
|
|
+#include "config.h"
|
|
+#include "memstream.h"
|
|
+
|
|
+int
|
|
+memstream_init(struct memstream *memstream)
|
|
+{
|
|
+#if HAVE_OPEN_MEMSTREAM
|
|
+ memstream->stream = open_memstream(&memstream->buf,
|
|
+ &memstream->size);
|
|
+#else
|
|
+ memstream->stream = tmpfile();
|
|
+#endif
|
|
+ memstream->buf = NULL;
|
|
+ return memstream->stream != NULL ? 0 : -1;
|
|
+}
|
|
+
|
|
+int
|
|
+memstream_close(struct memstream *memstream)
|
|
+{
|
|
+#if !defined(HAVE_OPEN_MEMSTREAM) || !HAVE_OPEN_MEMSTREAM
|
|
+ if (fseek(memstream->stream, 0, SEEK_END) < 0) {
|
|
+ fail:
|
|
+ fclose(memstream->stream);
|
|
+ return -1;
|
|
+ }
|
|
+ memstream->size = ftell(memstream->stream);
|
|
+ if (memstream->size == (size_t)-1)
|
|
+ goto fail;
|
|
+ memstream->buf = malloc(memstream->size);
|
|
+ if (memstream->buf == NULL)
|
|
+ goto fail;
|
|
+
|
|
+ rewind(memstream->stream);
|
|
+ if (fread(memstream->buf, 1, memstream->size, memstream->stream)
|
|
+ < memstream->size)
|
|
+ goto fail;
|
|
+#endif
|
|
+
|
|
+ return fclose(memstream->stream) == 0 ? 0 : -1;
|
|
+}
|
|
+
|
|
+void
|
|
+memstream_destroy(struct memstream *memstream)
|
|
+{
|
|
+ free(memstream->buf);
|
|
+}
|
|
diff --git a/memstream.h b/memstream.h
|
|
new file mode 100644
|
|
index 0000000..eb06541
|
|
--- /dev/null
|
|
+++ b/memstream.h
|
|
@@ -0,0 +1,35 @@
|
|
+/*
|
|
+ * This file is part of ltrace.
|
|
+ * Copyright (C) 2012 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
|
|
+ */
|
|
+
|
|
+#include <stdio.h>
|
|
+
|
|
+/* Portability wrapper for platforms that don't have
|
|
+ * open_memstream. */
|
|
+
|
|
+struct memstream
|
|
+{
|
|
+ FILE *stream;
|
|
+ char *buf;
|
|
+ size_t size;
|
|
+};
|
|
+
|
|
+int memstream_init(struct memstream *memstream);
|
|
+int memstream_close(struct memstream *memstream);
|
|
+void memstream_destroy(struct memstream *memstream);
|
|
diff --git a/options.c b/options.c
|
|
index e8fd2a2..eaf32fa 100644
|
|
--- a/options.c
|
|
+++ b/options.c
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
* This file is part of ltrace.
|
|
- * Copyright (C) 2012 Petr Machata, Red Hat Inc.
|
|
+ * Copyright (C) 2012, 2013 Petr Machata, Red Hat Inc.
|
|
* Copyright (C) 2009,2010 Joe Damato
|
|
* Copyright (C) 1998,1999,2002,2003,2004,2007,2008,2009 Juan Cespedes
|
|
* Copyright (C) 2006 Ian Wienand
|
|
@@ -86,27 +86,27 @@ usage(void) {
|
|
fprintf(stdout, "Usage: %s [option ...] [command [arg ...]]\n"
|
|
"Trace library calls of a given program.\n\n"
|
|
" -a, --align=COLUMN align return values in a secific column.\n"
|
|
- " -A ARRAYLEN maximum number of array elements to print.\n"
|
|
+ " -A MAXELTS maximum number of array elements to print.\n"
|
|
" -b, --no-signals don't print signals.\n"
|
|
" -c count time and calls, and report a summary on exit.\n"
|
|
# ifdef USE_DEMANGLE
|
|
" -C, --demangle decode low-level symbol names into user-level names.\n"
|
|
# endif
|
|
- " -D, --debug=LEVEL enable debugging (see -Dh or --debug=help).\n"
|
|
+ " -D, --debug=MASK enable debugging (see -Dh or --debug=help).\n"
|
|
" -Dh, --debug=help show help on debugging.\n"
|
|
- " -e expr modify which events to trace.\n"
|
|
+ " -e FILTER modify which library calls to trace.\n"
|
|
" -f trace children (fork() and clone()).\n"
|
|
" -F, --config=FILE load alternate configuration file (may be repeated).\n"
|
|
" -h, --help display this help and exit.\n"
|
|
" -i print instruction pointer at time of library call.\n"
|
|
- " -l, --library=FILE only trace symbols implemented by this library.\n"
|
|
+ " -l, --library=LIBRARY_PATTERN only trace symbols implemented by this library.\n"
|
|
" -L do NOT display library calls.\n"
|
|
" -n, --indent=NR indent output by NR spaces for each call level nesting.\n"
|
|
- " -o, --output=FILE write the trace output to that file.\n"
|
|
+ " -o, --output=FILENAME write the trace output to file with given name.\n"
|
|
" -p PID attach to the process with the process ID pid.\n"
|
|
" -r print relative timestamps.\n"
|
|
- " -s STRLEN specify the maximum string size to print.\n"
|
|
- " -S display system calls.\n"
|
|
+ " -s STRSIZE specify the maximum string size to print.\n"
|
|
+ " -S trace system calls as well as library calls.\n"
|
|
" -t, -tt, -ttt print absolute timestamps.\n"
|
|
" -T show the time spent inside each call.\n"
|
|
" -u USERNAME run command with the userid, groupid of username.\n"
|
|
@@ -114,7 +114,7 @@ usage(void) {
|
|
#if defined(HAVE_LIBUNWIND)
|
|
" -w, --where=NR print backtrace showing NR stack frames at most.\n"
|
|
#endif /* defined(HAVE_LIBUNWIND) */
|
|
- " -x NAME treat the global NAME like a library subroutine.\n"
|
|
+ " -x FILTER modify which static functions to trace.\n"
|
|
"\nReport bugs to ltrace-devel@lists.alioth.debian.org\n",
|
|
progname);
|
|
}
|
|
@@ -204,7 +204,7 @@ compile_libname(const char *expr, const char *a_lib, int lib_re_p,
|
|
|
|
regex_t lib_re;
|
|
int status = (lib_re_p ? regcomp : globcomp)(&lib_re, lib, 0);
|
|
- if (status != REG_NOERROR) {
|
|
+ if (status != 0) {
|
|
char buf[100];
|
|
regerror(status, &lib_re, buf, sizeof buf);
|
|
fprintf(stderr, "Rule near '%s' will be ignored: %s.\n",
|
|
@@ -459,6 +459,7 @@ process_options(int argc, char **argv)
|
|
while (1) {
|
|
int c;
|
|
char *p;
|
|
+#ifdef HAVE_GETOPT_LONG
|
|
int option_index = 0;
|
|
static struct option long_options[] = {
|
|
{"align", 1, 0, 'a'},
|
|
@@ -466,28 +467,34 @@ process_options(int argc, char **argv)
|
|
{"debug", 1, 0, 'D'},
|
|
# ifdef USE_DEMANGLE
|
|
{"demangle", 0, 0, 'C'},
|
|
-#endif
|
|
+# endif
|
|
{"indent", 1, 0, 'n'},
|
|
{"help", 0, 0, 'h'},
|
|
{"library", 1, 0, 'l'},
|
|
{"output", 1, 0, 'o'},
|
|
{"version", 0, 0, 'V'},
|
|
{"no-signals", 0, 0, 'b'},
|
|
-#if defined(HAVE_LIBUNWIND)
|
|
+# if defined(HAVE_LIBUNWIND)
|
|
{"where", 1, 0, 'w'},
|
|
-#endif /* defined(HAVE_LIBUNWIND) */
|
|
+# endif /* defined(HAVE_LIBUNWIND) */
|
|
{0, 0, 0, 0}
|
|
};
|
|
- c = getopt_long(argc, argv, "+cfhiLrStTVb"
|
|
-# ifdef USE_DEMANGLE
|
|
- "C"
|
|
-# endif
|
|
+#endif
|
|
+
|
|
+ const char *opts = "+"
|
|
+#ifdef USE_DEMANGLE
|
|
+ "C"
|
|
+#endif
|
|
#if defined(HAVE_LIBUNWIND)
|
|
- "a:A:D:e:F:l:n:o:p:s:u:x:X:w:", long_options,
|
|
-#else /* !defined(HAVE_LIBUNWIND) */
|
|
- "a:A:D:e:F:l:n:o:p:s:u:x:X:", long_options,
|
|
+ "w:"
|
|
+#endif
|
|
+ "cfhiLrStTVba:A:D:e:F:l:n:o:p:s:u:x:X:";
|
|
+
|
|
+#ifdef HAVE_GETOPT_LONG
|
|
+ c = getopt_long(argc, argv, opts, long_options, &option_index);
|
|
+#else
|
|
+ c = getopt(argc, argv, opts);
|
|
#endif
|
|
- &option_index);
|
|
if (c == -1) {
|
|
break;
|
|
}
|
|
@@ -610,10 +617,12 @@ process_options(int argc, char **argv)
|
|
options.user = optarg;
|
|
break;
|
|
case 'V':
|
|
- printf("ltrace version " PACKAGE_VERSION ".\n"
|
|
- "Copyright (C) 1997-2009 Juan Cespedes <cespedes@debian.org>.\n"
|
|
- "This is free software; see the GNU General Public Licence\n"
|
|
- "version 2 or later for copying conditions. There is NO warranty.\n");
|
|
+ printf("ltrace " PACKAGE_VERSION "\n"
|
|
+ "Copyright (C) 2010-2012 Petr Machata, Red Hat Inc.\n"
|
|
+ "Copyright (C) 1997-2009 Juan Cespedes <cespedes@debian.org>.\n"
|
|
+ "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\n"
|
|
+ "This is free software: you are free to change and redistribute it.\n"
|
|
+ "There is NO WARRANTY, to the extent permitted by law.\n");
|
|
exit(0);
|
|
break;
|
|
#if defined(HAVE_LIBUNWIND)
|
|
diff --git a/output.c b/output.c
|
|
index 1d01d31..fe62bb4 100644
|
|
--- a/output.c
|
|
+++ b/output.c
|
|
@@ -22,10 +22,6 @@
|
|
* 02110-1301 USA
|
|
*/
|
|
|
|
-/* glibc before 2.10, eglibc and uClibc all need _GNU_SOURCE defined
|
|
- * for open_memstream to become visible. */
|
|
-#define _GNU_SOURCE
|
|
-
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
@@ -47,25 +43,26 @@
|
|
#include "param.h"
|
|
#include "fetch.h"
|
|
#include "lens_default.h"
|
|
+#include "memstream.h"
|
|
|
|
/* TODO FIXME XXX: include in common.h: */
|
|
extern struct timeval current_time_spent;
|
|
|
|
Dict *dict_opt_c = NULL;
|
|
|
|
-static Process *current_proc = 0;
|
|
+static struct process *current_proc = 0;
|
|
static size_t current_depth = 0;
|
|
static int current_column = 0;
|
|
|
|
static void
|
|
-output_indent(struct Process *proc)
|
|
+output_indent(struct process *proc)
|
|
{
|
|
int d = options.indent * (proc->callstack_depth - 1);
|
|
current_column += fprintf(options.output, "%*s", d, "");
|
|
}
|
|
|
|
static void
|
|
-begin_of_line(Process *proc, int is_func, int indent)
|
|
+begin_of_line(struct process *proc, int is_func, int indent)
|
|
{
|
|
current_column = 0;
|
|
if (!proc) {
|
|
@@ -208,7 +205,7 @@ name2func(char const *name) {
|
|
}
|
|
|
|
void
|
|
-output_line(struct Process *proc, const char *fmt, ...)
|
|
+output_line(struct process *proc, const char *fmt, ...)
|
|
{
|
|
if (options.summary)
|
|
return;
|
|
@@ -248,7 +245,8 @@ output_error(FILE *stream)
|
|
}
|
|
|
|
static int
|
|
-fetch_simple_param(enum tof type, Process *proc, struct fetch_context *context,
|
|
+fetch_simple_param(enum tof type, struct process *proc,
|
|
+ struct fetch_context *context,
|
|
struct value_dict *arguments,
|
|
struct arg_type_info *info, int own,
|
|
struct value *valuep)
|
|
@@ -290,7 +288,8 @@ fetch_param_stop(struct value_dict *arguments, ssize_t *params_leftp)
|
|
}
|
|
|
|
static int
|
|
-fetch_param_pack(enum tof type, Process *proc, struct fetch_context *context,
|
|
+fetch_param_pack(enum tof type, struct process *proc,
|
|
+ struct fetch_context *context,
|
|
struct value_dict *arguments, struct param *param,
|
|
ssize_t *params_leftp)
|
|
{
|
|
@@ -343,7 +342,8 @@ fetch_param_pack(enum tof type, Process *proc, struct fetch_context *context,
|
|
}
|
|
|
|
static int
|
|
-fetch_one_param(enum tof type, Process *proc, struct fetch_context *context,
|
|
+fetch_one_param(enum tof type, struct process *proc,
|
|
+ struct fetch_context *context,
|
|
struct value_dict *arguments, struct param *param,
|
|
ssize_t *params_leftp)
|
|
{
|
|
@@ -372,7 +372,8 @@ fetch_one_param(enum tof type, Process *proc, struct fetch_context *context,
|
|
}
|
|
|
|
static int
|
|
-fetch_params(enum tof type, Process *proc, struct fetch_context *context,
|
|
+fetch_params(enum tof type, struct process *proc,
|
|
+ struct fetch_context *context,
|
|
struct value_dict *arguments, Function *func, ssize_t *params_leftp)
|
|
{
|
|
size_t i;
|
|
@@ -424,7 +425,7 @@ output_params(struct value_dict *arguments, size_t start, size_t end,
|
|
}
|
|
|
|
void
|
|
-output_left(enum tof type, struct Process *proc,
|
|
+output_left(enum tof type, struct process *proc,
|
|
struct library_symbol *libsym)
|
|
{
|
|
const char *function_name = libsym->name;
|
|
@@ -499,7 +500,7 @@ output_left(enum tof type, struct Process *proc,
|
|
}
|
|
|
|
void
|
|
-output_right(enum tof type, struct Process *proc, struct library_symbol *libsym)
|
|
+output_right(enum tof type, struct process *proc, struct library_symbol *libsym)
|
|
{
|
|
const char *function_name = libsym->name;
|
|
Function *func = name2func(function_name);
|
|
@@ -640,18 +641,18 @@ delim_output(FILE *stream, int *need_delimp,
|
|
o = writer(stream, data);
|
|
|
|
} else {
|
|
- char *buf;
|
|
- size_t bufsz;
|
|
- FILE *tmp = open_memstream(&buf, &bufsz);
|
|
- o = writer(tmp, data);
|
|
- fclose(tmp);
|
|
-
|
|
+ struct memstream ms;
|
|
+ if (memstream_init(&ms) < 0)
|
|
+ return -1;
|
|
+ o = writer(ms.stream, data);
|
|
+ if (memstream_close(&ms) < 0)
|
|
+ o = -1;
|
|
if (o > 0 && ((*need_delimp
|
|
&& account_output(&o, fprintf(stream, ", ")) < 0)
|
|
- || fwrite(buf, 1, bufsz, stream) != bufsz))
|
|
+ || fwrite(ms.buf, 1, ms.size, stream) != ms.size))
|
|
o = -1;
|
|
|
|
- free(buf);
|
|
+ memstream_destroy(&ms);
|
|
}
|
|
|
|
if (o < 0)
|
|
diff --git a/output.h b/output.h
|
|
index 0d16657..b9f0518 100644
|
|
--- a/output.h
|
|
+++ b/output.h
|
|
@@ -24,10 +24,10 @@
|
|
#include "fetch.h"
|
|
#include "forward.h"
|
|
|
|
-void output_line(struct Process *proc, const char *fmt, ...);
|
|
-void output_left(enum tof type, struct Process *proc,
|
|
+void output_line(struct process *proc, const char *fmt, ...);
|
|
+void output_left(enum tof type, struct process *proc,
|
|
struct library_symbol *libsym);
|
|
-void output_right(enum tof type, struct Process *proc,
|
|
+void output_right(enum tof type, struct process *proc,
|
|
struct library_symbol *libsym);
|
|
|
|
/* This function is for emitting lists of comma-separated strings.
|
|
diff --git a/proc.c b/proc.c
|
|
index 3b4bfdb..db3f645 100644
|
|
--- a/proc.c
|
|
+++ b/proc.c
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
* This file is part of ltrace.
|
|
- * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
|
|
+ * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
|
|
* Copyright (C) 2010 Joe Damato
|
|
* Copyright (C) 1998,2009 Juan Cespedes
|
|
*
|
|
@@ -43,24 +43,24 @@
|
|
|
|
#ifndef ARCH_HAVE_PROCESS_DATA
|
|
int
|
|
-arch_process_init(struct Process *proc)
|
|
+arch_process_init(struct process *proc)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
-arch_process_destroy(struct Process *proc)
|
|
+arch_process_destroy(struct process *proc)
|
|
{
|
|
}
|
|
|
|
int
|
|
-arch_process_clone(struct Process *retp, struct Process *proc)
|
|
+arch_process_clone(struct process *retp, struct process *proc)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
-arch_process_exec(struct Process *proc)
|
|
+arch_process_exec(struct process *proc)
|
|
{
|
|
return 0;
|
|
}
|
|
@@ -68,24 +68,24 @@ arch_process_exec(struct Process *proc)
|
|
|
|
#ifndef OS_HAVE_PROCESS_DATA
|
|
int
|
|
-os_process_init(struct Process *proc)
|
|
+os_process_init(struct process *proc)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
-os_process_destroy(struct Process *proc)
|
|
+os_process_destroy(struct process *proc)
|
|
{
|
|
}
|
|
|
|
int
|
|
-os_process_clone(struct Process *retp, struct Process *proc)
|
|
+os_process_clone(struct process *retp, struct process *proc)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
-os_process_exec(struct Process *proc)
|
|
+os_process_exec(struct process *proc)
|
|
{
|
|
return 0;
|
|
}
|
|
@@ -93,16 +93,16 @@ os_process_exec(struct Process *proc)
|
|
|
|
#ifndef ARCH_HAVE_DYNLINK_DONE
|
|
void
|
|
-arch_dynlink_done(struct Process *proc)
|
|
+arch_dynlink_done(struct process *proc)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
-static void add_process(struct Process *proc, int was_exec);
|
|
-static void unlist_process(struct Process *proc);
|
|
+static void add_process(struct process *proc, int was_exec);
|
|
+static void unlist_process(struct process *proc);
|
|
|
|
static void
|
|
-destroy_unwind(struct Process *proc)
|
|
+destroy_unwind(struct process *proc)
|
|
{
|
|
#if defined(HAVE_LIBUNWIND)
|
|
_UPT_destroy(proc->unwind_priv);
|
|
@@ -111,7 +111,7 @@ destroy_unwind(struct Process *proc)
|
|
}
|
|
|
|
static int
|
|
-process_bare_init(struct Process *proc, const char *filename,
|
|
+process_bare_init(struct process *proc, const char *filename,
|
|
pid_t pid, int was_exec)
|
|
{
|
|
if (!was_exec) {
|
|
@@ -151,7 +151,7 @@ process_bare_init(struct Process *proc, const char *filename,
|
|
}
|
|
|
|
static void
|
|
-process_bare_destroy(struct Process *proc, int was_exec)
|
|
+process_bare_destroy(struct process *proc, int was_exec)
|
|
{
|
|
dict_clear(proc->breakpoints);
|
|
if (!was_exec) {
|
|
@@ -162,7 +162,7 @@ process_bare_destroy(struct Process *proc, int was_exec)
|
|
}
|
|
|
|
static int
|
|
-process_init_main(struct Process *proc)
|
|
+process_init_main(struct process *proc)
|
|
{
|
|
if (breakpoints_init(proc) < 0) {
|
|
fprintf(stderr, "failed to init breakpoints %d\n",
|
|
@@ -174,7 +174,7 @@ process_init_main(struct Process *proc)
|
|
}
|
|
|
|
int
|
|
-process_init(struct Process *proc, const char *filename, pid_t pid)
|
|
+process_init(struct process *proc, const char *filename, pid_t pid)
|
|
{
|
|
if (process_bare_init(proc, filename, pid, 0) < 0) {
|
|
fail:
|
|
@@ -204,7 +204,7 @@ process_init(struct Process *proc, const char *filename, pid_t pid)
|
|
}
|
|
|
|
static enum callback_status
|
|
-destroy_breakpoint_cb(struct Process *proc, struct breakpoint *bp, void *data)
|
|
+destroy_breakpoint_cb(struct process *proc, struct breakpoint *bp, void *data)
|
|
{
|
|
breakpoint_destroy(bp);
|
|
free(bp);
|
|
@@ -212,10 +212,10 @@ destroy_breakpoint_cb(struct Process *proc, struct breakpoint *bp, void *data)
|
|
}
|
|
|
|
// XXX see comment in handle_event.c
|
|
-void callstack_pop(struct Process *proc);
|
|
+void callstack_pop(struct process *proc);
|
|
|
|
static void
|
|
-private_process_destroy(struct Process *proc, int was_exec)
|
|
+private_process_destroy(struct process *proc, int was_exec)
|
|
{
|
|
/* Pop remaining stack elements. */
|
|
while (proc->callstack_depth > 0) {
|
|
@@ -257,7 +257,7 @@ private_process_destroy(struct Process *proc, int was_exec)
|
|
}
|
|
|
|
void
|
|
-process_destroy(struct Process *proc)
|
|
+process_destroy(struct process *proc)
|
|
{
|
|
arch_process_destroy(proc);
|
|
os_process_destroy(proc);
|
|
@@ -265,7 +265,7 @@ process_destroy(struct Process *proc)
|
|
}
|
|
|
|
int
|
|
-process_exec(struct Process *proc)
|
|
+process_exec(struct process *proc)
|
|
{
|
|
/* Call exec handlers first, before we destroy the main
|
|
* state. */
|
|
@@ -284,11 +284,11 @@ process_exec(struct Process *proc)
|
|
return 0;
|
|
}
|
|
|
|
-struct Process *
|
|
+struct process *
|
|
open_program(const char *filename, pid_t pid)
|
|
{
|
|
assert(pid != 0);
|
|
- struct Process *proc = malloc(sizeof(*proc));
|
|
+ struct process *proc = malloc(sizeof(*proc));
|
|
if (proc == NULL || process_init(proc, filename, pid) < 0) {
|
|
free(proc);
|
|
return NULL;
|
|
@@ -297,8 +297,8 @@ open_program(const char *filename, pid_t pid)
|
|
}
|
|
|
|
struct clone_single_bp_data {
|
|
- struct Process *old_proc;
|
|
- struct Process *new_proc;
|
|
+ struct process *old_proc;
|
|
+ struct process *new_proc;
|
|
int error;
|
|
};
|
|
|
|
@@ -327,7 +327,7 @@ clone_single_bp(void *key, void *value, void *u)
|
|
}
|
|
|
|
int
|
|
-process_clone(struct Process *retp, struct Process *proc, pid_t pid)
|
|
+process_clone(struct process *retp, struct process *proc, pid_t pid)
|
|
{
|
|
if (process_bare_init(retp, proc->filename, pid, 0) < 0) {
|
|
fail1:
|
|
@@ -456,20 +456,18 @@ process_clone(struct Process *retp, struct Process *proc, pid_t pid)
|
|
static int
|
|
open_one_pid(pid_t pid)
|
|
{
|
|
- Process *proc;
|
|
- char *filename;
|
|
debug(DEBUG_PROCESS, "open_one_pid(pid=%d)", pid);
|
|
|
|
/* Get the filename first. Should the trace_pid fail, we can
|
|
* easily free it, untracing is more work. */
|
|
- if ((filename = pid2name(pid)) == NULL
|
|
- || trace_pid(pid) < 0) {
|
|
+ char *filename = pid2name(pid);
|
|
+ if (filename == NULL || trace_pid(pid) < 0) {
|
|
fail:
|
|
free(filename);
|
|
return -1;
|
|
}
|
|
|
|
- proc = open_program(filename, pid);
|
|
+ struct process *proc = open_program(filename, pid);
|
|
if (proc == NULL)
|
|
goto fail;
|
|
free(filename);
|
|
@@ -479,7 +477,7 @@ open_one_pid(pid_t pid)
|
|
}
|
|
|
|
static enum callback_status
|
|
-start_one_pid(Process * proc, void * data)
|
|
+start_one_pid(struct process *proc, void *data)
|
|
{
|
|
continue_process(proc->pid);
|
|
return CBS_CONT;
|
|
@@ -537,7 +535,7 @@ open_pid(pid_t pid)
|
|
old_ntasks = ntasks;
|
|
}
|
|
|
|
- struct Process *leader = pid2proc(pid)->leader;
|
|
+ struct process *leader = pid2proc(pid)->leader;
|
|
|
|
/* XXX Is there a way to figure out whether _start has
|
|
* actually already been hit? */
|
|
@@ -548,29 +546,29 @@ open_pid(pid_t pid)
|
|
}
|
|
|
|
static enum callback_status
|
|
-find_proc(Process * proc, void * data)
|
|
+find_proc(struct process *proc, void *data)
|
|
{
|
|
pid_t pid = (pid_t)(uintptr_t)data;
|
|
return proc->pid == pid ? CBS_STOP : CBS_CONT;
|
|
}
|
|
|
|
-Process *
|
|
-pid2proc(pid_t pid) {
|
|
+struct process *
|
|
+pid2proc(pid_t pid)
|
|
+{
|
|
return each_process(NULL, &find_proc, (void *)(uintptr_t)pid);
|
|
}
|
|
|
|
-static Process * list_of_processes = NULL;
|
|
+static struct process *list_of_processes = NULL;
|
|
|
|
static void
|
|
-unlist_process(Process * proc)
|
|
+unlist_process(struct process *proc)
|
|
{
|
|
- Process *tmp;
|
|
-
|
|
if (list_of_processes == proc) {
|
|
list_of_processes = list_of_processes->next;
|
|
return;
|
|
}
|
|
|
|
+ struct process *tmp;
|
|
for (tmp = list_of_processes; ; tmp = tmp->next) {
|
|
/* If the following assert fails, the process wasn't
|
|
* in the list. */
|
|
@@ -583,17 +581,17 @@ unlist_process(Process * proc)
|
|
}
|
|
}
|
|
|
|
-struct Process *
|
|
-each_process(struct Process *start_after,
|
|
- enum callback_status(*cb)(struct Process *proc, void *data),
|
|
+struct process *
|
|
+each_process(struct process *start_after,
|
|
+ enum callback_status(*cb)(struct process *proc, void *data),
|
|
void *data)
|
|
{
|
|
- struct Process *it = start_after == NULL ? list_of_processes
|
|
+ struct process *it = start_after == NULL ? list_of_processes
|
|
: start_after->next;
|
|
|
|
while (it != NULL) {
|
|
/* Callback might call remove_process. */
|
|
- struct Process *next = it->next;
|
|
+ struct process *next = it->next;
|
|
switch ((*cb)(it, data)) {
|
|
case CBS_FAIL:
|
|
/* XXX handle me */
|
|
@@ -607,20 +605,20 @@ each_process(struct Process *start_after,
|
|
return NULL;
|
|
}
|
|
|
|
-Process *
|
|
-each_task(struct Process *proc, struct Process *start_after,
|
|
- enum callback_status(*cb)(struct Process *proc, void *data),
|
|
+struct process *
|
|
+each_task(struct process *proc, struct process *start_after,
|
|
+ enum callback_status(*cb)(struct process *proc, void *data),
|
|
void *data)
|
|
{
|
|
assert(proc != NULL);
|
|
- struct Process *it = start_after == NULL ? proc->leader
|
|
+ struct process *it = start_after == NULL ? proc->leader
|
|
: start_after->next;
|
|
|
|
if (it != NULL) {
|
|
- struct Process *leader = it->leader;
|
|
+ struct process *leader = it->leader;
|
|
while (it != NULL && it->leader == leader) {
|
|
/* Callback might call remove_process. */
|
|
- struct Process *next = it->next;
|
|
+ struct process *next = it->next;
|
|
switch ((*cb)(it, data)) {
|
|
case CBS_FAIL:
|
|
/* XXX handle me */
|
|
@@ -636,19 +634,19 @@ each_task(struct Process *proc, struct Process *start_after,
|
|
}
|
|
|
|
static void
|
|
-add_process(struct Process *proc, int was_exec)
|
|
+add_process(struct process *proc, int was_exec)
|
|
{
|
|
- Process ** leaderp = &list_of_processes;
|
|
+ struct process **leaderp = &list_of_processes;
|
|
if (proc->pid) {
|
|
pid_t tgid = process_leader(proc->pid);
|
|
if (tgid == 0)
|
|
/* Must have been terminated before we managed
|
|
* to fully attach. */
|
|
return;
|
|
- if (tgid == proc->pid)
|
|
+ if (tgid == proc->pid) {
|
|
proc->leader = proc;
|
|
- else {
|
|
- Process * leader = pid2proc(tgid);
|
|
+ } else {
|
|
+ struct process *leader = pid2proc(tgid);
|
|
proc->leader = leader;
|
|
if (leader != NULL)
|
|
leaderp = &leader->next;
|
|
@@ -662,9 +660,9 @@ add_process(struct Process *proc, int was_exec)
|
|
}
|
|
|
|
void
|
|
-change_process_leader(Process * proc, Process * leader)
|
|
+change_process_leader(struct process *proc, struct process *leader)
|
|
{
|
|
- Process ** leaderp = &list_of_processes;
|
|
+ struct process **leaderp = &list_of_processes;
|
|
if (proc->leader == leader)
|
|
return;
|
|
|
|
@@ -679,7 +677,7 @@ change_process_leader(Process * proc, Process * leader)
|
|
}
|
|
|
|
static enum callback_status
|
|
-clear_leader(struct Process *proc, void *data)
|
|
+clear_leader(struct process *proc, void *data)
|
|
{
|
|
debug(DEBUG_FUNCTION, "detach_task %d from leader %d",
|
|
proc->pid, proc->leader->pid);
|
|
@@ -688,7 +686,7 @@ clear_leader(struct Process *proc, void *data)
|
|
}
|
|
|
|
void
|
|
-remove_process(Process *proc)
|
|
+remove_process(struct process *proc)
|
|
{
|
|
debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid);
|
|
|
|
@@ -702,7 +700,7 @@ remove_process(Process *proc)
|
|
}
|
|
|
|
void
|
|
-install_event_handler(Process *proc, struct event_handler *handler)
|
|
+install_event_handler(struct process *proc, struct event_handler *handler)
|
|
{
|
|
debug(DEBUG_FUNCTION, "install_event_handler(pid=%d, %p)", proc->pid, handler);
|
|
assert(proc->event_handler == NULL);
|
|
@@ -710,7 +708,7 @@ install_event_handler(Process *proc, struct event_handler *handler)
|
|
}
|
|
|
|
void
|
|
-destroy_event_handler(Process * proc)
|
|
+destroy_event_handler(struct process *proc)
|
|
{
|
|
struct event_handler *handler = proc->event_handler;
|
|
debug(DEBUG_FUNCTION, "destroy_event_handler(pid=%d, %p)", proc->pid, handler);
|
|
@@ -722,7 +720,7 @@ destroy_event_handler(Process * proc)
|
|
}
|
|
|
|
static int
|
|
-breakpoint_for_symbol(struct library_symbol *libsym, struct Process *proc)
|
|
+breakpoint_for_symbol(struct library_symbol *libsym, struct process *proc)
|
|
{
|
|
arch_addr_t bp_addr;
|
|
assert(proc->leader == proc);
|
|
@@ -799,7 +797,7 @@ cb_breakpoint_for_symbol(struct library_symbol *libsym, void *data)
|
|
}
|
|
|
|
static int
|
|
-proc_activate_latent_symbol(struct Process *proc,
|
|
+proc_activate_latent_symbol(struct process *proc,
|
|
struct library_symbol *libsym)
|
|
{
|
|
assert(libsym->latent);
|
|
@@ -809,7 +807,7 @@ proc_activate_latent_symbol(struct Process *proc,
|
|
}
|
|
|
|
int
|
|
-proc_activate_delayed_symbol(struct Process *proc,
|
|
+proc_activate_delayed_symbol(struct process *proc,
|
|
struct library_symbol *libsym)
|
|
{
|
|
assert(libsym->delayed);
|
|
@@ -819,7 +817,7 @@ proc_activate_delayed_symbol(struct Process *proc,
|
|
}
|
|
|
|
static enum callback_status
|
|
-activate_latent_in(struct Process *proc, struct library *lib, void *data)
|
|
+activate_latent_in(struct process *proc, struct library *lib, void *data)
|
|
{
|
|
struct library_exported_name *exported;
|
|
for (exported = data; exported != NULL; exported = exported->next) {
|
|
@@ -836,7 +834,7 @@ activate_latent_in(struct Process *proc, struct library *lib, void *data)
|
|
}
|
|
|
|
void
|
|
-proc_add_library(struct Process *proc, struct library *lib)
|
|
+proc_add_library(struct process *proc, struct library *lib)
|
|
{
|
|
assert(lib->next == NULL);
|
|
lib->next = proc->libraries;
|
|
@@ -864,7 +862,7 @@ proc_add_library(struct Process *proc, struct library *lib)
|
|
}
|
|
|
|
int
|
|
-proc_remove_library(struct Process *proc, struct library *lib)
|
|
+proc_remove_library(struct process *proc, struct library *lib)
|
|
{
|
|
struct library **libp;
|
|
for (libp = &proc->libraries; *libp != NULL; libp = &(*libp)->next)
|
|
@@ -876,8 +874,8 @@ proc_remove_library(struct Process *proc, struct library *lib)
|
|
}
|
|
|
|
struct library *
|
|
-proc_each_library(struct Process *proc, struct library *it,
|
|
- enum callback_status (*cb)(struct Process *proc,
|
|
+proc_each_library(struct process *proc, struct library *it,
|
|
+ enum callback_status (*cb)(struct process *proc,
|
|
struct library *lib, void *data),
|
|
void *data)
|
|
{
|
|
@@ -903,7 +901,7 @@ proc_each_library(struct Process *proc, struct library *it,
|
|
}
|
|
|
|
static void
|
|
-check_leader(struct Process *proc)
|
|
+check_leader(struct process *proc)
|
|
{
|
|
/* Only the group leader should be getting the breakpoints and
|
|
* thus have ->breakpoint initialized. */
|
|
@@ -913,7 +911,7 @@ check_leader(struct Process *proc)
|
|
}
|
|
|
|
int
|
|
-proc_add_breakpoint(struct Process *proc, struct breakpoint *bp)
|
|
+proc_add_breakpoint(struct process *proc, struct breakpoint *bp)
|
|
{
|
|
debug(DEBUG_FUNCTION, "proc_add_breakpoint(pid=%d, %s@%p)",
|
|
proc->pid, breakpoint_name(bp), bp->addr);
|
|
@@ -935,7 +933,7 @@ proc_add_breakpoint(struct Process *proc, struct breakpoint *bp)
|
|
}
|
|
|
|
void
|
|
-proc_remove_breakpoint(struct Process *proc, struct breakpoint *bp)
|
|
+proc_remove_breakpoint(struct process *proc, struct breakpoint *bp)
|
|
{
|
|
debug(DEBUG_FUNCTION, "proc_remove_breakpoint(pid=%d, %s@%p)",
|
|
proc->pid, breakpoint_name(bp), bp->addr);
|
|
@@ -950,8 +948,8 @@ struct each_breakpoint_data
|
|
{
|
|
void *start;
|
|
void *end;
|
|
- struct Process *proc;
|
|
- enum callback_status (*cb)(struct Process *proc,
|
|
+ struct process *proc;
|
|
+ enum callback_status (*cb)(struct process *proc,
|
|
struct breakpoint *bp,
|
|
void *data);
|
|
void *cb_data;
|
|
@@ -979,8 +977,8 @@ each_breakpoint_cb(void *key, void *value, void *d)
|
|
}
|
|
|
|
void *
|
|
-proc_each_breakpoint(struct Process *proc, void *start,
|
|
- enum callback_status (*cb)(struct Process *proc,
|
|
+proc_each_breakpoint(struct process *proc, void *start,
|
|
+ enum callback_status (*cb)(struct process *proc,
|
|
struct breakpoint *bp,
|
|
void *data), void *data)
|
|
{
|
|
@@ -995,7 +993,7 @@ proc_each_breakpoint(struct Process *proc, void *start,
|
|
}
|
|
|
|
int
|
|
-proc_find_symbol(struct Process *proc, struct library_symbol *sym,
|
|
+proc_find_symbol(struct process *proc, struct library_symbol *sym,
|
|
struct library **retlib, struct library_symbol **retsym)
|
|
{
|
|
struct library *lib = sym->lib;
|
|
@@ -1021,7 +1019,7 @@ proc_find_symbol(struct Process *proc, struct library_symbol *sym,
|
|
}
|
|
|
|
struct library_symbol *
|
|
-proc_each_symbol(struct Process *proc, struct library_symbol *start_after,
|
|
+proc_each_symbol(struct process *proc, struct library_symbol *start_after,
|
|
enum callback_status (*cb)(struct library_symbol *, void *),
|
|
void *data)
|
|
{
|
|
@@ -1035,3 +1033,25 @@ proc_each_symbol(struct Process *proc, struct library_symbol *start_after,
|
|
|
|
return NULL;
|
|
}
|
|
+
|
|
+#define DEF_READER(NAME, SIZE) \
|
|
+ int \
|
|
+ NAME(struct process *proc, arch_addr_t addr, \
|
|
+ uint##SIZE##_t *lp) \
|
|
+ { \
|
|
+ union { \
|
|
+ uint##SIZE##_t dst; \
|
|
+ char buf[0]; \
|
|
+ } u; \
|
|
+ if (umovebytes(proc, addr, &u.buf, sizeof(u.dst)) \
|
|
+ != sizeof(u.dst)) \
|
|
+ return -1; \
|
|
+ *lp = u.dst; \
|
|
+ return 0; \
|
|
+ }
|
|
+
|
|
+DEF_READER(proc_read_16, 16)
|
|
+DEF_READER(proc_read_32, 32)
|
|
+DEF_READER(proc_read_64, 64)
|
|
+
|
|
+#undef DEF_READER
|
|
diff --git a/proc.h b/proc.h
|
|
index a97796c..04c0ef7 100644
|
|
--- a/proc.h
|
|
+++ b/proc.h
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
* This file is part of ltrace.
|
|
- * Copyright (C) 2010,2011,2012 Petr Machata, Red Hat Inc.
|
|
+ * Copyright (C) 2010,2011,2012,2013 Petr Machata, Red Hat Inc.
|
|
* Copyright (C) 2010 Joe Damato
|
|
* Copyright (C) 1998,2001,2008,2009 Juan Cespedes
|
|
*
|
|
@@ -26,6 +26,7 @@
|
|
#include "config.h"
|
|
|
|
#include <sys/time.h>
|
|
+#include <stdint.h>
|
|
|
|
#if defined(HAVE_LIBUNWIND)
|
|
# include <libunwind.h>
|
|
@@ -75,13 +76,12 @@ struct callstack_element {
|
|
#define MAX_CALLDEPTH 64
|
|
|
|
/* XXX We would rather have this all organized a little differently,
|
|
- * have Process for the whole group and Task for what's there for
|
|
- * per-thread stuff. But for now this is the less invasive way of
|
|
- * structuring it. */
|
|
-typedef struct Process Process;
|
|
-struct Process {
|
|
+ * have struct process for the whole group and struct task (or struct
|
|
+ * lwp, struct thread) for what's there for per-thread stuff. But for
|
|
+ * now this is the less invasive way of structuring it. */
|
|
+struct process {
|
|
enum process_state state;
|
|
- Process * parent; /* needed by STATE_BEING_CREATED */
|
|
+ struct process *parent; /* needed by STATE_BEING_CREATED */
|
|
char * filename;
|
|
pid_t pid;
|
|
|
|
@@ -133,15 +133,15 @@ struct Process {
|
|
/**
|
|
* Process chaining.
|
|
**/
|
|
- Process * next;
|
|
+ struct process *next;
|
|
|
|
/* LEADER points to the leader thread of the POSIX.1 process.
|
|
If X->LEADER == X, then X is the leader thread and the
|
|
- Process structures chained by NEXT represent other threads,
|
|
+ process structures chained by NEXT represent other threads,
|
|
up until, but not including, the next leader thread.
|
|
LEADER may be NULL after the leader has already exited. In
|
|
that case this process is waiting to be collected. */
|
|
- Process * leader;
|
|
+ struct process *leader;
|
|
|
|
struct os_process_data os;
|
|
struct arch_process_data arch;
|
|
@@ -149,12 +149,12 @@ struct Process {
|
|
|
|
/* Initialize a process given a path to binary FILENAME, with a PID,
|
|
* and add the process to an internal chain of traced processes. */
|
|
-int process_init(struct Process *proc, const char *filename, pid_t pid);
|
|
+int process_init(struct process *proc, const char *filename, pid_t pid);
|
|
|
|
/* PROC underwent an exec. This is a bit like process_destroy
|
|
* followed by process_init, except that some state is kept and the
|
|
* process doesn't lose it's place in the list of processes. */
|
|
-int process_exec(struct Process *proc);
|
|
+int process_exec(struct process *proc);
|
|
|
|
/* Release any memory allocated for PROC (but not PROC itself). Does
|
|
* NOT remove PROC from internal chain.
|
|
@@ -162,74 +162,74 @@ int process_exec(struct Process *proc);
|
|
* XXX clearly this init/destroy pair is different than others and
|
|
* should be fixed. process_init should presumably be separate from
|
|
* process_add. */
|
|
-void process_destroy(struct Process *proc);
|
|
+void process_destroy(struct process *proc);
|
|
|
|
-struct Process *open_program(const char *filename, pid_t pid);
|
|
+struct process *open_program(const char *filename, pid_t pid);
|
|
void open_pid(pid_t pid);
|
|
-Process * pid2proc(pid_t pid);
|
|
+struct process *pid2proc(pid_t pid);
|
|
|
|
/* Clone the contents of PROC into the memory referenced by RETP.
|
|
* Returns 0 on success or a negative value on failure. */
|
|
-int process_clone(struct Process *retp, struct Process *proc, pid_t pid);
|
|
+int process_clone(struct process *retp, struct process *proc, pid_t pid);
|
|
|
|
/* Iterate through the processes that ltrace currently traces. Tasks
|
|
* are considered to be processes for the purpose of this iterator.
|
|
* See callback.h for notes on iteration interfaces. */
|
|
-Process *each_process(Process *start_after,
|
|
- enum callback_status (*cb)(struct Process *proc,
|
|
- void *data),
|
|
- void *data);
|
|
+struct process *each_process(struct process *start_after,
|
|
+ enum callback_status (*cb)(struct process *proc,
|
|
+ void *data),
|
|
+ void *data);
|
|
|
|
/* Iterate through list of tasks of given process PROC. See
|
|
* callback.h for notes on iteration interfaces. */
|
|
-Process *each_task(struct Process *proc, struct Process *start_after,
|
|
- enum callback_status (*cb)(struct Process *proc,
|
|
- void *data),
|
|
- void *data);
|
|
+struct process *each_task(struct process *proc, struct process *start_after,
|
|
+ enum callback_status (*cb)(struct process *proc,
|
|
+ void *data),
|
|
+ void *data);
|
|
|
|
-void change_process_leader(Process *proc, Process *leader);
|
|
+void change_process_leader(struct process *proc, struct process *leader);
|
|
|
|
/* Remove process from the list of traced processes, drop any events
|
|
* in the event queue, destroy it and free memory. */
|
|
-void remove_process(struct Process *proc);
|
|
+void remove_process(struct process *proc);
|
|
|
|
-void install_event_handler(Process *proc, struct event_handler *handler);
|
|
-void destroy_event_handler(Process *proc);
|
|
+void install_event_handler(struct process *proc, struct event_handler *handler);
|
|
+void destroy_event_handler(struct process *proc);
|
|
|
|
/* Add a library LIB to the list of PROC's libraries. */
|
|
-void proc_add_library(struct Process *proc, struct library *lib);
|
|
+void proc_add_library(struct process *proc, struct library *lib);
|
|
|
|
/* Remove LIB from list of PROC's libraries. Returns 0 if the library
|
|
* was found and unlinked, otherwise returns a negative value. */
|
|
-int proc_remove_library(struct Process *proc, struct library *lib);
|
|
+int proc_remove_library(struct process *proc, struct library *lib);
|
|
|
|
/* Clear a delayed flag. If a symbol is neither latent, nor delayed,
|
|
* a breakpoint is inserted for it. Returns 0 if the activation was
|
|
* successful or a negative value if it failed. Note that if a symbol
|
|
* is both latent and delayed, this will not enable the corresponding
|
|
* breakpoint. */
|
|
-int proc_activate_delayed_symbol(struct Process *proc,
|
|
+int proc_activate_delayed_symbol(struct process *proc,
|
|
struct library_symbol *libsym);
|
|
|
|
/* Iterate through the libraries of PROC. See callback.h for notes on
|
|
* iteration interfaces. */
|
|
-struct library *proc_each_library(struct Process *proc, struct library *start,
|
|
- enum callback_status (*cb)(struct Process *p,
|
|
+struct library *proc_each_library(struct process *proc, struct library *start,
|
|
+ enum callback_status (*cb)(struct process *p,
|
|
struct library *l,
|
|
void *data),
|
|
void *data);
|
|
|
|
/* Insert BP into PROC. */
|
|
-int proc_add_breakpoint(struct Process *proc, struct breakpoint *bp);
|
|
+int proc_add_breakpoint(struct process *proc, struct breakpoint *bp);
|
|
|
|
/* Remove BP from PROC. This has no reason to fail in runtime. If it
|
|
* does not find BP in PROC, it's hard error guarded by assertion. */
|
|
-void proc_remove_breakpoint(struct Process *proc, struct breakpoint *bp);
|
|
+void proc_remove_breakpoint(struct process *proc, struct breakpoint *bp);
|
|
|
|
/* Iterate through the breakpoints of PROC. See callback.h for notes
|
|
* on iteration interfaces. */
|
|
-void *proc_each_breakpoint(struct Process *proc, void *start,
|
|
- enum callback_status (*cb)(struct Process *proc,
|
|
+void *proc_each_breakpoint(struct process *proc, void *start,
|
|
+ enum callback_status (*cb)(struct process *proc,
|
|
struct breakpoint *bp,
|
|
void *data),
|
|
void *data);
|
|
@@ -237,21 +237,29 @@ void *proc_each_breakpoint(struct Process *proc, void *start,
|
|
/* Iterate through the dynamic section at src_addr looking for D_TAG.
|
|
* If tag is found, fill it's value in RET and return 0.
|
|
* If tag is not found, return a negative value. */
|
|
-int proc_find_dynamic_entry_addr(struct Process *proc, arch_addr_t src_addr,
|
|
+int proc_find_dynamic_entry_addr(struct process *proc, arch_addr_t src_addr,
|
|
int d_tag, arch_addr_t *ret);
|
|
|
|
/* Finds a symbol corresponding to LIBSYM in a process PROC. Returns
|
|
* 0 and sets *RETLIB and *RETSYM if the corresponding pointer is
|
|
* non-NULL. Returns a negative value when the symbols couldn't be
|
|
* found. */
|
|
-int proc_find_symbol(struct Process *proc, struct library_symbol *sym,
|
|
+int proc_find_symbol(struct process *proc, struct library_symbol *sym,
|
|
struct library **retlib, struct library_symbol **retsym);
|
|
|
|
/* Iterate through all symbols in all libraries of PROC. See
|
|
* callback.h for notes on this interface. */
|
|
struct library_symbol *proc_each_symbol
|
|
- (struct Process *proc, struct library_symbol *start_after,
|
|
+ (struct process *proc, struct library_symbol *start_after,
|
|
enum callback_status (*cb)(struct library_symbol *, void *),
|
|
void *data);
|
|
|
|
+/* Read 16, 32 or 64-bit quantity located at ADDR in PROC. The
|
|
+ * resulting value is stored in *LP. 0 is returned on success or a
|
|
+ * negative value on failure. This uses umovebytes under the hood
|
|
+ * (see backend.h). */
|
|
+int proc_read_16(struct process *proc, arch_addr_t addr, uint16_t *lp);
|
|
+int proc_read_32(struct process *proc, arch_addr_t addr, uint32_t *lp);
|
|
+int proc_read_64(struct process *proc, arch_addr_t addr, uint64_t *lp);
|
|
+
|
|
#endif /* _PROC_H_ */
|
|
diff --git a/read_config_file.c b/read_config_file.c
|
|
index e247436..015be50 100644
|
|
--- a/read_config_file.c
|
|
+++ b/read_config_file.c
|
|
@@ -27,7 +27,6 @@
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
-#include <error.h>
|
|
#include <assert.h>
|
|
|
|
#include "common.h"
|
|
@@ -41,6 +40,19 @@
|
|
#include "lens_default.h"
|
|
#include "lens_enum.h"
|
|
|
|
+/* Lifted from GCC: The ctype functions are often implemented as
|
|
+ * macros which do lookups in arrays using the parameter as the
|
|
+ * offset. If the ctype function parameter is a char, then gcc will
|
|
+ * (appropriately) warn that a "subscript has type char". Using a
|
|
+ * (signed) char as a subscript is bad because you may get negative
|
|
+ * offsets and thus it is not 8-bit safe. The CTYPE_CONV macro
|
|
+ * ensures that the parameter is cast to an unsigned char when a char
|
|
+ * is passed in. When an int is passed in, the parameter is left
|
|
+ * alone so we don't lose EOF. */
|
|
+
|
|
+#define CTYPE_CONV(CH) \
|
|
+ (sizeof(CH) == sizeof(unsigned char) ? (int)(unsigned char)(CH) : (int)(CH))
|
|
+
|
|
static int line_no;
|
|
static char *filename;
|
|
struct typedef_node_t;
|
|
@@ -97,7 +109,7 @@ parse_arg_type(char **name, enum arg_type *ret)
|
|
#undef KEYWORD
|
|
|
|
ok:
|
|
- if (isalnum(*rest))
|
|
+ if (isalnum(CTYPE_CONV(*rest)))
|
|
return -1;
|
|
|
|
*name = rest;
|
|
@@ -128,12 +140,12 @@ static char *
|
|
parse_ident(char **str) {
|
|
char *ident = *str;
|
|
|
|
- if (!isalpha(**str) && **str != '_') {
|
|
+ if (!isalpha(CTYPE_CONV(**str)) && **str != '_') {
|
|
report_error(filename, line_no, "bad identifier");
|
|
return NULL;
|
|
}
|
|
|
|
- while (**str && (isalnum(**str) || **str == '_')) {
|
|
+ while (**str && (isalnum(CTYPE_CONV(**str)) || **str == '_')) {
|
|
++(*str);
|
|
}
|
|
|
|
@@ -280,7 +292,7 @@ parse_argnum(char **str, int *ownp, int zero)
|
|
if (expr == NULL)
|
|
return NULL;
|
|
|
|
- if (isdigit(**str)) {
|
|
+ if (isdigit(CTYPE_CONV(**str))) {
|
|
long l;
|
|
if (parse_int(str, &l) < 0
|
|
|| check_nonnegative(l) < 0
|
|
@@ -381,7 +393,7 @@ static struct arg_type_info *
|
|
parse_typedef_name(char **str)
|
|
{
|
|
char *end = *str;
|
|
- while (*end && (isalnum(*end) || *end == '_'))
|
|
+ while (*end && (isalnum(CTYPE_CONV(*end)) || *end == '_'))
|
|
++end;
|
|
if (end == *str)
|
|
return NULL;
|
|
@@ -568,7 +580,7 @@ parse_string(char **str, struct arg_type_info **retp, int *ownp)
|
|
int own_length;
|
|
int with_arg = 0;
|
|
|
|
- if (isdigit(**str)) {
|
|
+ if (isdigit(CTYPE_CONV(**str))) {
|
|
/* string0 is string[retval], length is zero(retval)
|
|
* stringN is string[argN], length is zero(argN) */
|
|
long l;
|
|
@@ -683,7 +695,7 @@ try_parse_kwd(char **str, const char *kwd)
|
|
{
|
|
size_t len = strlen(kwd);
|
|
if (strncmp(*str, kwd, len) == 0
|
|
- && !isalnum((*str)[len])) {
|
|
+ && !isalnum(CTYPE_CONV((*str)[len]))) {
|
|
(*str) += len;
|
|
return 0;
|
|
}
|
|
@@ -1258,8 +1270,11 @@ void
|
|
init_global_config(void)
|
|
{
|
|
struct arg_type_info *info = malloc(2 * sizeof(*info));
|
|
- if (info == NULL)
|
|
- error(1, errno, "malloc in init_global_config");
|
|
+ if (info == NULL) {
|
|
+ fprintf(stderr, "Couldn't init global config: %s\n",
|
|
+ strerror(errno));
|
|
+ exit(1);
|
|
+ }
|
|
|
|
memset(info, 0, 2 * sizeof(*info));
|
|
info[0].type = ARGTYPE_POINTER;
|
|
diff --git a/sysdeps/linux-gnu/alpha/plt.c b/sysdeps/linux-gnu/alpha/plt.c
|
|
index c7ce9fe..1185363 100644
|
|
--- a/sysdeps/linux-gnu/alpha/plt.c
|
|
+++ b/sysdeps/linux-gnu/alpha/plt.c
|
|
@@ -23,11 +23,13 @@
|
|
#include "common.h"
|
|
|
|
GElf_Addr
|
|
-arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
|
|
+arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela)
|
|
+{
|
|
return lte->plt_addr + ndx * 12 + 32;
|
|
}
|
|
|
|
void *
|
|
-sym2addr(Process *proc, struct library_symbol *sym) {
|
|
+sym2addr(struct process *proc, struct library_symbol *sym)
|
|
+{
|
|
return sym->enter_addr;
|
|
}
|
|
diff --git a/sysdeps/linux-gnu/alpha/regs.c b/sysdeps/linux-gnu/alpha/regs.c
|
|
index 0b46afd..c197225 100644
|
|
--- a/sysdeps/linux-gnu/alpha/regs.c
|
|
+++ b/sysdeps/linux-gnu/alpha/regs.c
|
|
@@ -36,26 +36,31 @@
|
|
#endif
|
|
|
|
void *
|
|
-get_instruction_pointer(Process *proc) {
|
|
+get_instruction_pointer(struct process *proc)
|
|
+{
|
|
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 64 /* REG_PC */ , 0);
|
|
}
|
|
|
|
void
|
|
-set_instruction_pointer(Process *proc, void *addr) {
|
|
+set_instruction_pointer(struct process *proc, void *addr)
|
|
+{
|
|
ptrace(PTRACE_POKEUSER, proc->pid, 64 /* REG_PC */ , addr);
|
|
}
|
|
|
|
void *
|
|
-get_stack_pointer(Process *proc) {
|
|
+get_stack_pointer(struct process *proc)
|
|
+{
|
|
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 30 /* REG_FP */ , 0);
|
|
}
|
|
|
|
void *
|
|
-get_return_addr(Process *proc, void *stack_pointer) {
|
|
+get_return_addr(struct process *proc, void *stack_pointer)
|
|
+{
|
|
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 26 /* RA */ , 0);
|
|
}
|
|
|
|
void
|
|
-set_return_addr(Process *proc, void *addr) {
|
|
+set_return_addr(struct process *proc, void *addr)
|
|
+{
|
|
ptrace(PTRACE_POKEUSER, proc->pid, 26 /* RA */ , addr);
|
|
}
|
|
diff --git a/sysdeps/linux-gnu/alpha/trace.c b/sysdeps/linux-gnu/alpha/trace.c
|
|
index a7c5e59..c6f7494 100644
|
|
--- a/sysdeps/linux-gnu/alpha/trace.c
|
|
+++ b/sysdeps/linux-gnu/alpha/trace.c
|
|
@@ -40,13 +40,15 @@
|
|
#endif
|
|
|
|
void
|
|
-get_arch_dep(Process *proc) {
|
|
+get_arch_dep(struct process *proc)
|
|
+{
|
|
}
|
|
|
|
/* Returns 1 if syscall, 2 if sysret, 0 otherwise.
|
|
*/
|
|
int
|
|
-syscall_p(Process *proc, int status, int *sysnum) {
|
|
+syscall_p(struct process *proc, int status, int *sysnum)
|
|
+{
|
|
if (WIFSTOPPED(status)
|
|
&& WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
|
|
char *ip = get_instruction_pointer(proc) - 4;
|
|
@@ -69,7 +71,8 @@ syscall_p(Process *proc, int status, int *sysnum) {
|
|
}
|
|
|
|
long
|
|
-gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info)
|
|
+gimme_arg(enum tof type, struct process *proc, int arg_num,
|
|
+ struct arg_type_info *info)
|
|
{
|
|
if (arg_num == -1) { /* return value */
|
|
return ptrace(PTRACE_PEEKUSER, proc->pid, 0 /* REG_R0 */ , 0);
|
|
diff --git a/sysdeps/linux-gnu/arm/breakpoint.c b/sysdeps/linux-gnu/arm/breakpoint.c
|
|
index 5748401..2fb9578 100644
|
|
--- a/sysdeps/linux-gnu/arm/breakpoint.c
|
|
+++ b/sysdeps/linux-gnu/arm/breakpoint.c
|
|
@@ -92,7 +92,7 @@ arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp)
|
|
}
|
|
|
|
int
|
|
-arch_breakpoint_init(struct Process *proc, struct breakpoint *sbp)
|
|
+arch_breakpoint_init(struct process *proc, struct breakpoint *sbp)
|
|
{
|
|
/* XXX That uintptr_t cast is there temporarily until
|
|
* arch_addr_t becomes integral type. */
|
|
diff --git a/sysdeps/linux-gnu/arm/plt.c b/sysdeps/linux-gnu/arm/plt.c
|
|
index 1b97705..d1bf7ca 100644
|
|
--- a/sysdeps/linux-gnu/arm/plt.c
|
|
+++ b/sysdeps/linux-gnu/arm/plt.c
|
|
@@ -43,6 +43,7 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
|
|
}
|
|
|
|
void *
|
|
-sym2addr(Process *proc, struct library_symbol *sym) {
|
|
+sym2addr(struct process *proc, struct library_symbol *sym)
|
|
+{
|
|
return sym->enter_addr;
|
|
}
|
|
diff --git a/sysdeps/linux-gnu/arm/regs.c b/sysdeps/linux-gnu/arm/regs.c
|
|
index 484de7f..377df62 100644
|
|
--- a/sysdeps/linux-gnu/arm/regs.c
|
|
+++ b/sysdeps/linux-gnu/arm/regs.c
|
|
@@ -41,24 +41,28 @@
|
|
#define off_sp ((void *)52)
|
|
|
|
void *
|
|
-get_instruction_pointer(Process *proc) {
|
|
+get_instruction_pointer(struct process *proc)
|
|
+{
|
|
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0);
|
|
}
|
|
|
|
void
|
|
-set_instruction_pointer(Process *proc, void *addr) {
|
|
+set_instruction_pointer(struct process *proc, void *addr)
|
|
+{
|
|
ptrace(PTRACE_POKEUSER, proc->pid, off_pc, addr);
|
|
}
|
|
|
|
void *
|
|
-get_stack_pointer(Process *proc) {
|
|
+get_stack_pointer(struct process *proc)
|
|
+{
|
|
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_sp, 0);
|
|
}
|
|
|
|
/* really, this is given the *stack_pointer expecting
|
|
* a CISC architecture; in our case, we don't need that */
|
|
void *
|
|
-get_return_addr(Process *proc, void *stack_pointer) {
|
|
+get_return_addr(struct process *proc, void *stack_pointer)
|
|
+{
|
|
long addr = ptrace(PTRACE_PEEKUSER, proc->pid, off_lr, 0);
|
|
|
|
/* Remember & unset the thumb mode bit. XXX This is really a
|
|
@@ -74,7 +78,8 @@ get_return_addr(Process *proc, void *stack_pointer) {
|
|
}
|
|
|
|
void
|
|
-set_return_addr(Process *proc, void *addr) {
|
|
+set_return_addr(struct process *proc, void *addr)
|
|
+{
|
|
long iaddr = (int)addr | proc->thumb_mode;
|
|
ptrace(PTRACE_POKEUSER, proc->pid, off_lr, (void *)iaddr);
|
|
}
|
|
diff --git a/sysdeps/linux-gnu/arm/trace.c b/sysdeps/linux-gnu/arm/trace.c
|
|
index c528cfb..fbbf676 100644
|
|
--- a/sysdeps/linux-gnu/arm/trace.c
|
|
+++ b/sysdeps/linux-gnu/arm/trace.c
|
|
@@ -48,7 +48,8 @@
|
|
#define off_pc ((void *)60)
|
|
|
|
void
|
|
-get_arch_dep(Process *proc) {
|
|
+get_arch_dep(struct process *proc)
|
|
+{
|
|
proc_archdep *a;
|
|
|
|
if (!proc->arch_ptr)
|
|
@@ -63,7 +64,8 @@ get_arch_dep(Process *proc) {
|
|
* -1 on error.
|
|
*/
|
|
int
|
|
-syscall_p(Process *proc, int status, int *sysnum) {
|
|
+syscall_p(struct process *proc, int status, int *sysnum)
|
|
+{
|
|
if (WIFSTOPPED(status)
|
|
&& WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
|
|
/* get the user's pc (plus 8) */
|
|
@@ -104,7 +106,8 @@ syscall_p(Process *proc, int status, int *sysnum) {
|
|
}
|
|
|
|
long
|
|
-gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info)
|
|
+gimme_arg(enum tof type, struct process *proc, int arg_num,
|
|
+ struct arg_type_info *info)
|
|
{
|
|
proc_archdep *a = (proc_archdep *) proc->arch_ptr;
|
|
|
|
diff --git a/sysdeps/linux-gnu/breakpoint.c b/sysdeps/linux-gnu/breakpoint.c
|
|
index fe336b1..c28d745 100644
|
|
--- a/sysdeps/linux-gnu/breakpoint.c
|
|
+++ b/sysdeps/linux-gnu/breakpoint.c
|
|
@@ -79,7 +79,7 @@ arch_enable_breakpoint(pid_t pid, struct breakpoint *sbp)
|
|
#endif /* ARCH_HAVE_ENABLE_BREAKPOINT */
|
|
|
|
void
|
|
-enable_breakpoint(Process *proc, struct breakpoint *sbp)
|
|
+enable_breakpoint(struct process *proc, struct breakpoint *sbp)
|
|
{
|
|
debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p, symbol=%s",
|
|
proc->pid, sbp->addr, breakpoint_name(sbp));
|
|
@@ -127,7 +127,7 @@ arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp)
|
|
#endif /* ARCH_HAVE_DISABLE_BREAKPOINT */
|
|
|
|
void
|
|
-disable_breakpoint(Process *proc, struct breakpoint *sbp)
|
|
+disable_breakpoint(struct process *proc, struct breakpoint *sbp)
|
|
{
|
|
debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p, symbol=%s",
|
|
proc->pid, sbp->addr, breakpoint_name(sbp));
|
|
diff --git a/sysdeps/linux-gnu/cris/plt.c b/sysdeps/linux-gnu/cris/plt.c
|
|
index 427ae93..fcc18d2 100644
|
|
--- a/sysdeps/linux-gnu/cris/plt.c
|
|
+++ b/sysdeps/linux-gnu/cris/plt.c
|
|
@@ -28,7 +28,7 @@ GElf_Addr arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela)
|
|
return lte->plt_addr + 0x20 + (ndx * 26);
|
|
}
|
|
|
|
-void *sym2addr(Process *proc, struct library_symbol *sym)
|
|
+void *sym2addr(struct process *proc, struct library_symbol *sym)
|
|
{
|
|
return sym->enter_addr;
|
|
}
|
|
diff --git a/sysdeps/linux-gnu/cris/regs.c b/sysdeps/linux-gnu/cris/regs.c
|
|
index 7028b9e..4cf1fbf 100644
|
|
--- a/sysdeps/linux-gnu/cris/regs.c
|
|
+++ b/sysdeps/linux-gnu/cris/regs.c
|
|
@@ -37,22 +37,22 @@
|
|
# define PTRACE_POKEUSER PTRACE_POKEUSR
|
|
#endif
|
|
|
|
-void *get_instruction_pointer(Process *proc)
|
|
+void *get_instruction_pointer(struct process *proc)
|
|
{
|
|
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_PPC, 0);
|
|
}
|
|
|
|
-void set_instruction_pointer(Process *proc, void *addr)
|
|
+void set_instruction_pointer(struct process *proc, void *addr)
|
|
{
|
|
ptrace(PTRACE_POKEUSER, proc->pid, 4 * PT_PPC, addr);
|
|
}
|
|
|
|
-void *get_stack_pointer(Process *proc)
|
|
+void *get_stack_pointer(struct process *proc)
|
|
{
|
|
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_USP, 0);
|
|
}
|
|
|
|
-void *get_return_addr(Process *proc, void *stack_pointer)
|
|
+void *get_return_addr(struct process *proc, void *stack_pointer)
|
|
{
|
|
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_SRP, 0);
|
|
}
|
|
diff --git a/sysdeps/linux-gnu/cris/trace.c b/sysdeps/linux-gnu/cris/trace.c
|
|
index 98cb7d8..7d8cca6 100644
|
|
--- a/sysdeps/linux-gnu/cris/trace.c
|
|
+++ b/sysdeps/linux-gnu/cris/trace.c
|
|
@@ -40,14 +40,14 @@
|
|
# define PTRACE_POKEUSER PTRACE_POKEUSR
|
|
#endif
|
|
|
|
-void get_arch_dep(Process *proc)
|
|
+void get_arch_dep(struct process *proc)
|
|
{
|
|
}
|
|
|
|
/* Returns 1 if syscall, 2 if sysret, 0 otherwise.
|
|
*/
|
|
#define SYSCALL_INSN 0xe93d
|
|
-int syscall_p(Process *proc, int status, int *sysnum)
|
|
+int syscall_p(struct process *proc, int status, int *sysnum)
|
|
{
|
|
if (WIFSTOPPED(status)
|
|
&& WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
|
|
@@ -71,7 +71,7 @@ int syscall_p(Process *proc, int status, int *sysnum)
|
|
return 0;
|
|
}
|
|
|
|
-long gimme_arg(enum tof type, Process *proc, int arg_num,
|
|
+long gimme_arg(enum tof type, struct process *proc, int arg_num,
|
|
struct arg_type_info *info)
|
|
{
|
|
int pid = proc->pid;
|
|
diff --git a/sysdeps/linux-gnu/events.c b/sysdeps/linux-gnu/events.c
|
|
index 077a656..6cda97e 100644
|
|
--- a/sysdeps/linux-gnu/events.c
|
|
+++ b/sysdeps/linux-gnu/events.c
|
|
@@ -48,7 +48,7 @@ static Event * delayed_events = NULL;
|
|
static Event * end_delayed_events = NULL;
|
|
|
|
static enum callback_status
|
|
-first (Process * proc, void * data)
|
|
+first(struct process *proc, void *data)
|
|
{
|
|
return CBS_STOP;
|
|
}
|
|
@@ -83,12 +83,12 @@ each_qd_event(enum ecb_status (*pred)(Event *, void *), void * data)
|
|
Event * event;
|
|
for (event = prev; event != NULL; ) {
|
|
switch ((*pred)(event, data)) {
|
|
- case ecb_cont:
|
|
+ case ECB_CONT:
|
|
prev = event;
|
|
event = event->next;
|
|
continue;
|
|
|
|
- case ecb_deque:
|
|
+ case ECB_DEQUE:
|
|
debug(DEBUG_FUNCTION, "dequeuing event %d for %d",
|
|
event->type,
|
|
event->proc != NULL ? event->proc->pid : -1);
|
|
@@ -106,7 +106,7 @@ each_qd_event(enum ecb_status (*pred)(Event *, void *), void * data)
|
|
end_delayed_events = NULL;
|
|
/* fall-through */
|
|
|
|
- case ecb_yield:
|
|
+ case ECB_YIELD:
|
|
return event;
|
|
}
|
|
}
|
|
@@ -120,9 +120,9 @@ event_process_not_reenabling(Event * event, void * data)
|
|
if (event->proc == NULL
|
|
|| event->proc->leader == NULL
|
|
|| event->proc->leader->event_handler == NULL)
|
|
- return ecb_deque;
|
|
+ return ECB_DEQUE;
|
|
else
|
|
- return ecb_cont;
|
|
+ return ECB_CONT;
|
|
}
|
|
|
|
static Event *
|
|
@@ -188,7 +188,7 @@ next_event(void)
|
|
* now) the pain of figuring this out all over again.
|
|
* Petr Machata 2011-11-22. */
|
|
int i = 0;
|
|
- for (; i < 100 && process_status(pid) != ps_tracing_stop; ++i) {
|
|
+ for (; i < 100 && process_status(pid) != PS_TRACING_STOP; ++i) {
|
|
debug(2, "waiting for %d to stop", pid);
|
|
usleep(10000);
|
|
}
|
|
@@ -199,7 +199,7 @@ next_event(void)
|
|
}
|
|
get_arch_dep(event.proc);
|
|
debug(3, "event from pid %u", pid);
|
|
- Process *leader = event.proc->leader;
|
|
+ struct process *leader = event.proc->leader;
|
|
|
|
/* The process should be stopped after the waitpid call. But
|
|
* when the whole thread group is terminated, we see
|
|
@@ -341,13 +341,13 @@ static enum ecb_status
|
|
event_for_proc(struct Event *event, void *data)
|
|
{
|
|
if (event->proc == data)
|
|
- return ecb_deque;
|
|
+ return ECB_DEQUE;
|
|
else
|
|
- return ecb_cont;
|
|
+ return ECB_CONT;
|
|
}
|
|
|
|
void
|
|
-delete_events_for(struct Process *proc)
|
|
+delete_events_for(struct process *proc)
|
|
{
|
|
struct Event *event;
|
|
while ((event = each_qd_event(&event_for_proc, proc)) != NULL)
|
|
diff --git a/sysdeps/linux-gnu/events.h b/sysdeps/linux-gnu/events.h
|
|
index 3802aff..51ef309 100644
|
|
--- a/sysdeps/linux-gnu/events.h
|
|
+++ b/sysdeps/linux-gnu/events.h
|
|
@@ -26,16 +26,16 @@
|
|
/* Declarations for event que functions. */
|
|
|
|
enum ecb_status {
|
|
- ecb_cont, /* The iteration should continue. */
|
|
- ecb_yield, /* The iteration should stop, yielding this
|
|
+ ECB_CONT, /* The iteration should continue. */
|
|
+ ECB_YIELD, /* The iteration should stop, yielding this
|
|
* event. */
|
|
- ecb_deque, /* Like ecb_stop, but the event should be removed
|
|
+ ECB_DEQUE, /* Like ECB_STOP, but the event should be removed
|
|
* from the queue. */
|
|
};
|
|
|
|
struct Event *each_qd_event(enum ecb_status (*cb)(struct Event *event,
|
|
void *data), void *data);
|
|
-void delete_events_for(struct Process * proc);
|
|
+void delete_events_for(struct process *proc);
|
|
void enque_event(struct Event *event);
|
|
|
|
#endif /* SYSDEPS_LINUX_GNU_EVENTS_H */
|
|
diff --git a/sysdeps/linux-gnu/ia64/fetch.c b/sysdeps/linux-gnu/ia64/fetch.c
|
|
index 54dc5b8..e90dbed 100644
|
|
--- a/sysdeps/linux-gnu/ia64/fetch.c
|
|
+++ b/sysdeps/linux-gnu/ia64/fetch.c
|
|
@@ -63,7 +63,7 @@ union cfm_t {
|
|
};
|
|
|
|
static int
|
|
-fetch_context_init(struct Process *proc, struct fetch_context *context)
|
|
+fetch_context_init(struct process *proc, struct fetch_context *context)
|
|
{
|
|
context->slot_n = 0;
|
|
context->flt = 8;
|
|
@@ -76,7 +76,7 @@ fetch_context_init(struct Process *proc, struct fetch_context *context)
|
|
}
|
|
|
|
struct fetch_context *
|
|
-arch_fetch_arg_init(enum tof type, struct Process *proc,
|
|
+arch_fetch_arg_init(enum tof type, struct process *proc,
|
|
struct arg_type_info *ret_info)
|
|
{
|
|
struct fetch_context *context = malloc(sizeof(*context));
|
|
@@ -91,7 +91,7 @@ arch_fetch_arg_init(enum tof type, struct Process *proc,
|
|
}
|
|
|
|
struct fetch_context *
|
|
-arch_fetch_arg_clone(struct Process *proc,
|
|
+arch_fetch_arg_clone(struct process *proc,
|
|
struct fetch_context *context)
|
|
{
|
|
struct fetch_context *clone = malloc(sizeof(*context));
|
|
@@ -102,7 +102,7 @@ arch_fetch_arg_clone(struct Process *proc,
|
|
}
|
|
|
|
int
|
|
-allocate_stack_slot(struct fetch_context *ctx, struct Process *proc,
|
|
+allocate_stack_slot(struct fetch_context *ctx, struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep)
|
|
{
|
|
size_t al = type_alignof(proc, info);
|
|
@@ -121,7 +121,7 @@ allocate_stack_slot(struct fetch_context *ctx, struct Process *proc,
|
|
}
|
|
|
|
static int
|
|
-allocate_reg(struct fetch_context *ctx, struct Process *proc,
|
|
+allocate_reg(struct fetch_context *ctx, struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep)
|
|
{
|
|
if (ctx->slot_n >= 8)
|
|
@@ -152,7 +152,7 @@ allocate_reg(struct fetch_context *ctx, struct Process *proc,
|
|
}
|
|
|
|
static int
|
|
-copy_aggregate_part(struct fetch_context *ctx, struct Process *proc,
|
|
+copy_aggregate_part(struct fetch_context *ctx, struct process *proc,
|
|
unsigned char *buf, size_t size)
|
|
{
|
|
size_t slots = (size + 7) / 8;
|
|
@@ -176,7 +176,7 @@ copy_aggregate_part(struct fetch_context *ctx, struct Process *proc,
|
|
}
|
|
|
|
static int
|
|
-allocate_arg(struct fetch_context *ctx, struct Process *proc,
|
|
+allocate_arg(struct fetch_context *ctx, struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep)
|
|
{
|
|
size_t sz = type_sizeof(proc, info);
|
|
@@ -213,7 +213,7 @@ fpreg_to_double (struct ia64_fpreg *fp) {
|
|
}
|
|
|
|
static int
|
|
-allocate_float(struct fetch_context *ctx, struct Process *proc,
|
|
+allocate_float(struct fetch_context *ctx, struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep,
|
|
int take_slot)
|
|
{
|
|
@@ -281,7 +281,7 @@ get_hfa_type(struct arg_type_info *info, size_t *countp)
|
|
}
|
|
|
|
static int
|
|
-allocate_hfa(struct fetch_context *ctx, struct Process *proc,
|
|
+allocate_hfa(struct fetch_context *ctx, struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep,
|
|
enum arg_type hfa_type, size_t hfa_count)
|
|
{
|
|
@@ -366,7 +366,7 @@ allocate_hfa(struct fetch_context *ctx, struct Process *proc,
|
|
}
|
|
|
|
static int
|
|
-allocate_ret(struct fetch_context *ctx, struct Process *proc,
|
|
+allocate_ret(struct fetch_context *ctx, struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep)
|
|
{
|
|
size_t sz = type_sizeof(proc, info);
|
|
@@ -405,7 +405,7 @@ allocate_ret(struct fetch_context *ctx, struct Process *proc,
|
|
|
|
int
|
|
arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
|
|
- struct Process *proc,
|
|
+ struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep)
|
|
{
|
|
switch (info->type) {
|
|
@@ -446,7 +446,7 @@ arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
|
|
|
|
int
|
|
arch_fetch_retval(struct fetch_context *ctx, enum tof type,
|
|
- struct Process *proc, struct arg_type_info *info,
|
|
+ struct process *proc, struct arg_type_info *info,
|
|
struct value *valuep)
|
|
{
|
|
if (fetch_context_init(proc, ctx) < 0)
|
|
diff --git a/sysdeps/linux-gnu/ia64/plt.c b/sysdeps/linux-gnu/ia64/plt.c
|
|
index a29488f..f6bc939 100644
|
|
--- a/sysdeps/linux-gnu/ia64/plt.c
|
|
+++ b/sysdeps/linux-gnu/ia64/plt.c
|
|
@@ -68,12 +68,13 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela)
|
|
}
|
|
|
|
void *
|
|
-sym2addr(Process *proc, struct library_symbol *sym) {
|
|
+sym2addr(struct process *proc, struct library_symbol *sym)
|
|
+{
|
|
return sym->enter_addr;
|
|
}
|
|
|
|
int
|
|
-arch_translate_address_dyn(struct Process *proc,
|
|
+arch_translate_address_dyn(struct process *proc,
|
|
arch_addr_t addr, arch_addr_t *ret)
|
|
{
|
|
errno = 0;
|
|
diff --git a/sysdeps/linux-gnu/ia64/regs.c b/sysdeps/linux-gnu/ia64/regs.c
|
|
index cbc2744..fb79e8a 100644
|
|
--- a/sysdeps/linux-gnu/ia64/regs.c
|
|
+++ b/sysdeps/linux-gnu/ia64/regs.c
|
|
@@ -34,7 +34,8 @@
|
|
#include "common.h"
|
|
|
|
void *
|
|
-get_instruction_pointer(Process *proc) {
|
|
+get_instruction_pointer(struct process *proc)
|
|
+{
|
|
unsigned long ip = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IIP, 0);
|
|
unsigned long slot =
|
|
(ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IPSR, 0) >> 41) & 3;
|
|
@@ -43,7 +44,8 @@ get_instruction_pointer(Process *proc) {
|
|
}
|
|
|
|
void
|
|
-set_instruction_pointer(Process *proc, void *addr) {
|
|
+set_instruction_pointer(struct process *proc, void *addr)
|
|
+{
|
|
|
|
unsigned long newip = (unsigned long)addr;
|
|
unsigned long slot = (unsigned long)addr & 0xf;
|
|
@@ -59,7 +61,8 @@ set_instruction_pointer(Process *proc, void *addr) {
|
|
}
|
|
|
|
void *
|
|
-get_stack_pointer(Process *proc) {
|
|
+get_stack_pointer(struct process *proc)
|
|
+{
|
|
long l = ptrace(PTRACE_PEEKUSER, proc->pid, PT_R12, 0);
|
|
if (l == -1 && errno)
|
|
return NULL;
|
|
@@ -67,7 +70,8 @@ get_stack_pointer(Process *proc) {
|
|
}
|
|
|
|
void *
|
|
-get_return_addr(Process *proc, void *stack_pointer) {
|
|
+get_return_addr(struct process *proc, void *stack_pointer)
|
|
+{
|
|
long l = ptrace(PTRACE_PEEKUSER, proc->pid, PT_B0, 0);
|
|
if (l == -1 && errno)
|
|
return NULL;
|
|
@@ -75,6 +79,7 @@ get_return_addr(Process *proc, void *stack_pointer) {
|
|
}
|
|
|
|
void
|
|
-set_return_addr(Process *proc, void *addr) {
|
|
+set_return_addr(struct process *proc, void *addr)
|
|
+{
|
|
ptrace(PTRACE_POKEUSER, proc->pid, PT_B0, addr);
|
|
}
|
|
diff --git a/sysdeps/linux-gnu/ia64/trace.c b/sysdeps/linux-gnu/ia64/trace.c
|
|
index e608275..9e554ef 100644
|
|
--- a/sysdeps/linux-gnu/ia64/trace.c
|
|
+++ b/sysdeps/linux-gnu/ia64/trace.c
|
|
@@ -70,7 +70,8 @@ union cfm_t {
|
|
};
|
|
|
|
int
|
|
-syscall_p(Process *proc, int status, int *sysnum) {
|
|
+syscall_p(struct process *proc, int status, int *sysnum)
|
|
+{
|
|
if (WIFSTOPPED(status)
|
|
&& WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
|
|
long l = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IPSR, 0);
|
|
@@ -141,5 +142,6 @@ syscall_p(Process *proc, int status, int *sysnum) {
|
|
}
|
|
|
|
void
|
|
-get_arch_dep(Process *proc) {
|
|
+get_arch_dep(struct process *proc)
|
|
+{
|
|
}
|
|
diff --git a/sysdeps/linux-gnu/m68k/fetch.c b/sysdeps/linux-gnu/m68k/fetch.c
|
|
index f6d8a0b..24bd8f0 100644
|
|
--- a/sysdeps/linux-gnu/m68k/fetch.c
|
|
+++ b/sysdeps/linux-gnu/m68k/fetch.c
|
|
@@ -43,7 +43,7 @@ struct fetch_context
|
|
};
|
|
|
|
static int
|
|
-fetch_register_banks(struct Process *proc, struct fetch_context *context,
|
|
+fetch_register_banks(struct process *proc, struct fetch_context *context,
|
|
int floating)
|
|
{
|
|
if (ptrace(PTRACE_GETREGS, proc->pid, 0, &context->regs) < 0)
|
|
@@ -57,7 +57,7 @@ fetch_register_banks(struct Process *proc, struct fetch_context *context,
|
|
}
|
|
|
|
struct fetch_context *
|
|
-arch_fetch_arg_init(enum tof type, struct Process *proc,
|
|
+arch_fetch_arg_init(enum tof type, struct process *proc,
|
|
struct arg_type_info *ret_info)
|
|
{
|
|
struct fetch_context *context = malloc(sizeof(*context));
|
|
@@ -92,7 +92,7 @@ arch_fetch_arg_init(enum tof type, struct Process *proc,
|
|
}
|
|
|
|
struct fetch_context *
|
|
-arch_fetch_arg_clone(struct Process *proc, struct fetch_context *context)
|
|
+arch_fetch_arg_clone(struct process *proc, struct fetch_context *context)
|
|
{
|
|
struct fetch_context *ret = malloc(sizeof(*ret));
|
|
if (ret == NULL)
|
|
@@ -103,7 +103,7 @@ arch_fetch_arg_clone(struct Process *proc, struct fetch_context *context)
|
|
|
|
int
|
|
arch_fetch_arg_next(struct fetch_context *context, enum tof type,
|
|
- struct Process *proc, struct arg_type_info *info,
|
|
+ struct process *proc, struct arg_type_info *info,
|
|
struct value *valuep)
|
|
{
|
|
size_t sz = type_sizeof(proc, info);
|
|
@@ -143,7 +143,7 @@ arch_fetch_arg_next(struct fetch_context *context, enum tof type,
|
|
|
|
int
|
|
arch_fetch_retval(struct fetch_context *context, enum tof type,
|
|
- struct Process *proc, struct arg_type_info *info,
|
|
+ struct process *proc, struct arg_type_info *info,
|
|
struct value *valuep)
|
|
{
|
|
if (fetch_register_banks(proc, context, type == LT_TOF_FUNCTIONR) < 0)
|
|
diff --git a/sysdeps/linux-gnu/m68k/plt.c b/sysdeps/linux-gnu/m68k/plt.c
|
|
index c1b37dd..dcd6878 100644
|
|
--- a/sysdeps/linux-gnu/m68k/plt.c
|
|
+++ b/sysdeps/linux-gnu/m68k/plt.c
|
|
@@ -30,6 +30,7 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
|
|
}
|
|
|
|
void *
|
|
-sym2addr(Process *proc, struct library_symbol *sym) {
|
|
+sym2addr(struct process *proc, struct library_symbol *sym)
|
|
+{
|
|
return sym->enter_addr;
|
|
}
|
|
diff --git a/sysdeps/linux-gnu/m68k/regs.c b/sysdeps/linux-gnu/m68k/regs.c
|
|
index 4afdfbb..c2fafe1 100644
|
|
--- a/sysdeps/linux-gnu/m68k/regs.c
|
|
+++ b/sysdeps/linux-gnu/m68k/regs.c
|
|
@@ -36,26 +36,31 @@
|
|
#endif
|
|
|
|
void *
|
|
-get_instruction_pointer(Process *proc) {
|
|
+get_instruction_pointer(struct process *proc)
|
|
+{
|
|
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_PC, 0);
|
|
}
|
|
|
|
void
|
|
-set_instruction_pointer(Process *proc, void *addr) {
|
|
+set_instruction_pointer(struct process *proc, void *addr)
|
|
+{
|
|
ptrace(PTRACE_POKEUSER, proc->pid, 4 * PT_PC, addr);
|
|
}
|
|
|
|
void *
|
|
-get_stack_pointer(Process *proc) {
|
|
+get_stack_pointer(struct process *proc)
|
|
+{
|
|
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_USP, 0);
|
|
}
|
|
|
|
void *
|
|
-get_return_addr(Process *proc, void *stack_pointer) {
|
|
+get_return_addr(struct process *proc, void *stack_pointer)
|
|
+{
|
|
return (void *)ptrace(PTRACE_PEEKTEXT, proc->pid, stack_pointer, 0);
|
|
}
|
|
|
|
void
|
|
-set_return_addr(Process *proc, void *addr) {
|
|
+set_return_addr(struct process *proc, void *addr)
|
|
+{
|
|
ptrace(PTRACE_POKETEXT, proc->pid, proc->stack_pointer, addr);
|
|
}
|
|
diff --git a/sysdeps/linux-gnu/m68k/trace.c b/sysdeps/linux-gnu/m68k/trace.c
|
|
index 311ffd5..01b5253 100644
|
|
--- a/sysdeps/linux-gnu/m68k/trace.c
|
|
+++ b/sysdeps/linux-gnu/m68k/trace.c
|
|
@@ -40,13 +40,15 @@
|
|
#endif
|
|
|
|
void
|
|
-get_arch_dep(Process *proc) {
|
|
+get_arch_dep(struct process *proc)
|
|
+{
|
|
}
|
|
|
|
/* Returns 1 if syscall, 2 if sysret, 0 otherwise.
|
|
*/
|
|
int
|
|
-syscall_p(Process *proc, int status, int *sysnum) {
|
|
+syscall_p(struct process *proc, int status, int *sysnum)
|
|
+{
|
|
int depth;
|
|
|
|
if (WIFSTOPPED(status)
|
|
diff --git a/sysdeps/linux-gnu/mipsel/arch.h b/sysdeps/linux-gnu/mipsel/arch.h
|
|
index 684b546..ba1220d 100644
|
|
--- a/sysdeps/linux-gnu/mipsel/arch.h
|
|
+++ b/sysdeps/linux-gnu/mipsel/arch.h
|
|
@@ -1,5 +1,6 @@
|
|
/*
|
|
* This file is part of ltrace.
|
|
+ * Copyright (C) 2013 Petr Machata
|
|
* Copyright (C) 2006 Eric Vaitl
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
@@ -43,7 +44,7 @@ struct arch_ltelf_data {
|
|
#define ARCH_HAVE_GET_SYMINFO
|
|
#define ARCH_HAVE_DYNLINK_DONE
|
|
#define ARCH_HAVE_ADD_PLT_ENTRY
|
|
-#define ARCH_HAVE_ATOMIC_SINGLESTEP
|
|
+#define ARCH_HAVE_SW_SINGLESTEP
|
|
#define ARCH_HAVE_SYMBOL_RET
|
|
|
|
#define ARCH_HAVE_LIBRARY_SYMBOL_DATA
|
|
diff --git a/sysdeps/linux-gnu/mipsel/plt.c b/sysdeps/linux-gnu/mipsel/plt.c
|
|
index b277fbc..ce33406 100644
|
|
--- a/sysdeps/linux-gnu/mipsel/plt.c
|
|
+++ b/sysdeps/linux-gnu/mipsel/plt.c
|
|
@@ -104,7 +104,8 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela)
|
|
breakpoint changes I just add a new breakpoint for the new address.
|
|
*/
|
|
void *
|
|
-sym2addr(Process *proc, struct library_symbol *sym) {
|
|
+sym2addr(struct process *proc, struct library_symbol *sym)
|
|
+{
|
|
long ret;
|
|
|
|
if (sym->arch.pltalways
|
|
@@ -125,7 +126,7 @@ sym2addr(Process *proc, struct library_symbol *sym) {
|
|
/* Address of run time loader map, used for debugging. */
|
|
#define DT_MIPS_RLD_MAP 0x70000016
|
|
int
|
|
-arch_find_dl_debug(struct Process *proc, arch_addr_t dyn_addr,
|
|
+arch_find_dl_debug(struct process *proc, arch_addr_t dyn_addr,
|
|
arch_addr_t *ret)
|
|
{
|
|
arch_addr_t rld_addr;
|
|
@@ -251,11 +252,11 @@ arch_elf_destroy(struct ltelf *lte)
|
|
|
|
/* When functions return we check if the symbol needs an updated
|
|
breakpoint with the resolved address. */
|
|
-void arch_symbol_ret(struct Process *proc, struct library_symbol *libsym)
|
|
+void arch_symbol_ret(struct process *proc, struct library_symbol *libsym)
|
|
{
|
|
struct breakpoint *bp;
|
|
arch_addr_t resolved_addr;
|
|
- struct Process *leader = proc->leader;
|
|
+ struct process *leader = proc->leader;
|
|
|
|
/* Only deal with unresolved symbols. */
|
|
if (libsym->arch.type != MIPS_PLT_UNRESOLVED)
|
|
@@ -302,7 +303,7 @@ err:
|
|
static enum callback_status
|
|
cb_enable_breakpoint_sym(struct library_symbol *libsym, void *data)
|
|
{
|
|
- struct Process *proc = data;
|
|
+ struct process *proc = data;
|
|
arch_addr_t bp_addr;
|
|
|
|
if (!libsym->arch.gotonly)
|
|
@@ -329,19 +330,19 @@ cb_enable_breakpoint_sym(struct library_symbol *libsym, void *data)
|
|
}
|
|
|
|
static enum callback_status
|
|
-cb_enable_breakpoint_lib(struct Process *proc, struct library *lib, void *data)
|
|
+cb_enable_breakpoint_lib(struct process *proc, struct library *lib, void *data)
|
|
{
|
|
library_each_symbol(lib, NULL, cb_enable_breakpoint_sym, proc);
|
|
return CBS_CONT;
|
|
}
|
|
|
|
-void arch_dynlink_done(struct Process *proc)
|
|
+void arch_dynlink_done(struct process *proc)
|
|
{
|
|
proc_each_library(proc->leader, NULL, cb_enable_breakpoint_lib, NULL);
|
|
}
|
|
|
|
enum plt_status
|
|
-arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
|
|
+arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
|
|
const char *a_name, GElf_Rela *rela, size_t ndx,
|
|
struct library_symbol **ret)
|
|
{
|
|
@@ -350,7 +351,7 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
|
|
|
|
struct library_symbol *libsym = malloc(sizeof(*libsym));
|
|
if (libsym == NULL)
|
|
- return plt_fail;
|
|
+ return PLT_FAIL;
|
|
|
|
GElf_Addr addr = arch_plt_sym_val(lte, sym_index, 0);
|
|
|
|
@@ -389,12 +390,12 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
|
|
}
|
|
|
|
*ret = libsym;
|
|
- return plt_ok;
|
|
+ return PLT_OK;
|
|
|
|
fail:
|
|
free(name);
|
|
free(libsym);
|
|
- return plt_fail;
|
|
+ return PLT_FAIL;
|
|
}
|
|
|
|
int
|
|
diff --git a/sysdeps/linux-gnu/mipsel/regs.c b/sysdeps/linux-gnu/mipsel/regs.c
|
|
index 8731ac5..19f97cb 100644
|
|
--- a/sysdeps/linux-gnu/mipsel/regs.c
|
|
+++ b/sysdeps/linux-gnu/mipsel/regs.c
|
|
@@ -49,7 +49,8 @@
|
|
\return The current instruction pointer.
|
|
*/
|
|
void *
|
|
-get_instruction_pointer(Process *proc) {
|
|
+get_instruction_pointer(struct process *proc)
|
|
+{
|
|
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0);
|
|
}
|
|
|
|
@@ -63,7 +64,8 @@ get_instruction_pointer(Process *proc) {
|
|
we \c continue_process() after a breakpoint. Check if this is OK.
|
|
*/
|
|
void
|
|
-set_instruction_pointer(Process *proc, void *addr) {
|
|
+set_instruction_pointer(struct process *proc, void *addr)
|
|
+{
|
|
ptrace(PTRACE_POKEUSER, proc->pid, off_pc, addr);
|
|
}
|
|
|
|
@@ -72,7 +74,8 @@ set_instruction_pointer(Process *proc, void *addr) {
|
|
\return The current stack pointer.
|
|
*/
|
|
void *
|
|
-get_stack_pointer(Process *proc) {
|
|
+get_stack_pointer(struct process *proc)
|
|
+{
|
|
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_sp, 0);
|
|
}
|
|
|
|
@@ -87,11 +90,13 @@ get_stack_pointer(Process *proc) {
|
|
unused.
|
|
*/
|
|
void *
|
|
-get_return_addr(Process *proc, void *stack_pointer) {
|
|
+get_return_addr(struct process *proc, void *stack_pointer)
|
|
+{
|
|
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_lr, 0);
|
|
}
|
|
|
|
void
|
|
-set_return_addr(Process *proc, void *addr) {
|
|
+set_return_addr(struct process *proc, void *addr)
|
|
+{
|
|
ptrace(PTRACE_POKEUSER, proc->pid, off_lr, addr);
|
|
}
|
|
diff --git a/sysdeps/linux-gnu/mipsel/trace.c b/sysdeps/linux-gnu/mipsel/trace.c
|
|
index db9ec21..f553166 100644
|
|
--- a/sysdeps/linux-gnu/mipsel/trace.c
|
|
+++ b/sysdeps/linux-gnu/mipsel/trace.c
|
|
@@ -1,5 +1,6 @@
|
|
/*
|
|
* This file is part of ltrace.
|
|
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
|
|
* Copyright (C) 2012 Edgar E. Iglesias, Axis Communications
|
|
* Copyright (C) 2010 Arnaud Patard, Mandriva SA
|
|
* Copyright (C) 2008,2009 Juan Cespedes
|
|
@@ -64,7 +65,8 @@
|
|
private data area.
|
|
*/
|
|
void
|
|
-get_arch_dep(Process *proc) {
|
|
+get_arch_dep(struct process *proc)
|
|
+{
|
|
}
|
|
|
|
/**
|
|
@@ -85,7 +87,8 @@ get_arch_dep(Process *proc) {
|
|
for the system calls is 4000.
|
|
*/
|
|
int
|
|
-syscall_p(Process *proc, int status, int *sysnum) {
|
|
+syscall_p(struct process *proc, int status, int *sysnum)
|
|
+{
|
|
if (WIFSTOPPED(status)
|
|
&& WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
|
|
/* get the user's pc (plus 8) */
|
|
@@ -141,7 +144,7 @@ mips32_relative_offset (uint32_t inst)
|
|
return ((itype_immediate(inst) ^ 0x8000) - 0x8000) << 2;
|
|
}
|
|
|
|
-int mips_next_pcs(struct Process *proc, uint32_t pc, uint32_t *newpc)
|
|
+int mips_next_pcs(struct process *proc, uint32_t pc, uint32_t *newpc)
|
|
{
|
|
uint32_t inst, rx;
|
|
int op;
|
|
@@ -261,10 +264,10 @@ fail:
|
|
return 0;
|
|
}
|
|
|
|
-int
|
|
-arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
|
|
- int (*add_cb)(void *addr, void *data),
|
|
- void *add_cb_data)
|
|
+enum sw_singlestep_status
|
|
+arch_sw_singlestep(struct process *proc, struct breakpoint *bp,
|
|
+ int (*add_cb)(arch_addr_t, struct sw_singlestep_data *),
|
|
+ struct sw_singlestep_data *add_cb_data)
|
|
{
|
|
uint32_t pc = (uint32_t) get_instruction_pointer(proc);
|
|
uint32_t newpcs[2];
|
|
@@ -281,11 +284,11 @@ arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
|
|
}
|
|
|
|
if (add_cb(baddr, add_cb_data) < 0)
|
|
- return -1;
|
|
+ return SWS_FAIL;
|
|
}
|
|
|
|
ptrace(PTRACE_SYSCALL, proc->pid, 0, 0);
|
|
- return 0;
|
|
+ return SWS_OK;
|
|
}
|
|
|
|
/**
|
|
@@ -317,7 +320,8 @@ I'm not doing any floating point support here.
|
|
|
|
*/
|
|
long
|
|
-gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info)
|
|
+gimme_arg(enum tof type, struct process *proc, int arg_num,
|
|
+ struct arg_type_info *info)
|
|
{
|
|
long ret;
|
|
long addr;
|
|
diff --git a/sysdeps/linux-gnu/ppc/arch.h b/sysdeps/linux-gnu/ppc/arch.h
|
|
index fb8768a..3b903ee 100644
|
|
--- a/sysdeps/linux-gnu/ppc/arch.h
|
|
+++ b/sysdeps/linux-gnu/ppc/arch.h
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
* This file is part of ltrace.
|
|
- * Copyright (C) 2012 Petr Machata
|
|
+ * Copyright (C) 2012,2013 Petr Machata
|
|
* Copyright (C) 2006 Paul Gilliam
|
|
* Copyright (C) 2002,2004 Juan Cespedes
|
|
*
|
|
@@ -37,7 +37,7 @@
|
|
#define ARCH_SUPPORTS_OPD
|
|
#endif
|
|
|
|
-#define ARCH_HAVE_ATOMIC_SINGLESTEP
|
|
+#define ARCH_HAVE_SW_SINGLESTEP
|
|
#define ARCH_HAVE_ADD_PLT_ENTRY
|
|
#define ARCH_HAVE_TRANSLATE_ADDRESS
|
|
#define ARCH_HAVE_DYNLINK_DONE
|
|
diff --git a/sysdeps/linux-gnu/ppc/fetch.c b/sysdeps/linux-gnu/ppc/fetch.c
|
|
index 9963a1e..ed38336 100644
|
|
--- a/sysdeps/linux-gnu/ppc/fetch.c
|
|
+++ b/sysdeps/linux-gnu/ppc/fetch.c
|
|
@@ -31,7 +31,7 @@
|
|
#include "proc.h"
|
|
#include "value.h"
|
|
|
|
-static int allocate_gpr(struct fetch_context *ctx, struct Process *proc,
|
|
+static int allocate_gpr(struct fetch_context *ctx, struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep);
|
|
|
|
/* Floating point registers have the same width on 32-bit as well as
|
|
@@ -66,7 +66,7 @@ struct fetch_context {
|
|
};
|
|
|
|
static int
|
|
-fetch_context_init(struct Process *proc, struct fetch_context *context)
|
|
+fetch_context_init(struct process *proc, struct fetch_context *context)
|
|
{
|
|
context->greg = 3;
|
|
context->freg = 1;
|
|
@@ -108,7 +108,7 @@ fetch_context_init(struct Process *proc, struct fetch_context *context)
|
|
}
|
|
|
|
struct fetch_context *
|
|
-arch_fetch_arg_init(enum tof type, struct Process *proc,
|
|
+arch_fetch_arg_init(enum tof type, struct process *proc,
|
|
struct arg_type_info *ret_info)
|
|
{
|
|
struct fetch_context *context = malloc(sizeof(*context));
|
|
@@ -132,7 +132,7 @@ arch_fetch_arg_init(enum tof type, struct Process *proc,
|
|
}
|
|
|
|
struct fetch_context *
|
|
-arch_fetch_arg_clone(struct Process *proc,
|
|
+arch_fetch_arg_clone(struct process *proc,
|
|
struct fetch_context *context)
|
|
{
|
|
struct fetch_context *clone = malloc(sizeof(*context));
|
|
@@ -143,7 +143,7 @@ arch_fetch_arg_clone(struct Process *proc,
|
|
}
|
|
|
|
static int
|
|
-allocate_stack_slot(struct fetch_context *ctx, struct Process *proc,
|
|
+allocate_stack_slot(struct fetch_context *ctx, struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep)
|
|
{
|
|
size_t sz = type_sizeof(proc, info);
|
|
@@ -170,7 +170,7 @@ allocate_stack_slot(struct fetch_context *ctx, struct Process *proc,
|
|
}
|
|
|
|
static uint64_t
|
|
-read_gpr(struct fetch_context *ctx, struct Process *proc, int reg_num)
|
|
+read_gpr(struct fetch_context *ctx, struct process *proc, int reg_num)
|
|
{
|
|
if (proc->e_machine == EM_PPC)
|
|
return ctx->regs.r32[reg_num];
|
|
@@ -215,7 +215,7 @@ align_small_int(unsigned char *buf, size_t w, size_t sz)
|
|
}
|
|
|
|
static int
|
|
-allocate_gpr(struct fetch_context *ctx, struct Process *proc,
|
|
+allocate_gpr(struct fetch_context *ctx, struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep)
|
|
{
|
|
if (ctx->greg > 10)
|
|
@@ -245,7 +245,7 @@ allocate_gpr(struct fetch_context *ctx, struct Process *proc,
|
|
}
|
|
|
|
static int
|
|
-allocate_float(struct fetch_context *ctx, struct Process *proc,
|
|
+allocate_float(struct fetch_context *ctx, struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep)
|
|
{
|
|
int pool = proc->e_machine == EM_PPC64 ? 13 : 8;
|
|
@@ -276,7 +276,7 @@ allocate_float(struct fetch_context *ctx, struct Process *proc,
|
|
}
|
|
|
|
static int
|
|
-allocate_argument(struct fetch_context *ctx, struct Process *proc,
|
|
+allocate_argument(struct fetch_context *ctx, struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep)
|
|
{
|
|
/* Floating point types and void are handled specially. */
|
|
@@ -400,7 +400,7 @@ allocate_argument(struct fetch_context *ctx, struct Process *proc,
|
|
|
|
int
|
|
arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
|
|
- struct Process *proc,
|
|
+ struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep)
|
|
{
|
|
return allocate_argument(ctx, proc, info, valuep);
|
|
@@ -408,7 +408,7 @@ arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
|
|
|
|
int
|
|
arch_fetch_retval(struct fetch_context *ctx, enum tof type,
|
|
- struct Process *proc, struct arg_type_info *info,
|
|
+ struct process *proc, struct arg_type_info *info,
|
|
struct value *valuep)
|
|
{
|
|
if (ctx->ret_struct) {
|
|
diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c
|
|
index f83f087..439b8e8 100644
|
|
--- a/sysdeps/linux-gnu/ppc/plt.c
|
|
+++ b/sysdeps/linux-gnu/ppc/plt.c
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
* This file is part of ltrace.
|
|
- * Copyright (C) 2012 Petr Machata, Red Hat Inc.
|
|
+ * Copyright (C) 2012,2013 Petr Machata, Red Hat Inc.
|
|
* Copyright (C) 2004,2008,2009 Juan Cespedes
|
|
* Copyright (C) 2006 Paul Gilliam
|
|
*
|
|
@@ -125,51 +125,6 @@ host_powerpc64()
|
|
#endif
|
|
}
|
|
|
|
-int
|
|
-read_target_4(struct Process *proc, arch_addr_t addr, uint32_t *lp)
|
|
-{
|
|
- unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0);
|
|
- if (l == -1UL && errno)
|
|
- return -1;
|
|
-#ifdef __powerpc64__
|
|
- l >>= 32;
|
|
-#endif
|
|
- *lp = l;
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int
|
|
-read_target_8(struct Process *proc, arch_addr_t addr, uint64_t *lp)
|
|
-{
|
|
- unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0);
|
|
- if (l == -1UL && errno)
|
|
- return -1;
|
|
- if (host_powerpc64()) {
|
|
- *lp = l;
|
|
- } else {
|
|
- unsigned long l2 = ptrace(PTRACE_PEEKTEXT, proc->pid,
|
|
- addr + 4, 0);
|
|
- if (l2 == -1UL && errno)
|
|
- return -1;
|
|
- *lp = ((uint64_t)l << 32) | l2;
|
|
- }
|
|
- return 0;
|
|
-}
|
|
-
|
|
-int
|
|
-read_target_long(struct Process *proc, arch_addr_t addr, uint64_t *lp)
|
|
-{
|
|
- if (proc->e_machine == EM_PPC) {
|
|
- uint32_t w;
|
|
- int ret = read_target_4(proc, addr, &w);
|
|
- if (ret >= 0)
|
|
- *lp = (uint64_t)w;
|
|
- return ret;
|
|
- } else {
|
|
- return read_target_8(proc, addr, lp);
|
|
- }
|
|
-}
|
|
-
|
|
static void
|
|
mark_as_resolved(struct library_symbol *libsym, GElf_Addr value)
|
|
{
|
|
@@ -178,14 +133,14 @@ mark_as_resolved(struct library_symbol *libsym, GElf_Addr value)
|
|
}
|
|
|
|
void
|
|
-arch_dynlink_done(struct Process *proc)
|
|
+arch_dynlink_done(struct process *proc)
|
|
{
|
|
/* On PPC32 with BSS PLT, we need to enable delayed symbols. */
|
|
struct library_symbol *libsym = NULL;
|
|
while ((libsym = proc_each_symbol(proc, libsym,
|
|
library_symbol_delayed_cb, NULL))) {
|
|
- if (read_target_8(proc, libsym->enter_addr,
|
|
- &libsym->arch.resolved_value) < 0) {
|
|
+ if (proc_read_64(proc, libsym->enter_addr,
|
|
+ &libsym->arch.resolved_value) < 0) {
|
|
fprintf(stderr,
|
|
"couldn't read PLT value for %s(%p): %s\n",
|
|
libsym->name, libsym->enter_addr,
|
|
@@ -258,12 +213,12 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela)
|
|
* ourselves with bias, as the values in OPD have been resolved
|
|
* already. */
|
|
int
|
|
-arch_translate_address_dyn(struct Process *proc,
|
|
+arch_translate_address_dyn(struct process *proc,
|
|
arch_addr_t addr, arch_addr_t *ret)
|
|
{
|
|
if (proc->e_machine == EM_PPC64) {
|
|
uint64_t value;
|
|
- if (read_target_8(proc, addr, &value) < 0) {
|
|
+ if (proc_read_64(proc, addr, &value) < 0) {
|
|
fprintf(stderr,
|
|
"dynamic .opd translation of %p: %s\n",
|
|
addr, strerror(errno));
|
|
@@ -324,7 +279,7 @@ load_opd_data(struct ltelf *lte, struct library *lib)
|
|
}
|
|
|
|
void *
|
|
-sym2addr(struct Process *proc, struct library_symbol *sym)
|
|
+sym2addr(struct process *proc, struct library_symbol *sym)
|
|
{
|
|
return sym->enter_addr;
|
|
}
|
|
@@ -560,7 +515,7 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
|
|
}
|
|
|
|
static int
|
|
-read_plt_slot_value(struct Process *proc, GElf_Addr addr, GElf_Addr *valp)
|
|
+read_plt_slot_value(struct process *proc, GElf_Addr addr, GElf_Addr *valp)
|
|
{
|
|
/* On PPC64, we read from .plt, which contains 8 byte
|
|
* addresses. On PPC32 we read from .plt, which contains 4
|
|
@@ -568,7 +523,7 @@ read_plt_slot_value(struct Process *proc, GElf_Addr addr, GElf_Addr *valp)
|
|
* either can change. */
|
|
uint64_t l;
|
|
/* XXX double cast. */
|
|
- if (read_target_8(proc, (arch_addr_t)(uintptr_t)addr, &l) < 0) {
|
|
+ if (proc_read_64(proc, (arch_addr_t)(uintptr_t)addr, &l) < 0) {
|
|
fprintf(stderr, "ptrace .plt slot value @%#" PRIx64": %s\n",
|
|
addr, strerror(errno));
|
|
return -1;
|
|
@@ -579,7 +534,7 @@ read_plt_slot_value(struct Process *proc, GElf_Addr addr, GElf_Addr *valp)
|
|
}
|
|
|
|
static int
|
|
-unresolve_plt_slot(struct Process *proc, GElf_Addr addr, GElf_Addr value)
|
|
+unresolve_plt_slot(struct process *proc, GElf_Addr addr, GElf_Addr value)
|
|
{
|
|
/* We only modify plt_entry[0], which holds the resolved
|
|
* address of the routine. We keep the TOC and environment
|
|
@@ -594,18 +549,18 @@ unresolve_plt_slot(struct Process *proc, GElf_Addr addr, GElf_Addr value)
|
|
}
|
|
|
|
enum plt_status
|
|
-arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
|
|
+arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
|
|
const char *a_name, GElf_Rela *rela, size_t ndx,
|
|
struct library_symbol **ret)
|
|
{
|
|
if (lte->ehdr.e_machine == EM_PPC) {
|
|
if (lte->arch.secure_plt)
|
|
- return plt_default;
|
|
+ return PLT_DEFAULT;
|
|
|
|
struct library_symbol *libsym = NULL;
|
|
if (default_elf_add_plt_entry(proc, lte, a_name, rela, ndx,
|
|
&libsym) < 0)
|
|
- return plt_fail;
|
|
+ return PLT_FAIL;
|
|
|
|
/* On PPC32 with BSS PLT, delay the symbol until
|
|
* dynamic linker is done. */
|
|
@@ -613,7 +568,7 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
|
|
libsym->delayed = 1;
|
|
|
|
*ret = libsym;
|
|
- return plt_ok;
|
|
+ return PLT_OK;
|
|
}
|
|
|
|
/* PPC64. If we have stubs, we return a chain of breakpoint
|
|
@@ -636,7 +591,7 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
|
|
|
|
if (chain != NULL) {
|
|
*ret = chain;
|
|
- return plt_ok;
|
|
+ return PLT_OK;
|
|
}
|
|
|
|
/* We don't have stub symbols. Find corresponding .plt slot,
|
|
@@ -653,7 +608,7 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
|
|
|
|
GElf_Addr plt_slot_value;
|
|
if (read_plt_slot_value(proc, plt_slot_addr, &plt_slot_value) < 0)
|
|
- return plt_fail;
|
|
+ return PLT_FAIL;
|
|
|
|
char *name = strdup(a_name);
|
|
struct library_symbol *libsym = malloc(sizeof(*libsym));
|
|
@@ -663,7 +618,7 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
|
|
fail:
|
|
free(name);
|
|
free(libsym);
|
|
- return plt_fail;
|
|
+ return PLT_FAIL;
|
|
}
|
|
|
|
/* XXX The double cast should be removed when
|
|
@@ -696,7 +651,7 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
|
|
}
|
|
|
|
*ret = libsym;
|
|
- return plt_ok;
|
|
+ return PLT_OK;
|
|
}
|
|
|
|
void
|
|
@@ -712,7 +667,7 @@ arch_elf_destroy(struct ltelf *lte)
|
|
}
|
|
|
|
static void
|
|
-dl_plt_update_bp_on_hit(struct breakpoint *bp, struct Process *proc)
|
|
+dl_plt_update_bp_on_hit(struct breakpoint *bp, struct process *proc)
|
|
{
|
|
debug(DEBUG_PROCESS, "pid=%d dl_plt_update_bp_on_hit %s(%p)",
|
|
proc->pid, breakpoint_name(bp), bp->addr);
|
|
@@ -752,7 +707,7 @@ cb_on_all_stopped(struct process_stopping_handler *self)
|
|
static enum callback_status
|
|
cb_keep_stepping_p(struct process_stopping_handler *self)
|
|
{
|
|
- struct Process *proc = self->task_enabling_breakpoint;
|
|
+ struct process *proc = self->task_enabling_breakpoint;
|
|
struct library_symbol *libsym = self->breakpoint_being_enabled->libsym;
|
|
|
|
GElf_Addr value;
|
|
@@ -799,7 +754,7 @@ cb_keep_stepping_p(struct process_stopping_handler *self)
|
|
/* Install breakpoint to the address where the change takes
|
|
* place. If we fail, then that just means that we'll have to
|
|
* singlestep the next time around as well. */
|
|
- struct Process *leader = proc->leader;
|
|
+ struct process *leader = proc->leader;
|
|
if (leader == NULL || leader->arch.dl_plt_update_bp != NULL)
|
|
goto done;
|
|
|
|
@@ -827,7 +782,7 @@ done:
|
|
}
|
|
|
|
static void
|
|
-jump_to_entry_point(struct Process *proc, struct breakpoint *bp)
|
|
+jump_to_entry_point(struct process *proc, struct breakpoint *bp)
|
|
{
|
|
/* XXX The double cast should be removed when
|
|
* arch_addr_t becomes integral type. */
|
|
@@ -837,10 +792,10 @@ jump_to_entry_point(struct Process *proc, struct breakpoint *bp)
|
|
}
|
|
|
|
static void
|
|
-ppc_plt_bp_continue(struct breakpoint *bp, struct Process *proc)
|
|
+ppc_plt_bp_continue(struct breakpoint *bp, struct process *proc)
|
|
{
|
|
switch (bp->libsym->arch.type) {
|
|
- struct Process *leader;
|
|
+ struct process *leader;
|
|
void (*on_all_stopped)(struct process_stopping_handler *);
|
|
enum callback_status (*keep_stepping_p)
|
|
(struct process_stopping_handler *);
|
|
@@ -899,7 +854,7 @@ ppc_plt_bp_continue(struct breakpoint *bp, struct Process *proc)
|
|
* detect both cases and do any fix-ups necessary to mend this
|
|
* situation. */
|
|
static enum callback_status
|
|
-detach_task_cb(struct Process *task, void *data)
|
|
+detach_task_cb(struct process *task, void *data)
|
|
{
|
|
struct breakpoint *bp = data;
|
|
|
|
@@ -919,7 +874,7 @@ detach_task_cb(struct Process *task, void *data)
|
|
}
|
|
|
|
static void
|
|
-ppc_plt_bp_retract(struct breakpoint *bp, struct Process *proc)
|
|
+ppc_plt_bp_retract(struct breakpoint *bp, struct process *proc)
|
|
{
|
|
/* On PPC64, we rewrite .plt with PLT entry addresses. This
|
|
* needs to be undone. Unfortunately, the program may have
|
|
@@ -975,7 +930,7 @@ arch_library_symbol_clone(struct library_symbol *retp,
|
|
* don't need PROC here, we can store the data in BP if it is of
|
|
* interest to us. */
|
|
int
|
|
-arch_breakpoint_init(struct Process *proc, struct breakpoint *bp)
|
|
+arch_breakpoint_init(struct process *proc, struct breakpoint *bp)
|
|
{
|
|
/* Artificial and entry-point breakpoints are plain. */
|
|
if (bp->libsym == NULL || bp->libsym->plt_type != LS_TOPLT_EXEC)
|
|
@@ -1012,7 +967,7 @@ arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp)
|
|
}
|
|
|
|
int
|
|
-arch_process_init(struct Process *proc)
|
|
+arch_process_init(struct process *proc)
|
|
{
|
|
proc->arch.dl_plt_update_bp = NULL;
|
|
proc->arch.handler = NULL;
|
|
@@ -1020,19 +975,19 @@ arch_process_init(struct Process *proc)
|
|
}
|
|
|
|
void
|
|
-arch_process_destroy(struct Process *proc)
|
|
+arch_process_destroy(struct process *proc)
|
|
{
|
|
}
|
|
|
|
int
|
|
-arch_process_clone(struct Process *retp, struct Process *proc)
|
|
+arch_process_clone(struct process *retp, struct process *proc)
|
|
{
|
|
retp->arch = proc->arch;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
-arch_process_exec(struct Process *proc)
|
|
+arch_process_exec(struct process *proc)
|
|
{
|
|
return arch_process_init(proc);
|
|
}
|
|
diff --git a/sysdeps/linux-gnu/ppc/regs.c b/sysdeps/linux-gnu/ppc/regs.c
|
|
index 37f89a4..ed9b398 100644
|
|
--- a/sysdeps/linux-gnu/ppc/regs.c
|
|
+++ b/sysdeps/linux-gnu/ppc/regs.c
|
|
@@ -40,35 +40,32 @@
|
|
#endif
|
|
|
|
void *
|
|
-get_instruction_pointer(Process *proc) {
|
|
+get_instruction_pointer(struct process *proc)
|
|
+{
|
|
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long)*PT_NIP, 0);
|
|
}
|
|
|
|
void
|
|
-set_instruction_pointer(Process *proc, void *addr)
|
|
+set_instruction_pointer(struct process *proc, void *addr)
|
|
{
|
|
if (ptrace(PTRACE_POKEUSER, proc->pid, sizeof(long)*PT_NIP, addr) != 0)
|
|
error(0, errno, "set_instruction_pointer");
|
|
}
|
|
|
|
void *
|
|
-get_stack_pointer(Process *proc) {
|
|
+get_stack_pointer(struct process *proc)
|
|
+{
|
|
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long)*PT_R1, 0);
|
|
}
|
|
|
|
void *
|
|
-get_return_addr(Process *proc, void *stack_pointer) {
|
|
+get_return_addr(struct process *proc, void *stack_pointer)
|
|
+{
|
|
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long)*PT_LNK, 0);
|
|
}
|
|
|
|
void
|
|
-set_return_addr(Process *proc, void *addr) {
|
|
+set_return_addr(struct process *proc, void *addr)
|
|
+{
|
|
ptrace(PTRACE_POKEUSER, proc->pid, sizeof(long)*PT_LNK, addr);
|
|
}
|
|
-
|
|
-/* Grab the value of CTR registers. */
|
|
-void *
|
|
-get_count_register (Process *proc) {
|
|
- return (void *) ptrace (PTRACE_PEEKUSER, proc->pid,
|
|
- sizeof (long) * PT_CTR, 0);
|
|
-}
|
|
diff --git a/sysdeps/linux-gnu/ppc/trace.c b/sysdeps/linux-gnu/ppc/trace.c
|
|
index 4357a1e..ee9a6b5 100644
|
|
--- a/sysdeps/linux-gnu/ppc/trace.c
|
|
+++ b/sysdeps/linux-gnu/ppc/trace.c
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
* This file is part of ltrace.
|
|
- * Copyright (C) 2010,2012 Petr Machata, Red Hat Inc.
|
|
+ * Copyright (C) 2010,2012,2013 Petr Machata, Red Hat Inc.
|
|
* Copyright (C) 2011 Andreas Schwab
|
|
* Copyright (C) 2002,2004,2008,2009 Juan Cespedes
|
|
* Copyright (C) 2008 Luis Machado, IBM Corporation
|
|
@@ -49,7 +49,8 @@
|
|
#endif
|
|
|
|
void
|
|
-get_arch_dep(Process *proc) {
|
|
+get_arch_dep(struct process *proc)
|
|
+{
|
|
#ifdef __powerpc64__
|
|
proc->mask_32bit = (proc->e_machine == EM_PPC);
|
|
#endif
|
|
@@ -59,7 +60,8 @@ get_arch_dep(Process *proc) {
|
|
|
|
/* Returns 1 if syscall, 2 if sysret, 0 otherwise. */
|
|
int
|
|
-syscall_p(Process *proc, int status, int *sysnum) {
|
|
+syscall_p(struct process *proc, int status, int *sysnum)
|
|
+{
|
|
if (WIFSTOPPED(status)
|
|
&& WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
|
|
long pc = (long)get_instruction_pointer(proc);
|
|
@@ -84,18 +86,15 @@ syscall_p(Process *proc, int status, int *sysnum) {
|
|
|
|
/* The atomic skip code is mostly taken from GDB. */
|
|
|
|
-/* In plt.h. XXX make this official interface. */
|
|
-int read_target_4(struct Process *proc, arch_addr_t addr, uint32_t *lp);
|
|
-
|
|
-int
|
|
-arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
|
|
- int (*add_cb)(void *addr, void *data),
|
|
- void *add_cb_data)
|
|
+enum sw_singlestep_status
|
|
+arch_sw_singlestep(struct process *proc, struct breakpoint *sbp,
|
|
+ int (*add_cb)(arch_addr_t, struct sw_singlestep_data *),
|
|
+ struct sw_singlestep_data *add_cb_data)
|
|
{
|
|
arch_addr_t ip = get_instruction_pointer(proc);
|
|
struct breakpoint *other = address2bpstruct(proc->leader, ip);
|
|
|
|
- debug(1, "arch_atomic_singlestep pid=%d addr=%p %s(%p)",
|
|
+ debug(1, "arch_sw_singlestep pid=%d addr=%p %s(%p)",
|
|
proc->pid, ip, breakpoint_name(sbp), sbp->addr);
|
|
|
|
/* If the original instruction was lwarx/ldarx, we can't
|
|
@@ -107,15 +106,15 @@ arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
|
|
} u;
|
|
if (other != NULL) {
|
|
memcpy(u.buf, sbp->orig_value, BREAKPOINT_LENGTH);
|
|
- } else if (read_target_4(proc, ip, &u.insn) < 0) {
|
|
+ } else if (proc_read_32(proc, ip, &u.insn) < 0) {
|
|
fprintf(stderr, "couldn't read instruction at IP %p\n", ip);
|
|
/* Do the normal singlestep. */
|
|
- return 1;
|
|
+ return SWS_HW;
|
|
}
|
|
|
|
if ((u.insn & LWARX_MASK) != LWARX_INSTRUCTION
|
|
&& (u.insn & LWARX_MASK) != LDARX_INSTRUCTION)
|
|
- return 1;
|
|
+ return SWS_HW;
|
|
|
|
debug(1, "singlestep over atomic block at %p", ip);
|
|
|
|
@@ -125,7 +124,7 @@ arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
|
|
addr += 4;
|
|
unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0);
|
|
if (l == (unsigned long)-1 && errno)
|
|
- return -1;
|
|
+ return SWS_FAIL;
|
|
uint32_t insn;
|
|
#ifdef __powerpc64__
|
|
insn = l >> 32;
|
|
@@ -140,7 +139,7 @@ arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
|
|
debug(1, "pid=%d, branch in atomic block from %p to %p",
|
|
proc->pid, addr, branch_addr);
|
|
if (add_cb(branch_addr, add_cb_data) < 0)
|
|
- return -1;
|
|
+ return SWS_FAIL;
|
|
}
|
|
|
|
/* Assume that the atomic sequence ends with a
|
|
@@ -157,22 +156,22 @@ arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
|
|
if (insn_count > 16) {
|
|
fprintf(stderr, "[%d] couldn't find end of atomic block"
|
|
" at %p\n", proc->pid, ip);
|
|
- return -1;
|
|
+ return SWS_FAIL;
|
|
}
|
|
}
|
|
|
|
/* Put the breakpoint to the next instruction. */
|
|
addr += 4;
|
|
if (add_cb(addr, add_cb_data) < 0)
|
|
- return -1;
|
|
+ return SWS_FAIL;
|
|
|
|
debug(1, "PTRACE_CONT");
|
|
ptrace(PTRACE_CONT, proc->pid, 0, 0);
|
|
- return 0;
|
|
+ return SWS_OK;
|
|
}
|
|
|
|
size_t
|
|
-arch_type_sizeof(struct Process *proc, struct arg_type_info *info)
|
|
+arch_type_sizeof(struct process *proc, struct arg_type_info *info)
|
|
{
|
|
if (proc == NULL)
|
|
return (size_t)-2;
|
|
@@ -215,7 +214,7 @@ arch_type_sizeof(struct Process *proc, struct arg_type_info *info)
|
|
}
|
|
|
|
size_t
|
|
-arch_type_alignof(struct Process *proc, struct arg_type_info *info)
|
|
+arch_type_alignof(struct process *proc, struct arg_type_info *info)
|
|
{
|
|
if (proc == NULL)
|
|
return (size_t)-2;
|
|
diff --git a/sysdeps/linux-gnu/proc.c b/sysdeps/linux-gnu/proc.c
|
|
index 5adfb16..d69c985 100644
|
|
--- a/sysdeps/linux-gnu/proc.c
|
|
+++ b/sysdeps/linux-gnu/proc.c
|
|
@@ -177,44 +177,45 @@ process_status_cb(const char *line, const char *prefix, void *data)
|
|
} while (0)
|
|
|
|
switch (c) {
|
|
- case 'Z': RETURN(ps_zombie);
|
|
- case 't': RETURN(ps_tracing_stop);
|
|
+ case 'Z': RETURN(PS_ZOMBIE);
|
|
+ case 't': RETURN(PS_TRACING_STOP);
|
|
case 'T':
|
|
/* This can be either "T (stopped)" or, for older
|
|
* kernels, "T (tracing stop)". */
|
|
if (!strcmp(status, "T (stopped)\n"))
|
|
- RETURN(ps_stop);
|
|
+ RETURN(PS_STOP);
|
|
else if (!strcmp(status, "T (tracing stop)\n"))
|
|
- RETURN(ps_tracing_stop);
|
|
+ RETURN(PS_TRACING_STOP);
|
|
else {
|
|
fprintf(stderr, "Unknown process status: %s",
|
|
status);
|
|
- RETURN(ps_stop); /* Some sort of stop
|
|
+ RETURN(PS_STOP); /* Some sort of stop
|
|
* anyway. */
|
|
}
|
|
case 'D':
|
|
- case 'S': RETURN(ps_sleeping);
|
|
+ case 'S': RETURN(PS_SLEEPING);
|
|
}
|
|
|
|
- RETURN(ps_other);
|
|
+ RETURN(PS_OTHER);
|
|
#undef RETURN
|
|
}
|
|
|
|
enum process_status
|
|
process_status(pid_t pid)
|
|
{
|
|
- enum process_status ret = ps_invalid;
|
|
+ enum process_status ret = PS_INVALID;
|
|
FILE * file = open_status_file(pid);
|
|
if (file != NULL) {
|
|
each_line_starting(file, "State:\t", &process_status_cb, &ret);
|
|
fclose(file);
|
|
- if (ret == ps_invalid)
|
|
+ if (ret == PS_INVALID)
|
|
fprintf(stderr, "process_status %d: %s", pid,
|
|
strerror(errno));
|
|
- } else
|
|
+ } else {
|
|
/* If the file is not present, the process presumably
|
|
* exited already. */
|
|
- ret = ps_zombie;
|
|
+ ret = PS_ZOMBIE;
|
|
+ }
|
|
|
|
return ret;
|
|
}
|
|
@@ -279,7 +280,7 @@ process_tasks(pid_t pid, pid_t **ret_tasks, size_t *ret_n)
|
|
* ABI object, as theorized about somewhere on pmachata/revamp
|
|
* branch. */
|
|
static void *
|
|
-select_32_64(struct Process *proc, void *p32, void *p64)
|
|
+select_32_64(struct process *proc, void *p32, void *p64)
|
|
{
|
|
if (sizeof(long) == 4 || proc->mask_32bit)
|
|
return p32;
|
|
@@ -288,7 +289,7 @@ select_32_64(struct Process *proc, void *p32, void *p64)
|
|
}
|
|
|
|
static int
|
|
-fetch_dyn64(struct Process *proc, arch_addr_t *addr, Elf64_Dyn *ret)
|
|
+fetch_dyn64(struct process *proc, arch_addr_t *addr, Elf64_Dyn *ret)
|
|
{
|
|
if (umovebytes(proc, *addr, ret, sizeof(*ret)) != sizeof(*ret))
|
|
return -1;
|
|
@@ -297,7 +298,7 @@ fetch_dyn64(struct Process *proc, arch_addr_t *addr, Elf64_Dyn *ret)
|
|
}
|
|
|
|
static int
|
|
-fetch_dyn32(struct Process *proc, arch_addr_t *addr, Elf64_Dyn *ret)
|
|
+fetch_dyn32(struct process *proc, arch_addr_t *addr, Elf64_Dyn *ret)
|
|
{
|
|
Elf32_Dyn dyn;
|
|
if (umovebytes(proc, *addr, &dyn, sizeof(dyn)) != sizeof(dyn))
|
|
@@ -311,14 +312,14 @@ fetch_dyn32(struct Process *proc, arch_addr_t *addr, Elf64_Dyn *ret)
|
|
}
|
|
|
|
static int (*
|
|
-dyn_fetcher(struct Process *proc))(struct Process *,
|
|
+dyn_fetcher(struct process *proc))(struct process *,
|
|
arch_addr_t *, Elf64_Dyn *)
|
|
{
|
|
return select_32_64(proc, fetch_dyn32, fetch_dyn64);
|
|
}
|
|
|
|
int
|
|
-proc_find_dynamic_entry_addr(struct Process *proc, arch_addr_t src_addr,
|
|
+proc_find_dynamic_entry_addr(struct process *proc, arch_addr_t src_addr,
|
|
int d_tag, arch_addr_t *ret)
|
|
{
|
|
debug(DEBUG_FUNCTION, "find_dynamic_entry()");
|
|
@@ -364,7 +365,7 @@ struct lt_link_map_32 LT_LINK_MAP(32);
|
|
struct lt_link_map_64 LT_LINK_MAP(64);
|
|
|
|
static int
|
|
-fetch_lm64(struct Process *proc, arch_addr_t addr,
|
|
+fetch_lm64(struct process *proc, arch_addr_t addr,
|
|
struct lt_link_map_64 *ret)
|
|
{
|
|
if (umovebytes(proc, addr, ret, sizeof(*ret)) != sizeof(*ret))
|
|
@@ -373,7 +374,7 @@ fetch_lm64(struct Process *proc, arch_addr_t addr,
|
|
}
|
|
|
|
static int
|
|
-fetch_lm32(struct Process *proc, arch_addr_t addr,
|
|
+fetch_lm32(struct process *proc, arch_addr_t addr,
|
|
struct lt_link_map_64 *ret)
|
|
{
|
|
struct lt_link_map_32 lm;
|
|
@@ -390,7 +391,7 @@ fetch_lm32(struct Process *proc, arch_addr_t addr,
|
|
}
|
|
|
|
static int (*
|
|
-lm_fetcher(struct Process *proc))(struct Process *,
|
|
+lm_fetcher(struct process *proc))(struct process *,
|
|
arch_addr_t, struct lt_link_map_64 *)
|
|
{
|
|
return select_32_64(proc, fetch_lm32, fetch_lm64);
|
|
@@ -410,7 +411,7 @@ struct lt_r_debug_32 LT_R_DEBUG(32);
|
|
struct lt_r_debug_64 LT_R_DEBUG(64);
|
|
|
|
static int
|
|
-fetch_rd64(struct Process *proc, arch_addr_t addr,
|
|
+fetch_rd64(struct process *proc, arch_addr_t addr,
|
|
struct lt_r_debug_64 *ret)
|
|
{
|
|
if (umovebytes(proc, addr, ret, sizeof(*ret)) != sizeof(*ret))
|
|
@@ -419,7 +420,7 @@ fetch_rd64(struct Process *proc, arch_addr_t addr,
|
|
}
|
|
|
|
static int
|
|
-fetch_rd32(struct Process *proc, arch_addr_t addr,
|
|
+fetch_rd32(struct process *proc, arch_addr_t addr,
|
|
struct lt_r_debug_64 *ret)
|
|
{
|
|
struct lt_r_debug_32 rd;
|
|
@@ -436,7 +437,7 @@ fetch_rd32(struct Process *proc, arch_addr_t addr,
|
|
}
|
|
|
|
static int (*
|
|
-rdebug_fetcher(struct Process *proc))(struct Process *,
|
|
+rdebug_fetcher(struct process *proc))(struct process *,
|
|
arch_addr_t, struct lt_r_debug_64 *)
|
|
{
|
|
return select_32_64(proc, fetch_rd32, fetch_rd64);
|
|
@@ -463,13 +464,13 @@ fetch_auxv32_entry(int fd, Elf64_auxv_t *ret)
|
|
}
|
|
|
|
static int (*
|
|
-auxv_fetcher(struct Process *proc))(int, Elf64_auxv_t *)
|
|
+auxv_fetcher(struct process *proc))(int, Elf64_auxv_t *)
|
|
{
|
|
return select_32_64(proc, fetch_auxv32_entry, fetch_auxv64_entry);
|
|
}
|
|
|
|
static void
|
|
-crawl_linkmap(struct Process *proc, struct lt_r_debug_64 *dbg)
|
|
+crawl_linkmap(struct process *proc, struct lt_r_debug_64 *dbg)
|
|
{
|
|
debug (DEBUG_FUNCTION, "crawl_linkmap()");
|
|
|
|
@@ -551,7 +552,7 @@ crawl_linkmap(struct Process *proc, struct lt_r_debug_64 *dbg)
|
|
}
|
|
|
|
static int
|
|
-load_debug_struct(struct Process *proc, struct lt_r_debug_64 *ret)
|
|
+load_debug_struct(struct process *proc, struct lt_r_debug_64 *ret)
|
|
{
|
|
debug(DEBUG_FUNCTION, "load_debug_struct");
|
|
|
|
@@ -564,7 +565,7 @@ load_debug_struct(struct Process *proc, struct lt_r_debug_64 *ret)
|
|
}
|
|
|
|
static void
|
|
-rdebug_bp_on_hit(struct breakpoint *bp, struct Process *proc)
|
|
+rdebug_bp_on_hit(struct breakpoint *bp, struct process *proc)
|
|
{
|
|
debug(DEBUG_FUNCTION, "arch_check_dbg");
|
|
|
|
@@ -595,7 +596,7 @@ rdebug_bp_on_hit(struct breakpoint *bp, struct Process *proc)
|
|
|
|
#ifndef ARCH_HAVE_FIND_DL_DEBUG
|
|
int
|
|
-arch_find_dl_debug(struct Process *proc, arch_addr_t dyn_addr,
|
|
+arch_find_dl_debug(struct process *proc, arch_addr_t dyn_addr,
|
|
arch_addr_t *ret)
|
|
{
|
|
return proc_find_dynamic_entry_addr(proc, dyn_addr, DT_DEBUG, ret);
|
|
@@ -603,7 +604,7 @@ arch_find_dl_debug(struct Process *proc, arch_addr_t dyn_addr,
|
|
#endif
|
|
|
|
int
|
|
-linkmap_init(struct Process *proc, arch_addr_t dyn_addr)
|
|
+linkmap_init(struct process *proc, arch_addr_t dyn_addr)
|
|
{
|
|
debug(DEBUG_FUNCTION, "linkmap_init(%d, dyn_addr=%p)", proc->pid, dyn_addr);
|
|
|
|
@@ -648,13 +649,13 @@ task_kill (pid_t pid, int sig)
|
|
}
|
|
|
|
void
|
|
-process_removed(struct Process *proc)
|
|
+process_removed(struct process *proc)
|
|
{
|
|
delete_events_for(proc);
|
|
}
|
|
|
|
int
|
|
-process_get_entry(struct Process *proc,
|
|
+process_get_entry(struct process *proc,
|
|
arch_addr_t *entryp,
|
|
arch_addr_t *interp_biasp)
|
|
{
|
|
@@ -706,7 +707,7 @@ process_get_entry(struct Process *proc,
|
|
}
|
|
|
|
int
|
|
-os_process_init(struct Process *proc)
|
|
+os_process_init(struct process *proc)
|
|
{
|
|
proc->os.debug_addr = 0;
|
|
proc->os.debug_state = 0;
|
|
@@ -714,19 +715,19 @@ os_process_init(struct Process *proc)
|
|
}
|
|
|
|
void
|
|
-os_process_destroy(struct Process *proc)
|
|
+os_process_destroy(struct process *proc)
|
|
{
|
|
}
|
|
|
|
int
|
|
-os_process_clone(struct Process *retp, struct Process *proc)
|
|
+os_process_clone(struct process *retp, struct process *proc)
|
|
{
|
|
retp->os = proc->os;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
-os_process_exec(struct Process *proc)
|
|
+os_process_exec(struct process *proc)
|
|
{
|
|
return 0;
|
|
}
|
|
diff --git a/sysdeps/linux-gnu/s390/fetch.c b/sysdeps/linux-gnu/s390/fetch.c
|
|
index fa8f42d..0b68dbc 100644
|
|
--- a/sysdeps/linux-gnu/s390/fetch.c
|
|
+++ b/sysdeps/linux-gnu/s390/fetch.c
|
|
@@ -61,7 +61,7 @@ s390x(struct fetch_context *ctx)
|
|
}
|
|
|
|
static int
|
|
-fetch_register_banks(struct Process *proc, struct fetch_context *ctx)
|
|
+fetch_register_banks(struct process *proc, struct fetch_context *ctx)
|
|
{
|
|
ptrace_area parea;
|
|
parea.len = sizeof(ctx->regs);
|
|
@@ -76,7 +76,7 @@ fetch_register_banks(struct Process *proc, struct fetch_context *ctx)
|
|
}
|
|
|
|
static int
|
|
-fetch_context_init(struct Process *proc, struct fetch_context *context)
|
|
+fetch_context_init(struct process *proc, struct fetch_context *context)
|
|
{
|
|
context->greg = 2;
|
|
context->freg = 0;
|
|
@@ -84,7 +84,7 @@ fetch_context_init(struct Process *proc, struct fetch_context *context)
|
|
}
|
|
|
|
struct fetch_context *
|
|
-arch_fetch_arg_init(enum tof type, struct Process *proc,
|
|
+arch_fetch_arg_init(enum tof type, struct process *proc,
|
|
struct arg_type_info *ret_info)
|
|
{
|
|
struct fetch_context *context = malloc(sizeof(*context));
|
|
@@ -105,7 +105,7 @@ arch_fetch_arg_init(enum tof type, struct Process *proc,
|
|
}
|
|
|
|
struct fetch_context *
|
|
-arch_fetch_arg_clone(struct Process *proc,
|
|
+arch_fetch_arg_clone(struct process *proc,
|
|
struct fetch_context *context)
|
|
{
|
|
struct fetch_context *clone = malloc(sizeof(*context));
|
|
@@ -116,7 +116,7 @@ arch_fetch_arg_clone(struct Process *proc,
|
|
}
|
|
|
|
static int
|
|
-allocate_stack_slot(struct fetch_context *ctx, struct Process *proc,
|
|
+allocate_stack_slot(struct fetch_context *ctx, struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep,
|
|
size_t sz)
|
|
{
|
|
@@ -148,7 +148,7 @@ copy_gpr(struct fetch_context *ctx, struct value *valuep, int regno)
|
|
}
|
|
|
|
static int
|
|
-allocate_gpr(struct fetch_context *ctx, struct Process *proc,
|
|
+allocate_gpr(struct fetch_context *ctx, struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep,
|
|
size_t sz)
|
|
{
|
|
@@ -160,7 +160,7 @@ allocate_gpr(struct fetch_context *ctx, struct Process *proc,
|
|
}
|
|
|
|
static int
|
|
-allocate_gpr_pair(struct fetch_context *ctx, struct Process *proc,
|
|
+allocate_gpr_pair(struct fetch_context *ctx, struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep,
|
|
size_t sz)
|
|
{
|
|
@@ -191,7 +191,7 @@ allocate_gpr_pair(struct fetch_context *ctx, struct Process *proc,
|
|
}
|
|
|
|
static int
|
|
-allocate_fpr(struct fetch_context *ctx, struct Process *proc,
|
|
+allocate_fpr(struct fetch_context *ctx, struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep,
|
|
size_t sz)
|
|
{
|
|
@@ -212,7 +212,7 @@ allocate_fpr(struct fetch_context *ctx, struct Process *proc,
|
|
|
|
int
|
|
arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
|
|
- struct Process *proc,
|
|
+ struct process *proc,
|
|
struct arg_type_info *info, struct value *valuep)
|
|
{
|
|
size_t sz = type_sizeof(proc, info);
|
|
@@ -267,7 +267,7 @@ arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
|
|
|
|
int
|
|
arch_fetch_retval(struct fetch_context *ctx, enum tof type,
|
|
- struct Process *proc, struct arg_type_info *info,
|
|
+ struct process *proc, struct arg_type_info *info,
|
|
struct value *valuep)
|
|
{
|
|
if (info->type == ARGTYPE_STRUCT) {
|
|
diff --git a/sysdeps/linux-gnu/s390/plt.c b/sysdeps/linux-gnu/s390/plt.c
|
|
index 5f612e5..8893d45 100644
|
|
--- a/sysdeps/linux-gnu/s390/plt.c
|
|
+++ b/sysdeps/linux-gnu/s390/plt.c
|
|
@@ -29,6 +29,7 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
|
|
}
|
|
|
|
void *
|
|
-sym2addr(Process *proc, struct library_symbol *sym) {
|
|
+sym2addr(struct process *proc, struct library_symbol *sym)
|
|
+{
|
|
return sym->enter_addr;
|
|
}
|
|
diff --git a/sysdeps/linux-gnu/s390/regs.c b/sysdeps/linux-gnu/s390/regs.c
|
|
index 0592ccd..44e8f67 100644
|
|
--- a/sysdeps/linux-gnu/s390/regs.c
|
|
+++ b/sysdeps/linux-gnu/s390/regs.c
|
|
@@ -46,7 +46,8 @@
|
|
#endif
|
|
|
|
void *
|
|
-get_instruction_pointer(Process *proc) {
|
|
+get_instruction_pointer(struct process *proc)
|
|
+{
|
|
long ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_PSWADDR, 0) & PSW_MASK;
|
|
#ifdef __s390x__
|
|
if (proc->mask_32bit)
|
|
@@ -56,7 +57,8 @@ get_instruction_pointer(Process *proc) {
|
|
}
|
|
|
|
void
|
|
-set_instruction_pointer(Process *proc, void *addr) {
|
|
+set_instruction_pointer(struct process *proc, void *addr)
|
|
+{
|
|
#ifdef __s390x__
|
|
if (proc->mask_32bit)
|
|
addr = (void *)((long)addr & PSW_MASK31);
|
|
@@ -65,7 +67,8 @@ set_instruction_pointer(Process *proc, void *addr) {
|
|
}
|
|
|
|
void *
|
|
-get_stack_pointer(Process *proc) {
|
|
+get_stack_pointer(struct process *proc)
|
|
+{
|
|
long ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR15, 0) & PSW_MASK;
|
|
#ifdef __s390x__
|
|
if (proc->mask_32bit)
|
|
@@ -75,7 +78,8 @@ get_stack_pointer(Process *proc) {
|
|
}
|
|
|
|
void *
|
|
-get_return_addr(Process *proc, void *stack_pointer) {
|
|
+get_return_addr(struct process *proc, void *stack_pointer)
|
|
+{
|
|
long ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR14, 0) & PSW_MASK;
|
|
#ifdef __s390x__
|
|
if (proc->mask_32bit)
|
|
@@ -85,7 +89,8 @@ get_return_addr(Process *proc, void *stack_pointer) {
|
|
}
|
|
|
|
void
|
|
-set_return_addr(Process *proc, void *addr) {
|
|
+set_return_addr(struct process *proc, void *addr)
|
|
+{
|
|
#ifdef __s390x__
|
|
if (proc->mask_32bit)
|
|
addr = (void *)((long)addr & PSW_MASK31);
|
|
diff --git a/sysdeps/linux-gnu/s390/trace.c b/sysdeps/linux-gnu/s390/trace.c
|
|
index b9e05ff..78b04c3 100644
|
|
--- a/sysdeps/linux-gnu/s390/trace.c
|
|
+++ b/sysdeps/linux-gnu/s390/trace.c
|
|
@@ -43,7 +43,8 @@
|
|
#endif
|
|
|
|
void
|
|
-get_arch_dep(Process *proc) {
|
|
+get_arch_dep(struct process *proc)
|
|
+{
|
|
#ifdef __s390x__
|
|
unsigned long psw;
|
|
|
|
@@ -64,7 +65,8 @@ get_arch_dep(Process *proc) {
|
|
/* Returns 1 if syscall, 2 if sysret, 0 otherwise.
|
|
*/
|
|
int
|
|
-syscall_p(Process *proc, int status, int *sysnum) {
|
|
+syscall_p(struct process *proc, int status, int *sysnum)
|
|
+{
|
|
long pc, opcode, offset_reg, scno, tmp;
|
|
void *svc_addr;
|
|
int gpr_offset[16] = { PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
|
|
@@ -175,7 +177,7 @@ syscall_p(Process *proc, int status, int *sysnum) {
|
|
}
|
|
|
|
size_t
|
|
-arch_type_sizeof(struct Process *proc, struct arg_type_info *info)
|
|
+arch_type_sizeof(struct process *proc, struct arg_type_info *info)
|
|
{
|
|
if (proc == NULL)
|
|
return (size_t)-2;
|
|
@@ -217,7 +219,7 @@ arch_type_sizeof(struct Process *proc, struct arg_type_info *info)
|
|
}
|
|
|
|
size_t
|
|
-arch_type_alignof(struct Process *proc, struct arg_type_info *info)
|
|
+arch_type_alignof(struct process *proc, struct arg_type_info *info)
|
|
{
|
|
if (proc == NULL)
|
|
return (size_t)-2;
|
|
diff --git a/sysdeps/linux-gnu/sparc/plt.c b/sysdeps/linux-gnu/sparc/plt.c
|
|
index 40bbabc..3d2e589 100644
|
|
--- a/sysdeps/linux-gnu/sparc/plt.c
|
|
+++ b/sysdeps/linux-gnu/sparc/plt.c
|
|
@@ -28,6 +28,7 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
|
|
}
|
|
|
|
void *
|
|
-sym2addr(Process *proc, struct library_symbol *sym) {
|
|
+sym2addr(struct process *proc, struct library_symbol *sym)
|
|
+{
|
|
return sym->enter_addr;
|
|
}
|
|
diff --git a/sysdeps/linux-gnu/sparc/regs.c b/sysdeps/linux-gnu/sparc/regs.c
|
|
index 5e5ad20..8431c9b 100644
|
|
--- a/sysdeps/linux-gnu/sparc/regs.c
|
|
+++ b/sysdeps/linux-gnu/sparc/regs.c
|
|
@@ -27,7 +27,8 @@
|
|
#include "common.h"
|
|
|
|
void *
|
|
-get_instruction_pointer(Process *proc) {
|
|
+get_instruction_pointer(struct process *proc)
|
|
+{
|
|
proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
|
|
if (a->valid)
|
|
return (void *)a->regs.pc;
|
|
@@ -35,14 +36,16 @@ get_instruction_pointer(Process *proc) {
|
|
}
|
|
|
|
void
|
|
-set_instruction_pointer(Process *proc, void *addr) {
|
|
+set_instruction_pointer(struct process *proc, void *addr)
|
|
+{
|
|
proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
|
|
if (a->valid)
|
|
a->regs.pc = (long)addr;
|
|
}
|
|
|
|
void *
|
|
-get_stack_pointer(Process *proc) {
|
|
+get_stack_pointer(struct process *proc)
|
|
+{
|
|
proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
|
|
if (a->valid)
|
|
return (void *)a->regs.u_regs[UREG_I5];
|
|
@@ -50,7 +53,8 @@ get_stack_pointer(Process *proc) {
|
|
}
|
|
|
|
void *
|
|
-get_return_addr(Process *proc, void *stack_pointer) {
|
|
+get_return_addr(struct process *proc, void *stack_pointer)
|
|
+{
|
|
proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
|
|
unsigned int t;
|
|
if (!a->valid)
|
|
@@ -63,7 +67,8 @@ get_return_addr(Process *proc, void *stack_pointer) {
|
|
}
|
|
|
|
void
|
|
-set_return_addr(Process *proc, void *addr) {
|
|
+set_return_addr(struct process *proc, void *addr)
|
|
+{
|
|
proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
|
|
if (!a->valid)
|
|
return;
|
|
diff --git a/sysdeps/linux-gnu/sparc/trace.c b/sysdeps/linux-gnu/sparc/trace.c
|
|
index e1725ff..078d406 100644
|
|
--- a/sysdeps/linux-gnu/sparc/trace.c
|
|
+++ b/sysdeps/linux-gnu/sparc/trace.c
|
|
@@ -31,7 +31,8 @@
|
|
#include "common.h"
|
|
|
|
void
|
|
-get_arch_dep(Process *proc) {
|
|
+get_arch_dep(struct process *proc)
|
|
+{
|
|
proc_archdep *a;
|
|
if (!proc->arch_ptr)
|
|
proc->arch_ptr = (void *)malloc(sizeof(proc_archdep));
|
|
@@ -43,7 +44,8 @@ get_arch_dep(Process *proc) {
|
|
* Returns -1 otherwise
|
|
*/
|
|
int
|
|
-syscall_p(Process *proc, int status, int *sysnum) {
|
|
+syscall_p(struct process *proc, int status, int *sysnum)
|
|
+{
|
|
if (WIFSTOPPED(status)
|
|
&& WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
|
|
void *ip = get_instruction_pointer(proc);
|
|
@@ -66,7 +68,8 @@ syscall_p(Process *proc, int status, int *sysnum) {
|
|
}
|
|
|
|
long
|
|
-gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info)
|
|
+gimme_arg(enum tof type, struct process *proc, int arg_num,
|
|
+ struct arg_type_info *info)
|
|
{
|
|
proc_archdep *a = (proc_archdep *) proc->arch_ptr;
|
|
if (!a->valid) {
|
|
diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
|
|
index e13b761..e57a5ed 100644
|
|
--- a/sysdeps/linux-gnu/trace.c
|
|
+++ b/sysdeps/linux-gnu/trace.c
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
* This file is part of ltrace.
|
|
- * Copyright (C) 2007,2011,2012 Petr Machata, Red Hat Inc.
|
|
+ * Copyright (C) 2007,2011,2012,2013 Petr Machata, Red Hat Inc.
|
|
* Copyright (C) 2010 Joe Damato
|
|
* Copyright (C) 1998,2002,2003,2004,2008,2009 Juan Cespedes
|
|
* Copyright (C) 2006 Ian Wienand
|
|
@@ -111,7 +111,7 @@ trace_pid(pid_t pid)
|
|
}
|
|
|
|
void
|
|
-trace_set_options(struct Process *proc)
|
|
+trace_set_options(struct process *proc)
|
|
{
|
|
if (proc->tracesysgood & 0x80)
|
|
return;
|
|
@@ -148,8 +148,8 @@ static enum ecb_status
|
|
event_for_pid(Event *event, void *data)
|
|
{
|
|
if (event->proc != NULL && event->proc->pid == (pid_t)(uintptr_t)data)
|
|
- return ecb_yield;
|
|
- return ecb_cont;
|
|
+ return ECB_YIELD;
|
|
+ return ECB_CONT;
|
|
}
|
|
|
|
static int
|
|
@@ -206,7 +206,7 @@ add_task_info(struct pid_set *pids, pid_t pid)
|
|
}
|
|
|
|
static enum callback_status
|
|
-task_stopped(struct Process *task, void *data)
|
|
+task_stopped(struct process *task, void *data)
|
|
{
|
|
enum process_status st = process_status(task->pid);
|
|
if (data != NULL)
|
|
@@ -217,13 +217,13 @@ task_stopped(struct Process *task, void *data)
|
|
* the meantime. This can happen when the whole thread group
|
|
* is terminating. */
|
|
switch (st) {
|
|
- case ps_invalid:
|
|
- case ps_tracing_stop:
|
|
- case ps_zombie:
|
|
+ case PS_INVALID:
|
|
+ case PS_TRACING_STOP:
|
|
+ case PS_ZOMBIE:
|
|
return CBS_CONT;
|
|
- case ps_sleeping:
|
|
- case ps_stop:
|
|
- case ps_other:
|
|
+ case PS_SLEEPING:
|
|
+ case PS_STOP:
|
|
+ case PS_OTHER:
|
|
return CBS_STOP;
|
|
}
|
|
|
|
@@ -232,7 +232,7 @@ task_stopped(struct Process *task, void *data)
|
|
|
|
/* Task is blocked if it's stopped, or if it's a vfork parent. */
|
|
static enum callback_status
|
|
-task_blocked(struct Process *task, void *data)
|
|
+task_blocked(struct process *task, void *data)
|
|
{
|
|
struct pid_set *pids = data;
|
|
struct pid_task *task_info = get_task_info(pids, task->pid);
|
|
@@ -246,7 +246,7 @@ task_blocked(struct Process *task, void *data)
|
|
static Event *process_vfork_on_event(struct event_handler *super, Event *event);
|
|
|
|
static enum callback_status
|
|
-task_vforked(struct Process *task, void *data)
|
|
+task_vforked(struct process *task, void *data)
|
|
{
|
|
if (task->event_handler != NULL
|
|
&& task->event_handler->on_event == &process_vfork_on_event)
|
|
@@ -255,15 +255,15 @@ task_vforked(struct Process *task, void *data)
|
|
}
|
|
|
|
static int
|
|
-is_vfork_parent(struct Process *task)
|
|
+is_vfork_parent(struct process *task)
|
|
{
|
|
return each_task(task->leader, NULL, &task_vforked, NULL) != NULL;
|
|
}
|
|
|
|
static enum callback_status
|
|
-send_sigstop(struct Process *task, void *data)
|
|
+send_sigstop(struct process *task, void *data)
|
|
{
|
|
- struct Process *leader = task->leader;
|
|
+ struct process *leader = task->leader;
|
|
struct pid_set *pids = data;
|
|
|
|
/* Look for pre-existing task record, or add new. */
|
|
@@ -299,8 +299,8 @@ send_sigstop(struct Process *task, void *data)
|
|
* vforked process. We set up event handler specially to hint
|
|
* us. In that case parent is in D state, which we use to
|
|
* weed out unnecessary looping. */
|
|
- if (st == ps_sleeping
|
|
- && is_vfork_parent (task)) {
|
|
+ if (st == PS_SLEEPING
|
|
+ && is_vfork_parent(task)) {
|
|
task_info->vforked = 1;
|
|
return CBS_CONT;
|
|
}
|
|
@@ -321,7 +321,7 @@ send_sigstop(struct Process *task, void *data)
|
|
breakpoint where IP points and let the process continue. After
|
|
this the breakpoint can be retracted and the process detached. */
|
|
static void
|
|
-ugly_workaround(struct Process *proc)
|
|
+ugly_workaround(struct process *proc)
|
|
{
|
|
void *ip = get_instruction_pointer(proc);
|
|
struct breakpoint *sbp = dict_find_entry(proc->leader->breakpoints, ip);
|
|
@@ -334,7 +334,7 @@ ugly_workaround(struct Process *proc)
|
|
|
|
static void
|
|
process_stopping_done(struct process_stopping_handler *self,
|
|
- struct Process *leader)
|
|
+ struct process *leader)
|
|
{
|
|
debug(DEBUG_PROCESS, "process stopping done %d",
|
|
self->task_enabling_breakpoint->pid);
|
|
@@ -351,7 +351,7 @@ process_stopping_done(struct process_stopping_handler *self,
|
|
|
|
if (self->exiting) {
|
|
ugly_workaround:
|
|
- self->state = psh_ugly_workaround;
|
|
+ self->state = PSH_UGLY_WORKAROUND;
|
|
ugly_workaround(self->task_enabling_breakpoint);
|
|
} else {
|
|
switch ((self->ugly_workaround_p)(self)) {
|
|
@@ -377,11 +377,11 @@ undo_breakpoint(Event *event, void *data)
|
|
&& event->proc->leader == data
|
|
&& event->type == EVENT_BREAKPOINT)
|
|
set_instruction_pointer(event->proc, event->e_un.brk_addr);
|
|
- return ecb_cont;
|
|
+ return ECB_CONT;
|
|
}
|
|
|
|
static enum callback_status
|
|
-untrace_task(struct Process *task, void *data)
|
|
+untrace_task(struct process *task, void *data)
|
|
{
|
|
if (task != data)
|
|
untrace_pid(task->pid);
|
|
@@ -389,7 +389,7 @@ untrace_task(struct Process *task, void *data)
|
|
}
|
|
|
|
static enum callback_status
|
|
-remove_task(struct Process *task, void *data)
|
|
+remove_task(struct process *task, void *data)
|
|
{
|
|
/* Don't untrace leader just yet. */
|
|
if (task != data)
|
|
@@ -398,14 +398,14 @@ remove_task(struct Process *task, void *data)
|
|
}
|
|
|
|
static enum callback_status
|
|
-retract_breakpoint_cb(struct Process *proc, struct breakpoint *bp, void *data)
|
|
+retract_breakpoint_cb(struct process *proc, struct breakpoint *bp, void *data)
|
|
{
|
|
breakpoint_on_retract(bp, proc);
|
|
return CBS_CONT;
|
|
}
|
|
|
|
static void
|
|
-detach_process(struct Process *leader)
|
|
+detach_process(struct process *leader)
|
|
{
|
|
each_qd_event(&undo_breakpoint, leader);
|
|
disable_all_breakpoints(leader);
|
|
@@ -414,7 +414,7 @@ detach_process(struct Process *leader)
|
|
/* Now untrace the process, if it was attached to by -p. */
|
|
struct opt_p_t *it;
|
|
for (it = opt_p; it != NULL; it = it->next) {
|
|
- struct Process *proc = pid2proc(it->pid);
|
|
+ struct process *proc = pid2proc(it->pid);
|
|
if (proc == NULL)
|
|
continue;
|
|
if (proc->leader == leader) {
|
|
@@ -540,19 +540,13 @@ all_stops_accountable(struct pid_set *pids)
|
|
return 1;
|
|
}
|
|
|
|
-/* The protocol is: 0 for success, negative for failure, positive if
|
|
- * default singlestep is to be used. */
|
|
-int arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
|
|
- int (*add_cb)(void *addr, void *data),
|
|
- void *add_cb_data);
|
|
-
|
|
-#ifndef ARCH_HAVE_ATOMIC_SINGLESTEP
|
|
-int
|
|
-arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
|
|
- int (*add_cb)(void *addr, void *data),
|
|
- void *add_cb_data)
|
|
+#ifndef ARCH_HAVE_SW_SINGLESTEP
|
|
+enum sw_singlestep_status
|
|
+arch_sw_singlestep(struct process *proc, struct breakpoint *bp,
|
|
+ int (*add_cb)(arch_addr_t, struct sw_singlestep_data *),
|
|
+ struct sw_singlestep_data *data)
|
|
{
|
|
- return 1;
|
|
+ return SWS_HW;
|
|
}
|
|
#endif
|
|
|
|
@@ -560,43 +554,46 @@ static Event *process_stopping_on_event(struct event_handler *super,
|
|
Event *event);
|
|
|
|
static void
|
|
-remove_atomic_breakpoints(struct Process *proc)
|
|
+remove_sw_breakpoints(struct process *proc)
|
|
{
|
|
struct process_stopping_handler *self
|
|
= (void *)proc->leader->event_handler;
|
|
assert(self != NULL);
|
|
assert(self->super.on_event == process_stopping_on_event);
|
|
|
|
- int ct = sizeof(self->atomic_skip_bp_addrs)
|
|
- / sizeof(*self->atomic_skip_bp_addrs);
|
|
+ int ct = sizeof(self->sws_bp_addrs) / sizeof(*self->sws_bp_addrs);
|
|
int i;
|
|
for (i = 0; i < ct; ++i)
|
|
- if (self->atomic_skip_bp_addrs[i] != 0) {
|
|
- delete_breakpoint(proc, self->atomic_skip_bp_addrs[i]);
|
|
- self->atomic_skip_bp_addrs[i] = 0;
|
|
+ if (self->sws_bp_addrs[i] != 0) {
|
|
+ delete_breakpoint(proc, self->sws_bp_addrs[i]);
|
|
+ self->sws_bp_addrs[i] = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
-atomic_singlestep_bp_on_hit(struct breakpoint *bp, struct Process *proc)
|
|
+sw_singlestep_bp_on_hit(struct breakpoint *bp, struct process *proc)
|
|
{
|
|
- remove_atomic_breakpoints(proc);
|
|
+ remove_sw_breakpoints(proc);
|
|
}
|
|
|
|
+struct sw_singlestep_data {
|
|
+ struct process_stopping_handler *self;
|
|
+};
|
|
+
|
|
static int
|
|
-atomic_singlestep_add_bp(void *addr, void *data)
|
|
+sw_singlestep_add_bp(arch_addr_t addr, struct sw_singlestep_data *data)
|
|
{
|
|
- struct process_stopping_handler *self = data;
|
|
- struct Process *proc = self->task_enabling_breakpoint;
|
|
+ struct process_stopping_handler *self = data->self;
|
|
+ struct process *proc = self->task_enabling_breakpoint;
|
|
|
|
- int ct = sizeof(self->atomic_skip_bp_addrs)
|
|
- / sizeof(*self->atomic_skip_bp_addrs);
|
|
+ int ct = sizeof(self->sws_bp_addrs)
|
|
+ / sizeof(*self->sws_bp_addrs);
|
|
int i;
|
|
for (i = 0; i < ct; ++i)
|
|
- if (self->atomic_skip_bp_addrs[i] == 0) {
|
|
- self->atomic_skip_bp_addrs[i] = addr;
|
|
+ if (self->sws_bp_addrs[i] == 0) {
|
|
+ self->sws_bp_addrs[i] = addr;
|
|
static struct bp_callbacks cbs = {
|
|
- .on_hit = atomic_singlestep_bp_on_hit,
|
|
+ .on_hit = sw_singlestep_bp_on_hit,
|
|
};
|
|
struct breakpoint *bp
|
|
= insert_breakpoint(proc, addr, NULL);
|
|
@@ -604,30 +601,35 @@ atomic_singlestep_add_bp(void *addr, void *data)
|
|
return 0;
|
|
}
|
|
|
|
- assert(!"Too many atomic singlestep breakpoints!");
|
|
+ assert(!"Too many sw singlestep breakpoints!");
|
|
abort();
|
|
}
|
|
|
|
static int
|
|
singlestep(struct process_stopping_handler *self)
|
|
{
|
|
- struct Process *proc = self->task_enabling_breakpoint;
|
|
-
|
|
- int status = arch_atomic_singlestep(self->task_enabling_breakpoint,
|
|
- self->breakpoint_being_enabled,
|
|
- &atomic_singlestep_add_bp, self);
|
|
+ struct process *proc = self->task_enabling_breakpoint;
|
|
+
|
|
+ struct sw_singlestep_data data = { self };
|
|
+ switch (arch_sw_singlestep(self->task_enabling_breakpoint,
|
|
+ self->breakpoint_being_enabled,
|
|
+ &sw_singlestep_add_bp, &data)) {
|
|
+ case SWS_HW:
|
|
+ /* Otherwise do the default action: singlestep. */
|
|
+ debug(1, "PTRACE_SINGLESTEP");
|
|
+ if (ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0)) {
|
|
+ perror("PTRACE_SINGLESTEP");
|
|
+ return -1;
|
|
+ }
|
|
+ return 0;
|
|
|
|
- /* Propagate failure and success. */
|
|
- if (status <= 0)
|
|
- return status;
|
|
+ case SWS_OK:
|
|
+ return 0;
|
|
|
|
- /* Otherwise do the default action: singlestep. */
|
|
- debug(1, "PTRACE_SINGLESTEP");
|
|
- if (ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0)) {
|
|
- perror("PTRACE_SINGLESTEP");
|
|
+ case SWS_FAIL:
|
|
return -1;
|
|
}
|
|
- return 0;
|
|
+ abort();
|
|
}
|
|
|
|
static void
|
|
@@ -639,16 +641,16 @@ post_singlestep(struct process_stopping_handler *self,
|
|
if (*eventp != NULL && (*eventp)->type == EVENT_BREAKPOINT)
|
|
*eventp = NULL; // handled
|
|
|
|
- struct Process *proc = self->task_enabling_breakpoint;
|
|
+ struct process *proc = self->task_enabling_breakpoint;
|
|
|
|
- remove_atomic_breakpoints(proc);
|
|
+ remove_sw_breakpoints(proc);
|
|
self->breakpoint_being_enabled = NULL;
|
|
}
|
|
|
|
static void
|
|
singlestep_error(struct process_stopping_handler *self)
|
|
{
|
|
- struct Process *teb = self->task_enabling_breakpoint;
|
|
+ struct process *teb = self->task_enabling_breakpoint;
|
|
struct breakpoint *sbp = self->breakpoint_being_enabled;
|
|
fprintf(stderr, "%d couldn't continue when handling %s (%p) at %p\n",
|
|
teb->pid, breakpoint_name(sbp), sbp->addr,
|
|
@@ -659,7 +661,7 @@ singlestep_error(struct process_stopping_handler *self)
|
|
static void
|
|
pt_continue(struct process_stopping_handler *self)
|
|
{
|
|
- struct Process *teb = self->task_enabling_breakpoint;
|
|
+ struct process *teb = self->task_enabling_breakpoint;
|
|
debug(1, "PTRACE_CONT");
|
|
ptrace(PTRACE_CONT, teb->pid, 0, 0);
|
|
}
|
|
@@ -675,12 +677,12 @@ static void
|
|
disable_and(struct process_stopping_handler *self,
|
|
void (*do_this)(struct process_stopping_handler *self))
|
|
{
|
|
- struct Process *teb = self->task_enabling_breakpoint;
|
|
+ struct process *teb = self->task_enabling_breakpoint;
|
|
debug(DEBUG_PROCESS, "all stopped, now singlestep/cont %d", teb->pid);
|
|
if (self->breakpoint_being_enabled->enabled)
|
|
disable_breakpoint(teb, self->breakpoint_being_enabled);
|
|
(do_this)(self);
|
|
- self->state = psh_singlestep;
|
|
+ self->state = PSH_SINGLESTEP;
|
|
}
|
|
|
|
void
|
|
@@ -705,9 +707,9 @@ static Event *
|
|
process_stopping_on_event(struct event_handler *super, Event *event)
|
|
{
|
|
struct process_stopping_handler *self = (void *)super;
|
|
- struct Process *task = event->proc;
|
|
- struct Process *leader = task->leader;
|
|
- struct Process *teb = self->task_enabling_breakpoint;
|
|
+ struct process *task = event->proc;
|
|
+ struct process *leader = task->leader;
|
|
+ struct process *teb = self->task_enabling_breakpoint;
|
|
|
|
debug(DEBUG_PROCESS,
|
|
"process_stopping_on_event: pid %d; event type %d; state %d",
|
|
@@ -737,7 +739,7 @@ process_stopping_on_event(struct event_handler *super, Event *event)
|
|
}
|
|
|
|
switch (state) {
|
|
- case psh_stopping:
|
|
+ case PSH_STOPPING:
|
|
/* If everyone is stopped, singlestep. */
|
|
if (each_task(leader, NULL, &task_blocked,
|
|
&self->pids) == NULL) {
|
|
@@ -746,7 +748,7 @@ process_stopping_on_event(struct event_handler *super, Event *event)
|
|
}
|
|
break;
|
|
|
|
- case psh_singlestep:
|
|
+ case PSH_SINGLESTEP:
|
|
/* In singlestep state, breakpoint signifies that we
|
|
* have now stepped, and can re-enable the breakpoint. */
|
|
if (event != NULL && task == teb) {
|
|
@@ -801,13 +803,14 @@ process_stopping_on_event(struct event_handler *super, Event *event)
|
|
break;
|
|
|
|
psh_sinking:
|
|
- state = self->state = psh_sinking;
|
|
- case psh_sinking:
|
|
+ state = self->state = PSH_SINKING;
|
|
+ /* Fall through. */
|
|
+ case PSH_SINKING:
|
|
if (await_sigstop_delivery(&self->pids, task_info, event))
|
|
process_stopping_done(self, leader);
|
|
break;
|
|
|
|
- case psh_ugly_workaround:
|
|
+ case PSH_UGLY_WORKAROUND:
|
|
if (event == NULL)
|
|
break;
|
|
if (event->type == EVENT_BREAKPOINT) {
|
|
@@ -845,7 +848,7 @@ no(struct process_stopping_handler *self)
|
|
}
|
|
|
|
int
|
|
-process_install_stopping_handler(struct Process *proc, struct breakpoint *sbp,
|
|
+process_install_stopping_handler(struct process *proc, struct breakpoint *sbp,
|
|
void (*as)(struct process_stopping_handler *),
|
|
enum callback_status (*ks)
|
|
(struct process_stopping_handler *),
|
|
@@ -894,7 +897,7 @@ process_install_stopping_handler(struct Process *proc, struct breakpoint *sbp,
|
|
}
|
|
|
|
void
|
|
-continue_after_breakpoint(Process *proc, struct breakpoint *sbp)
|
|
+continue_after_breakpoint(struct process *proc, struct breakpoint *sbp)
|
|
{
|
|
debug(DEBUG_PROCESS,
|
|
"continue_after_breakpoint: pid=%d, addr=%p",
|
|
@@ -937,8 +940,8 @@ static Event *
|
|
ltrace_exiting_on_event(struct event_handler *super, Event *event)
|
|
{
|
|
struct ltrace_exiting_handler *self = (void *)super;
|
|
- struct Process *task = event->proc;
|
|
- struct Process *leader = task->leader;
|
|
+ struct process *task = event->proc;
|
|
+ struct process *leader = task->leader;
|
|
|
|
debug(DEBUG_PROCESS,
|
|
"ltrace_exiting_on_event: pid %d; event type %d",
|
|
@@ -970,7 +973,7 @@ ltrace_exiting_destroy(struct event_handler *super)
|
|
}
|
|
|
|
static int
|
|
-ltrace_exiting_install_handler(struct Process *proc)
|
|
+ltrace_exiting_install_handler(struct process *proc)
|
|
{
|
|
/* Only install to leader. */
|
|
if (proc->leader != proc)
|
|
@@ -1087,7 +1090,7 @@ process_vfork_on_event(struct event_handler *super, Event *event)
|
|
}
|
|
|
|
void
|
|
-continue_after_vfork(struct Process *proc)
|
|
+continue_after_vfork(struct process *proc)
|
|
{
|
|
debug(DEBUG_PROCESS, "continue_after_vfork: pid=%d", proc->pid);
|
|
struct process_vfork_handler *handler = calloc(sizeof(*handler), 1);
|
|
@@ -1116,7 +1119,7 @@ continue_after_vfork(struct Process *proc)
|
|
}
|
|
|
|
static int
|
|
-is_mid_stopping(Process *proc)
|
|
+is_mid_stopping(struct process *proc)
|
|
{
|
|
return proc != NULL
|
|
&& proc->event_handler != NULL
|
|
@@ -1124,7 +1127,7 @@ is_mid_stopping(Process *proc)
|
|
}
|
|
|
|
void
|
|
-continue_after_syscall(struct Process *proc, int sysnum, int ret_p)
|
|
+continue_after_syscall(struct process *proc, int sysnum, int ret_p)
|
|
{
|
|
/* Don't continue if we are mid-stopping. */
|
|
if (ret_p && (is_mid_stopping(proc) || is_mid_stopping(proc->leader))) {
|
|
@@ -1136,6 +1139,23 @@ continue_after_syscall(struct Process *proc, int sysnum, int ret_p)
|
|
continue_process(proc->pid);
|
|
}
|
|
|
|
+void
|
|
+continue_after_exec(struct process *proc)
|
|
+{
|
|
+ continue_process(proc->pid);
|
|
+
|
|
+ /* After the exec, we expect to hit the first executable
|
|
+ * instruction.
|
|
+ *
|
|
+ * XXX TODO It would be nice to have this removed, but then we
|
|
+ * need to do that also for initial call to wait_for_proc in
|
|
+ * execute_program. In that case we could generate a
|
|
+ * EVENT_FIRST event or something, or maybe this could somehow
|
|
+ * be rolled into EVENT_NEW. */
|
|
+ wait_for_proc(proc->pid);
|
|
+ continue_process(proc->pid);
|
|
+}
|
|
+
|
|
/* If ltrace gets SIGINT, the processes directly or indirectly run by
|
|
* ltrace get it too. We just have to wait long enough for the signal
|
|
* to be delivered and the process terminated, which we notice and
|
|
@@ -1152,7 +1172,7 @@ os_ltrace_exiting(void)
|
|
{
|
|
struct opt_p_t *it;
|
|
for (it = opt_p; it != NULL; it = it->next) {
|
|
- struct Process *proc = pid2proc(it->pid);
|
|
+ struct process *proc = pid2proc(it->pid);
|
|
if (proc == NULL || proc->leader == NULL)
|
|
continue;
|
|
if (ltrace_exiting_install_handler(proc->leader) < 0)
|
|
@@ -1174,7 +1194,8 @@ os_ltrace_exiting_sighandler(void)
|
|
}
|
|
|
|
size_t
|
|
-umovebytes(Process *proc, void *addr, void *laddr, size_t len) {
|
|
+umovebytes(struct process *proc, void *addr, void *laddr, size_t len)
|
|
+{
|
|
|
|
union {
|
|
long a;
|
|
diff --git a/sysdeps/linux-gnu/trace.h b/sysdeps/linux-gnu/trace.h
|
|
index 88ac33d..e988f70 100644
|
|
--- a/sysdeps/linux-gnu/trace.h
|
|
+++ b/sysdeps/linux-gnu/trace.h
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
* This file is part of ltrace.
|
|
- * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
|
|
+ * Copyright (C) 2011,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
|
|
@@ -59,13 +59,13 @@ struct process_stopping_handler
|
|
struct event_handler super;
|
|
|
|
/* The task that is doing the re-enablement. */
|
|
- struct Process *task_enabling_breakpoint;
|
|
+ struct process *task_enabling_breakpoint;
|
|
|
|
/* The pointer being re-enabled. */
|
|
struct breakpoint *breakpoint_being_enabled;
|
|
|
|
/* Artificial atomic skip breakpoint, if any needed. */
|
|
- void *atomic_skip_bp_addrs[2];
|
|
+ arch_addr_t sws_bp_addrs[2];
|
|
|
|
/* When all tasks are stopped, this callback gets called. */
|
|
void (*on_all_stopped)(struct process_stopping_handler *);
|
|
@@ -84,17 +84,17 @@ struct process_stopping_handler
|
|
|
|
enum {
|
|
/* We are waiting for everyone to land in t/T. */
|
|
- psh_stopping = 0,
|
|
+ PSH_STOPPING = 0,
|
|
|
|
/* We are doing the PTRACE_SINGLESTEP. */
|
|
- psh_singlestep,
|
|
+ PSH_SINGLESTEP,
|
|
|
|
/* We are waiting for all the SIGSTOPs to arrive so
|
|
* that we can sink them. */
|
|
- psh_sinking,
|
|
+ PSH_SINKING,
|
|
|
|
/* This is for tracking the ugly workaround. */
|
|
- psh_ugly_workaround,
|
|
+ PSH_UGLY_WORKAROUND,
|
|
} state;
|
|
|
|
int exiting;
|
|
@@ -108,7 +108,7 @@ struct process_stopping_handler
|
|
* ON_ALL_STOPPED is LINUX_PTRACE_DISABLE_AND_SINGLESTEP, the default
|
|
* for KEEP_STEPPING_P and UGLY_WORKAROUND_P is "no". */
|
|
int process_install_stopping_handler
|
|
- (struct Process *proc, struct breakpoint *sbp,
|
|
+ (struct process *proc, struct breakpoint *sbp,
|
|
void (*on_all_stopped)(struct process_stopping_handler *),
|
|
enum callback_status (*keep_stepping_p)
|
|
(struct process_stopping_handler *),
|
|
diff --git a/sysdeps/linux-gnu/x86/fetch.c b/sysdeps/linux-gnu/x86/fetch.c
|
|
index 4dab4cc..aa02a0a 100644
|
|
--- a/sysdeps/linux-gnu/x86/fetch.c
|
|
+++ b/sysdeps/linux-gnu/x86/fetch.c
|
|
@@ -323,13 +323,13 @@ allocate_class(enum arg_class cls, struct fetch_context *context,
|
|
}
|
|
|
|
static ssize_t
|
|
-classify(struct Process *proc, struct fetch_context *context,
|
|
+classify(struct process *proc, struct fetch_context *context,
|
|
struct arg_type_info *info, struct value *valuep, enum arg_class classes[],
|
|
size_t sz, size_t eightbytes);
|
|
|
|
/* This classifies one eightbyte part of an array or struct. */
|
|
static ssize_t
|
|
-classify_eightbyte(struct Process *proc, struct fetch_context *context,
|
|
+classify_eightbyte(struct process *proc, struct fetch_context *context,
|
|
struct arg_type_info *info, struct value *valuep,
|
|
enum arg_class *classp, size_t start, size_t end,
|
|
struct arg_type_info *(*getter)(struct arg_type_info *,
|
|
@@ -364,7 +364,7 @@ classify_eightbyte(struct Process *proc, struct fetch_context *context,
|
|
|
|
/* This classifies small arrays and structs. */
|
|
static ssize_t
|
|
-classify_eightbytes(struct Process *proc, struct fetch_context *context,
|
|
+classify_eightbytes(struct process *proc, struct fetch_context *context,
|
|
struct arg_type_info *info, struct value *valuep,
|
|
enum arg_class classes[], size_t elements,
|
|
size_t eightbytes,
|
|
@@ -432,7 +432,7 @@ flatten_structure(struct arg_type_info *flattened, struct arg_type_info *info)
|
|
}
|
|
|
|
static ssize_t
|
|
-classify(struct Process *proc, struct fetch_context *context,
|
|
+classify(struct process *proc, struct fetch_context *context,
|
|
struct arg_type_info *info, struct value *valuep, enum arg_class classes[],
|
|
size_t sz, size_t eightbytes)
|
|
{
|
|
@@ -517,7 +517,7 @@ pass_by_reference(struct value *valuep, enum arg_class classes[])
|
|
}
|
|
|
|
static ssize_t
|
|
-classify_argument(struct Process *proc, struct fetch_context *context,
|
|
+classify_argument(struct process *proc, struct fetch_context *context,
|
|
struct arg_type_info *info, struct value *valuep,
|
|
enum arg_class classes[], size_t *sizep)
|
|
{
|
|
@@ -545,7 +545,7 @@ classify_argument(struct Process *proc, struct fetch_context *context,
|
|
}
|
|
|
|
static int
|
|
-fetch_register_banks(struct Process *proc, struct fetch_context *context,
|
|
+fetch_register_banks(struct process *proc, struct fetch_context *context,
|
|
int floating)
|
|
{
|
|
if (ptrace(PTRACE_GETREGS, proc->pid, 0, &context->iregs) < 0)
|
|
@@ -566,7 +566,7 @@ fetch_register_banks(struct Process *proc, struct fetch_context *context,
|
|
|
|
static int
|
|
arch_fetch_arg_next_32(struct fetch_context *context, enum tof type,
|
|
- struct Process *proc, struct arg_type_info *info,
|
|
+ struct process *proc, struct arg_type_info *info,
|
|
struct value *valuep)
|
|
{
|
|
size_t sz = type_sizeof(proc, info);
|
|
@@ -580,7 +580,7 @@ arch_fetch_arg_next_32(struct fetch_context *context, enum tof type,
|
|
|
|
static int
|
|
arch_fetch_retval_32(struct fetch_context *context, enum tof type,
|
|
- struct Process *proc, struct arg_type_info *info,
|
|
+ struct process *proc, struct arg_type_info *info,
|
|
struct value *valuep)
|
|
{
|
|
if (fetch_register_banks(proc, context, type == LT_TOF_FUNCTIONR) < 0)
|
|
@@ -646,7 +646,7 @@ fetch_stack_pointer(struct fetch_context *context)
|
|
|
|
struct fetch_context *
|
|
arch_fetch_arg_init_32(struct fetch_context *context,
|
|
- enum tof type, struct Process *proc,
|
|
+ enum tof type, struct process *proc,
|
|
struct arg_type_info *ret_info)
|
|
{
|
|
context->stack_pointer = fetch_stack_pointer(context) + 4;
|
|
@@ -673,7 +673,7 @@ arch_fetch_arg_init_32(struct fetch_context *context,
|
|
|
|
struct fetch_context *
|
|
arch_fetch_arg_init_64(struct fetch_context *ctx, enum tof type,
|
|
- struct Process *proc, struct arg_type_info *ret_info)
|
|
+ struct process *proc, struct arg_type_info *ret_info)
|
|
{
|
|
/* The first stack slot holds a return address. */
|
|
ctx->stack_pointer = fetch_stack_pointer(ctx) + 8;
|
|
@@ -698,7 +698,7 @@ arch_fetch_arg_init_64(struct fetch_context *ctx, enum tof type,
|
|
}
|
|
|
|
struct fetch_context *
|
|
-arch_fetch_arg_init(enum tof type, struct Process *proc,
|
|
+arch_fetch_arg_init(enum tof type, struct process *proc,
|
|
struct arg_type_info *ret_info)
|
|
{
|
|
struct fetch_context *ctx = malloc(sizeof(*ctx));
|
|
@@ -724,7 +724,7 @@ arch_fetch_arg_init(enum tof type, struct Process *proc,
|
|
}
|
|
|
|
struct fetch_context *
|
|
-arch_fetch_arg_clone(struct Process *proc, struct fetch_context *context)
|
|
+arch_fetch_arg_clone(struct process *proc, struct fetch_context *context)
|
|
{
|
|
struct fetch_context *ret = malloc(sizeof(*ret));
|
|
if (ret == NULL)
|
|
@@ -734,7 +734,7 @@ arch_fetch_arg_clone(struct Process *proc, struct fetch_context *context)
|
|
|
|
static int
|
|
arch_fetch_pool_arg_next(struct fetch_context *context, enum tof type,
|
|
- struct Process *proc, struct arg_type_info *info,
|
|
+ struct process *proc, struct arg_type_info *info,
|
|
struct value *valuep, enum reg_pool pool)
|
|
{
|
|
enum arg_class classes[2];
|
|
@@ -776,7 +776,7 @@ arch_fetch_pool_arg_next(struct fetch_context *context, enum tof type,
|
|
|
|
int
|
|
arch_fetch_fun_retval(struct fetch_context *context, enum tof type,
|
|
- struct Process *proc, struct arg_type_info *info,
|
|
+ struct process *proc, struct arg_type_info *info,
|
|
struct value *valuep)
|
|
{
|
|
assert(type != LT_TOF_FUNCTION
|
|
@@ -808,7 +808,7 @@ arch_fetch_fun_retval(struct fetch_context *context, enum tof type,
|
|
|
|
int
|
|
arch_fetch_arg_next(struct fetch_context *context, enum tof type,
|
|
- struct Process *proc, struct arg_type_info *info,
|
|
+ struct process *proc, struct arg_type_info *info,
|
|
struct value *valuep)
|
|
{
|
|
if (proc->e_machine == EM_386)
|
|
@@ -832,7 +832,7 @@ arch_fetch_arg_next(struct fetch_context *context, enum tof type,
|
|
|
|
int
|
|
arch_fetch_retval(struct fetch_context *context, enum tof type,
|
|
- struct Process *proc, struct arg_type_info *info,
|
|
+ struct process *proc, struct arg_type_info *info,
|
|
struct value *valuep)
|
|
{
|
|
if (proc->e_machine == EM_386)
|
|
diff --git a/sysdeps/linux-gnu/x86/plt.c b/sysdeps/linux-gnu/x86/plt.c
|
|
index dc6f183..c2a4151 100644
|
|
--- a/sysdeps/linux-gnu/x86/plt.c
|
|
+++ b/sysdeps/linux-gnu/x86/plt.c
|
|
@@ -24,11 +24,13 @@
|
|
#include "library.h"
|
|
|
|
GElf_Addr
|
|
-arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
|
|
+arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela)
|
|
+{
|
|
return lte->plt_addr + (ndx + 1) * 16;
|
|
}
|
|
|
|
void *
|
|
-sym2addr(Process *proc, struct library_symbol *sym) {
|
|
+sym2addr(struct process *proc, struct library_symbol *sym)
|
|
+{
|
|
return sym->enter_addr;
|
|
}
|
|
diff --git a/sysdeps/linux-gnu/x86/regs.c b/sysdeps/linux-gnu/x86/regs.c
|
|
index ca6470b..3886e84 100644
|
|
--- a/sysdeps/linux-gnu/x86/regs.c
|
|
+++ b/sysdeps/linux-gnu/x86/regs.c
|
|
@@ -56,7 +56,7 @@ conv_32(arch_addr_t val)
|
|
}
|
|
|
|
void *
|
|
-get_instruction_pointer(struct Process *proc)
|
|
+get_instruction_pointer(struct process *proc)
|
|
{
|
|
long int ret = ptrace(PTRACE_PEEKUSER, proc->pid, XIP, 0);
|
|
if (proc->e_machine == EM_386)
|
|
@@ -65,7 +65,7 @@ get_instruction_pointer(struct Process *proc)
|
|
}
|
|
|
|
void
|
|
-set_instruction_pointer(struct Process *proc, arch_addr_t addr)
|
|
+set_instruction_pointer(struct process *proc, arch_addr_t addr)
|
|
{
|
|
if (proc->e_machine == EM_386)
|
|
addr = conv_32(addr);
|
|
@@ -73,7 +73,7 @@ set_instruction_pointer(struct Process *proc, arch_addr_t addr)
|
|
}
|
|
|
|
void *
|
|
-get_stack_pointer(struct Process *proc)
|
|
+get_stack_pointer(struct process *proc)
|
|
{
|
|
long sp = ptrace(PTRACE_PEEKUSER, proc->pid, XSP, 0);
|
|
if (sp == -1 && errno) {
|
|
@@ -91,7 +91,7 @@ get_stack_pointer(struct Process *proc)
|
|
}
|
|
|
|
void *
|
|
-get_return_addr(struct Process *proc, void *sp)
|
|
+get_return_addr(struct process *proc, void *sp)
|
|
{
|
|
long a = ptrace(PTRACE_PEEKTEXT, proc->pid, sp, 0);
|
|
if (a == -1 && errno) {
|
|
@@ -109,7 +109,8 @@ get_return_addr(struct Process *proc, void *sp)
|
|
}
|
|
|
|
void
|
|
-set_return_addr(Process *proc, void *addr) {
|
|
+set_return_addr(struct process *proc, void *addr)
|
|
+{
|
|
if (proc->e_machine == EM_386)
|
|
addr = (void *)((long int)addr & 0xffffffff);
|
|
ptrace(PTRACE_POKETEXT, proc->pid, proc->stack_pointer, addr);
|
|
diff --git a/sysdeps/linux-gnu/x86/trace.c b/sysdeps/linux-gnu/x86/trace.c
|
|
index ed8bdb4..6a1a6a5 100644
|
|
--- a/sysdeps/linux-gnu/x86/trace.c
|
|
+++ b/sysdeps/linux-gnu/x86/trace.c
|
|
@@ -55,7 +55,7 @@ static const int x86_64 = 0;
|
|
#endif
|
|
|
|
void
|
|
-get_arch_dep(struct Process *proc)
|
|
+get_arch_dep(struct process *proc)
|
|
{
|
|
/* Unfortunately there are still remnants of mask_32bit uses
|
|
* around. */
|
|
@@ -75,7 +75,7 @@ get_arch_dep(struct Process *proc)
|
|
/* Returns 1 if syscall, 2 if sysret, 0 otherwise.
|
|
*/
|
|
int
|
|
-syscall_p(struct Process *proc, int status, int *sysnum)
|
|
+syscall_p(struct process *proc, int status, int *sysnum)
|
|
{
|
|
if (WIFSTOPPED(status)
|
|
&& WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
|
|
@@ -109,7 +109,7 @@ syscall_p(struct Process *proc, int status, int *sysnum)
|
|
}
|
|
|
|
size_t
|
|
-arch_type_sizeof(struct Process *proc, struct arg_type_info *info)
|
|
+arch_type_sizeof(struct process *proc, struct arg_type_info *info)
|
|
{
|
|
if (proc == NULL)
|
|
return (size_t)-2;
|
|
@@ -151,7 +151,7 @@ arch_type_sizeof(struct Process *proc, struct arg_type_info *info)
|
|
}
|
|
|
|
size_t
|
|
-arch_type_alignof(struct Process *proc, struct arg_type_info *info)
|
|
+arch_type_alignof(struct process *proc, struct arg_type_info *info)
|
|
{
|
|
if (proc == NULL)
|
|
return (size_t)-2;
|
|
diff --git a/type.c b/type.c
|
|
index 3ce8563..d80550b 100644
|
|
--- a/type.c
|
|
+++ b/type.c
|
|
@@ -123,7 +123,7 @@ type_struct_destroy(struct arg_type_info *info)
|
|
}
|
|
|
|
static int
|
|
-layout_struct(struct Process *proc, struct arg_type_info *info,
|
|
+layout_struct(struct process *proc, struct arg_type_info *info,
|
|
size_t *sizep, size_t *alignmentp, size_t *offsetofp)
|
|
{
|
|
size_t sz = 0;
|
|
@@ -254,10 +254,10 @@ type_destroy(struct arg_type_info *info)
|
|
}
|
|
|
|
#ifdef ARCH_HAVE_SIZEOF
|
|
-size_t arch_type_sizeof(struct Process *proc, struct arg_type_info * arg);
|
|
+size_t arch_type_sizeof(struct process *proc, struct arg_type_info *arg);
|
|
#else
|
|
size_t
|
|
-arch_type_sizeof(struct Process *proc, struct arg_type_info * arg)
|
|
+arch_type_sizeof(struct process *proc, struct arg_type_info *arg)
|
|
{
|
|
/* Use default value. */
|
|
return (size_t)-2;
|
|
@@ -265,10 +265,10 @@ arch_type_sizeof(struct Process *proc, struct arg_type_info * arg)
|
|
#endif
|
|
|
|
#ifdef ARCH_HAVE_ALIGNOF
|
|
-size_t arch_type_alignof(struct Process *proc, struct arg_type_info * arg);
|
|
+size_t arch_type_alignof(struct process *proc, struct arg_type_info *arg);
|
|
#else
|
|
size_t
|
|
-arch_type_alignof(struct Process *proc, struct arg_type_info * arg)
|
|
+arch_type_alignof(struct process *proc, struct arg_type_info *arg)
|
|
{
|
|
/* Use default value. */
|
|
return (size_t)-2;
|
|
@@ -289,7 +289,7 @@ align(size_t sz, size_t alignment)
|
|
}
|
|
|
|
size_t
|
|
-type_sizeof(struct Process *proc, struct arg_type_info *type)
|
|
+type_sizeof(struct process *proc, struct arg_type_info *type)
|
|
{
|
|
size_t arch_size = arch_type_sizeof(proc, type);
|
|
if (arch_size != (size_t)-2)
|
|
@@ -359,7 +359,7 @@ type_sizeof(struct Process *proc, struct arg_type_info *type)
|
|
#define alignof(field,st) ((size_t) ((char*) &st.field - (char*) &st))
|
|
|
|
size_t
|
|
-type_alignof(struct Process *proc, struct arg_type_info *type)
|
|
+type_alignof(struct process *proc, struct arg_type_info *type)
|
|
{
|
|
size_t arch_alignment = arch_type_alignof(proc, type);
|
|
if (arch_alignment != (size_t)-2)
|
|
@@ -412,7 +412,7 @@ type_alignof(struct Process *proc, struct arg_type_info *type)
|
|
}
|
|
|
|
size_t
|
|
-type_offsetof(struct Process *proc, struct arg_type_info *type, size_t emt)
|
|
+type_offsetof(struct process *proc, struct arg_type_info *type, size_t emt)
|
|
{
|
|
assert(type->type == ARGTYPE_STRUCT
|
|
|| type->type == ARGTYPE_ARRAY);
|
|
diff --git a/type.h b/type.h
|
|
index e8dec71..b92c1af 100644
|
|
--- a/type.h
|
|
+++ b/type.h
|
|
@@ -111,11 +111,11 @@ void type_init_pointer(struct arg_type_info *info,
|
|
void type_destroy(struct arg_type_info *info);
|
|
|
|
/* Compute a size of given type. Return (size_t)-1 for error. */
|
|
-size_t type_sizeof(struct Process *proc, struct arg_type_info *type);
|
|
+size_t type_sizeof(struct process *proc, struct arg_type_info *type);
|
|
|
|
/* Compute an alignment necessary for elements of this type. Return
|
|
* (size_t)-1 for error. */
|
|
-size_t type_alignof(struct Process *proc, struct arg_type_info *type);
|
|
+size_t type_alignof(struct process *proc, struct arg_type_info *type);
|
|
|
|
/* Align value SZ to ALIGNMENT and return the result. */
|
|
size_t align(size_t sz, size_t alignment);
|
|
@@ -126,7 +126,7 @@ struct arg_type_info *type_element(struct arg_type_info *type, size_t elt);
|
|
|
|
/* Compute an offset of EMT-th element of type TYPE. This works for
|
|
* arrays and structures. Return (size_t)-1 for error. */
|
|
-size_t type_offsetof(struct Process *proc,
|
|
+size_t type_offsetof(struct process *proc,
|
|
struct arg_type_info *type, size_t elt);
|
|
|
|
/* Whether TYPE is an integral type as defined by the C standard. */
|
|
diff --git a/value.c b/value.c
|
|
index f7950da..d18db17 100644
|
|
--- a/value.c
|
|
+++ b/value.c
|
|
@@ -29,7 +29,7 @@
|
|
#include "backend.h"
|
|
|
|
static void
|
|
-value_common_init(struct value *valp, struct Process *inferior,
|
|
+value_common_init(struct value *valp, struct process *inferior,
|
|
struct value *parent, struct arg_type_info *type,
|
|
int own_type)
|
|
{
|
|
@@ -43,7 +43,7 @@ value_common_init(struct value *valp, struct Process *inferior,
|
|
}
|
|
|
|
void
|
|
-value_init(struct value *valp, struct Process *inferior, struct value *parent,
|
|
+value_init(struct value *valp, struct process *inferior, struct value *parent,
|
|
struct arg_type_info *type, int own_type)
|
|
{
|
|
assert(inferior != NULL);
|
|
diff --git a/value.h b/value.h
|
|
index 795573c..f501254 100644
|
|
--- a/value.h
|
|
+++ b/value.h
|
|
@@ -46,7 +46,7 @@ enum value_location_t {
|
|
|
|
struct value {
|
|
struct arg_type_info *type;
|
|
- struct Process *inferior;
|
|
+ struct process *inferior;
|
|
struct value *parent;
|
|
size_t size;
|
|
union {
|
|
@@ -63,7 +63,7 @@ struct value {
|
|
* value, in case of compound types. It may be NULL. TYPE is a type
|
|
* of the value. It may be NULL if the type is not yet known. If
|
|
* OWN_TYPE, the passed-in type is owned and released by value. */
|
|
-void value_init(struct value *value, struct Process *inferior,
|
|
+void value_init(struct value *value, struct process *inferior,
|
|
struct value *parent, struct arg_type_info *type,
|
|
int own_type);
|
|
|
|
diff --git a/zero.c b/zero.c
|
|
index bc119ee..5757943 100644
|
|
--- a/zero.c
|
|
+++ b/zero.c
|
|
@@ -18,7 +18,6 @@
|
|
* 02110-1301 USA
|
|
*/
|
|
|
|
-#include <error.h>
|
|
#include <errno.h>
|
|
|
|
#include "zero.h"
|
|
@@ -93,13 +92,12 @@ build_zero_w_arg(struct expr_node *expr, int own)
|
|
struct expr_node *
|
|
expr_node_zero(void)
|
|
{
|
|
- static struct expr_node *node = NULL;
|
|
- if (node == NULL) {
|
|
- node = malloc(sizeof(*node));
|
|
- if (node == NULL)
|
|
- error(1, errno, "malloc expr_node_zero");
|
|
- expr_init_cb1(node, &zero1_callback,
|
|
+ static struct expr_node *nodep = NULL;
|
|
+ if (nodep == NULL) {
|
|
+ static struct expr_node node;
|
|
+ expr_init_cb1(&node, &zero1_callback,
|
|
expr_self(), 0, (void *)-1);
|
|
+ nodep = &node;
|
|
}
|
|
- return node;
|
|
+ return nodep;
|
|
}
|