From aa961fbb7f0b790dacaf6d3d4b0532598372b11d Mon Sep 17 00:00:00 2001 From: Petr Machata Date: May 31 2012 16:30:02 +0000 Subject: Add upstream patches for parameter passing, add s390 support --- diff --git a/ltrace-0.6.0-abi-s390.patch b/ltrace-0.6.0-abi-s390.patch new file mode 100644 index 0000000..cfb870d --- /dev/null +++ b/ltrace-0.6.0-abi-s390.patch @@ -0,0 +1,1695 @@ +diff --git a/backend.h b/backend.h +index 08306e1..29688ea 100644 +--- a/backend.h ++++ b/backend.h +@@ -22,6 +22,8 @@ + #define BACKEND_H + + #include "forward.h" ++#include "sysdep.h" ++ + #include + + enum process_status { +@@ -33,8 +35,6 @@ enum process_status { + ps_other, /* Necessary other states can be added as needed. */ + }; + +-typedef void *target_address_t; +- + /* + * This file contains documentation of back end interface. Some of + * these may be implemented on an OS level (i.e. they are the same +@@ -93,7 +93,7 @@ void get_arch_dep(struct Process *proc); + * XXX note that the IP must fit into an arch pointer. This prevents + * us to use 32-bit ltrace to trace 64-bit process, even on arches + * that would otherwise support this. Above we have a definition of +- * target_address_t. This should be converted to an integral type and ++ * arch_addr_t. This should be converted to an integral type and + * used for target addresses throughout. */ + void *get_instruction_pointer(struct Process *proc); + +@@ -183,7 +183,7 @@ void *sym2addr(struct Process *proc, struct library_symbol *sym); + /* 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, target_address_t dyn_addr); ++int linkmap_init(struct Process *proc, arch_addr_t dyn_addr); + + /* Called for breakpoints defined over an artificial symbol "". This + * can be used (like it is on Linux/GNU) to add more breakpoints +@@ -240,8 +240,8 @@ int arch_process_exec(struct Process *proc); + * otherwise. Sets *ENTRYP and *INTERP_BIASP to non-zero values if + * the corresponding value is known. Unknown values are set to 0. */ + int process_get_entry(struct Process *proc, +- target_address_t *entryp, +- target_address_t *interp_biasp); ++ arch_addr_t *entryp, ++ arch_addr_t *interp_biasp); + + /* This is called after the dynamic linker is done with the + * process startup. */ +diff --git a/breakpoint.h b/breakpoint.h +index 0398072..7cd914e 100644 +--- a/breakpoint.h ++++ b/breakpoint.h +@@ -81,7 +81,7 @@ void breakpoint_on_retract(struct breakpoint *bp, struct Process *proc); + * disabled. orig_value has to be set separately. CBS may be + * NULL. */ + int breakpoint_init(struct breakpoint *bp, struct Process *proc, +- target_address_t addr, struct library_symbol *libsym); ++ 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, +diff --git a/breakpoints.c b/breakpoints.c +index 8dc09df..e7120ee 100644 +--- a/breakpoints.c ++++ b/breakpoints.c +@@ -20,7 +20,7 @@ + #ifndef ARCH_HAVE_TRANSLATE_ADDRESS + int + arch_translate_address_dyn(struct Process *proc, +- target_address_t addr, target_address_t *ret) ++ arch_addr_t addr, arch_addr_t *ret) + { + *ret = addr; + return 0; +@@ -29,7 +29,7 @@ arch_translate_address_dyn(struct Process *proc, + struct ltelf; + int + arch_translate_address(struct ltelf *lte, +- target_address_t addr, target_address_t *ret) ++ arch_addr_t addr, arch_addr_t *ret) + { + *ret = addr; + return 0; +@@ -95,7 +95,7 @@ arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp) + + static void + breakpoint_init_base(struct breakpoint *bp, struct Process *proc, +- target_address_t addr, struct library_symbol *libsym) ++ arch_addr_t addr, struct library_symbol *libsym) + { + bp->cbs = NULL; + bp->addr = addr; +@@ -110,7 +110,7 @@ breakpoint_init_base(struct breakpoint *bp, struct Process *proc, + * need process for anything. */ + int + breakpoint_init(struct breakpoint *bp, struct Process *proc, +- target_address_t addr, struct library_symbol *libsym) ++ arch_addr_t addr, struct library_symbol *libsym) + { + breakpoint_init_base(bp, proc, addr, libsym); + return arch_breakpoint_init(proc, bp); +@@ -357,7 +357,7 @@ disable_all_breakpoints(Process *proc) { + * for one structure. */ + struct entry_breakpoint { + struct breakpoint super; +- target_address_t dyn_addr; ++ arch_addr_t dyn_addr; + }; + + static void +@@ -366,7 +366,7 @@ entry_breakpoint_on_hit(struct breakpoint *a, struct Process *proc) + struct entry_breakpoint *bp = (void *)a; + if (proc == NULL || proc->leader == NULL) + return; +- target_address_t dyn_addr = bp->dyn_addr; ++ arch_addr_t dyn_addr = bp->dyn_addr; + delete_breakpoint(proc, bp->super.addr); + linkmap_init(proc, dyn_addr); + arch_dynlink_done(proc); +@@ -374,7 +374,7 @@ entry_breakpoint_on_hit(struct breakpoint *a, struct Process *proc) + + int + entry_breakpoint_init(struct Process *proc, +- struct entry_breakpoint *bp, target_address_t addr, ++ struct entry_breakpoint *bp, arch_addr_t addr, + struct library *lib) + { + int err; +diff --git a/library.c b/library.c +index 2bd7dbb..2ce3427 100644 +--- a/library.c ++++ b/library.c +@@ -71,10 +71,10 @@ target_address_hash(const void *key) + { + /* XXX this assumes that key is passed by value. */ + union { +- target_address_t addr; +- unsigned int ints[sizeof(target_address_t) ++ arch_addr_t addr; ++ unsigned int ints[sizeof(arch_addr_t) + / sizeof(unsigned int)]; +- } u = { .addr = (target_address_t)key }; ++ } u = { .addr = (arch_addr_t)key }; + + size_t i; + unsigned int h = 0; +@@ -87,8 +87,8 @@ int + target_address_cmp(const void *key1, const void *key2) + { + /* XXX this assumes that key is passed by value. */ +- target_address_t addr1 = (target_address_t)key1; +- target_address_t addr2 = (target_address_t)key2; ++ arch_addr_t addr1 = (arch_addr_t)key1; ++ arch_addr_t addr2 = (arch_addr_t)key2; + return addr1 < addr2 ? 1 + : addr1 > addr2 ? -1 : 0; + } +@@ -110,7 +110,7 @@ strdup_if_owned(const char **retp, const char *str, int owned) + + static void + private_library_symbol_init(struct library_symbol *libsym, +- target_address_t addr, ++ arch_addr_t addr, + const char *name, int own_name, + enum toplt type_of_plt) + { +@@ -130,7 +130,7 @@ private_library_symbol_destroy(struct library_symbol *libsym) + + int + library_symbol_init(struct library_symbol *libsym, +- target_address_t addr, const char *name, int own_name, ++ arch_addr_t addr, const char *name, int own_name, + enum toplt type_of_plt) + { + private_library_symbol_init(libsym, addr, name, own_name, type_of_plt); +@@ -358,5 +358,5 @@ 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) + { +- return lib->key == *(target_address_t *)keyp ? CBS_STOP : CBS_CONT; ++ return lib->key == *(arch_addr_t *)keyp ? CBS_STOP : CBS_CONT; + } +diff --git a/library.h b/library.h +index c387b02..876a533 100644 +--- a/library.h ++++ b/library.h +@@ -33,13 +33,6 @@ enum toplt { + LS_TOPLT_EXEC, /* PLT for this symbol is executable. */ + }; + +-/* We should in general be able to trace 64-bit processes with 32-bit +- * ltrace. (At least PPC has several PTRACE requests related to +- * tracing 64-on-32, so presumably it should be possible.) But ltrace +- * is currently hopelessly infested with using void* for host address. +- * So keep with it, for now. */ +-typedef void *target_address_t; +- + /* Dict interface. */ + unsigned int target_address_hash(const void *key); + int target_address_cmp(const void *key1, const void *key2); +@@ -48,7 +41,7 @@ struct library_symbol { + struct library_symbol *next; + struct library *lib; + const char *name; +- target_address_t enter_addr; ++ arch_addr_t enter_addr; + enum toplt plt_type; + char own_name; + struct arch_library_symbol_data arch; +@@ -57,7 +50,7 @@ struct library_symbol { + /* Init LIBSYM. NAME will be freed when LIBSYM is destroyed if + * OWN_NAME. ARCH has to be initialized by a separate call. */ + int library_symbol_init(struct library_symbol *libsym, +- target_address_t addr, const char *name, int own_name, ++ arch_addr_t addr, const char *name, int own_name, + enum toplt type_of_plt); + + /* Copy library symbol SYM into the area pointed-to by RETP. Return 0 +@@ -102,20 +95,20 @@ struct library { + + /* Unique key. Two library objects are considered equal, if + * they have the same key. */ +- target_address_t key; ++ arch_addr_t key; + + /* Address where the library is mapped. Two library objects + * are considered equal, if they have the same base. */ +- target_address_t base; ++ arch_addr_t base; + + /* Absolute address of the entry point. Useful for main + * binary, though I suppose the value might be useful for the + * dynamic linker, too (in case we ever want to do early + * process tracing). */ +- target_address_t entry; ++ arch_addr_t entry; + + /* Address of PT_DYNAMIC segment. */ +- target_address_t dyn_addr; ++ arch_addr_t dyn_addr; + + /* Symbols associated with the library. */ + struct library_symbol *symbols; +@@ -171,14 +164,14 @@ enum callback_status library_named_cb(struct Process *proc, + /* A function that can be used as proc_each_library callback. Looks + * for a library with given base. + * +- * NOTE: The key is passed as a POINTER to target_address_t (that +- * because in general, target_address_t doesn't fit in void*). */ ++ * 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, + struct library *lib, void *keyp); + + /* XXX this should really be in backend.h (as on pmachata/revamp + * branch), or, on this branch, in common.h. But we need +- * target_address_t (which should also be in backend.h, I reckon), so ++ * arch_addr_t (which should also be in backend.h, I reckon), so + * stuff it here for the time being. */ + /* This function is implemented in the back end. It is called for all + * raw addresses as read from symbol tables etc. If necessary on +@@ -187,10 +180,10 @@ enum callback_status library_with_key_cb(struct Process *proc, + * success and a negative value on failure. */ + struct ltelf; + int arch_translate_address(struct ltelf *lte, +- target_address_t addr, target_address_t *ret); ++ 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, +- target_address_t addr, target_address_t *ret); ++ arch_addr_t addr, arch_addr_t *ret); + + #endif /* _LIBRARY_H_ */ +diff --git a/ltrace-elf.c b/ltrace-elf.c +index e4a61eb..50c4f62 100644 +--- a/ltrace-elf.c ++++ b/ltrace-elf.c +@@ -84,8 +84,8 @@ default_elf_add_plt_entry(struct Process *proc, struct ltelf *lte, + goto fail; + + /* XXX The double cast should be removed when +- * target_address_t becomes integral type. */ +- target_address_t taddr = (target_address_t) ++ * arch_addr_t becomes integral type. */ ++ arch_addr_t taddr = (arch_addr_t) + (uintptr_t)(addr + lte->bias); + + if (library_symbol_init(libsym, taddr, name, 1, LS_TOPLT_EXEC) < 0) { +@@ -573,7 +573,7 @@ populate_plt(struct Process *proc, const char *filename, + * each address, and replace name in libsym with a shorter variant if + * we find it. */ + struct unique_symbol { +- target_address_t addr; ++ arch_addr_t addr; + struct library_symbol *libsym; + }; + +@@ -593,7 +593,8 @@ populate_this_symtab(struct Process *proc, const char *filename, + + /* XXX support IFUNC as well. */ + if (GELF_ST_TYPE(sym.st_info) != STT_FUNC +- || sym.st_value == 0) ++ || sym.st_value == 0 ++ || sym.st_shndx == STN_UNDEF) + continue; + + const char *orig_name = strtab + sym.st_name; +@@ -642,9 +642,9 @@ populate_this_symtab(struct Process *proc, const char *filename, + if (!filter_matches_symbol(options.static_filter, name, lib)) + continue; + +- target_address_t addr = (target_address_t) ++ arch_addr_t addr = (arch_addr_t) + (uintptr_t)(sym.st_value + lte->bias); +- target_address_t naddr; ++ arch_addr_t naddr; + + /* On arches that support OPD, the value of typical + * function symbol will be a pointer to .opd, but some +@@ -734,6 +734,7 @@ ltelf_read_library(struct library *lib, struct Process *proc, + } + + proc->e_machine = lte.ehdr.e_machine; ++ proc->e_class = lte.ehdr.e_ident[EI_CLASS]; + + int status = 0; + if (lib == NULL) +@@ -764,18 +765,18 @@ ltelf_read_library(struct library *lib, struct Process *proc, + } + + /* XXX The double cast should be removed when +- * target_address_t becomes integral type. */ +- target_address_t entry = (target_address_t)(uintptr_t)lte.entry_addr; ++ * arch_addr_t becomes integral type. */ ++ arch_addr_t entry = (arch_addr_t)(uintptr_t)lte.entry_addr; + if (arch_translate_address(<e, entry, &entry) < 0) + goto fail; + + /* XXX The double cast should be removed when +- * target_address_t becomes integral type. */ +- lib->base = (target_address_t)(uintptr_t)lte.base_addr; ++ * arch_addr_t becomes integral type. */ ++ lib->base = (arch_addr_t)(uintptr_t)lte.base_addr; + lib->entry = entry; + /* XXX The double cast should be removed when +- * target_address_t becomes integral type. */ +- lib->dyn_addr = (target_address_t)(uintptr_t)lte.dyn_addr; ++ * arch_addr_t becomes integral type. */ ++ lib->dyn_addr = (arch_addr_t)(uintptr_t)lte.dyn_addr; + + if (filter_matches_library(options.plt_filter, lib) + && populate_plt(proc, filename, <e, lib) < 0) +diff --git a/output.c b/output.c +index 8bfe3f0..b138055 100644 +--- a/output.c ++++ b/output.c +@@ -546,12 +546,12 @@ output_right(enum tof type, struct Process *proc, struct library_symbol *libsym) + value_init(&retval, proc, NULL, func->return_info, 0); + own_retval = 1; + if (fetch_retval(context, type, proc, func->return_info, +- &retval) == 0) { +- if (stel->arguments != NULL +- && val_dict_push_named(stel->arguments, &retval, +- "retval", 0) == 0) +- own_retval = 0; +- } ++ &retval) < 0) ++ value_set_type(&retval, NULL, 0); ++ else if (stel->arguments != NULL ++ && val_dict_push_named(stel->arguments, &retval, ++ "retval", 0) == 0) ++ own_retval = 0; + } + + if (stel->arguments != NULL) +@@ -563,7 +563,8 @@ output_right(enum tof type, struct Process *proc, struct library_symbol *libsym) + tabto(options.align - 1); + fprintf(options.output, "= "); + +- output_one(&retval, stel->arguments); ++ if (context != NULL && retval.type != NULL) ++ output_one(&retval, stel->arguments); + + if (own_retval) + value_destroy(&retval); +diff --git a/proc.c b/proc.c +index b280df8..bf26180 100644 +--- a/proc.c ++++ b/proc.c +@@ -129,8 +129,8 @@ process_bare_destroy(struct Process *pro + static int + process_init_main(struct Process *proc) + { +- target_address_t entry; +- target_address_t interp_bias; ++ arch_addr_t entry; ++ arch_addr_t interp_bias; + if (process_get_entry(proc, &entry, &interp_bias) < 0) { + fprintf(stderr, "Couldn't get entry points of process %d\n", + proc->pid); +@@ -270,6 +270,7 @@ process_clone(struct Process *retp, struct Process *proc, pid_t pid) + + retp->tracesysgood = proc->tracesysgood; + retp->e_machine = proc->e_machine; ++ retp->e_class = proc->e_class; + + /* For non-leader processes, that's all we need to do. */ + if (retp->leader != retp) +diff --git a/proc.h b/proc.h +index fe9048f..5529187 100644 +--- a/proc.h ++++ b/proc.h +@@ -97,7 +97,7 @@ struct Process { + /* Dictionary of breakpoints (which is a mapping + * address->breakpoint). This is NULL for non-leader + * processes. XXX note that we store addresses (keys) by +- * value. That assumes that target_address_t fits in host ++ * value. That assumes that arch_addr_t fits in host + * pointer. */ + Dict * breakpoints; + +@@ -119,7 +119,15 @@ struct Process { + void * stack_pointer; /* To get return addr, args... */ + void * return_addr; + void * arch_ptr; ++ ++ /* XXX We would like to replace this with a pointer to ABI ++ * object that would provide the relevant services, instead of ++ * checking the necessary flags in the back end ad ++ * nauseam. */ + short e_machine; ++ char e_class; ++ ++ /* XXX this shoudl go to ARM's arch_process_data. */ + #ifdef __arm__ + int thumb_mode; /* ARM execution mode: 0: ARM, 1: Thumb */ + #endif +diff --git a/sysdeps/linux-gnu/arm/breakpoint.c b/sysdeps/linux-gnu/arm/breakpoint.c +index 5bcf86e..5748401 100644 +--- a/sysdeps/linux-gnu/arm/breakpoint.c ++++ b/sysdeps/linux-gnu/arm/breakpoint.c +@@ -95,7 +95,7 @@ int + arch_breakpoint_init(struct Process *proc, struct breakpoint *sbp) + { + /* XXX That uintptr_t cast is there temporarily until +- * target_address_t becomes integral type. */ ++ * arch_addr_t becomes integral type. */ + int thumb_mode = ((uintptr_t)sbp->addr) & 1; + if (thumb_mode) + sbp->addr = (void *)((uintptr_t)sbp->addr & ~1); +diff --git a/sysdeps/linux-gnu/ppc/fetch.c b/sysdeps/linux-gnu/ppc/fetch.c +index 370f43e..44cd056 100644 +--- a/sysdeps/linux-gnu/ppc/fetch.c ++++ b/sysdeps/linux-gnu/ppc/fetch.c +@@ -54,7 +54,7 @@ typedef uint32_t gregs32_t[48]; + typedef uint64_t gregs64_t[48]; + + struct fetch_context { +- target_address_t stack_pointer; ++ arch_addr_t stack_pointer; + int greg; + int freg; + int ret_struct; +@@ -159,10 +159,10 @@ allocate_stack_slot(struct fetch_context *ctx, struct Process *proc, + else if (proc->e_machine == EM_PPC64 && a < 8) + a = 8; + +- /* XXX Remove the two double casts when target_address_t ++ /* XXX Remove the two double casts when arch_addr_t + * becomes integral type. */ + uintptr_t tmp = align((uint64_t)(uintptr_t)ctx->stack_pointer, a); +- ctx->stack_pointer = (target_address_t)tmp; ++ ctx->stack_pointer = (arch_addr_t)tmp; + + if (valuep != NULL) { + valuep->where = VAL_LOC_INFERIOR; +@@ -409,9 +409,9 @@ arch_fetch_retval(struct fetch_context *ctx, enum tof type, + value_init(valuep, proc, NULL, info, 0); + + valuep->where = VAL_LOC_INFERIOR; +- /* XXX Remove the double cast when target_address_t ++ /* XXX Remove the double cast when arch_addr_t + * becomes integral type. */ +- valuep->u.address = (target_address_t)(uintptr_t)addr; ++ valuep->u.address = (arch_addr_t)(uintptr_t)addr; + return 0; + } + +diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c +index 944bd6a..c9ca458 100644 +--- a/sysdeps/linux-gnu/ppc/plt.c ++++ b/sysdeps/linux-gnu/ppc/plt.c +@@ -104,7 +104,7 @@ host_powerpc64() + } + + int +-read_target_4(struct Process *proc, target_address_t addr, uint32_t *lp) ++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) +@@ -117,7 +117,7 @@ read_target_4(struct Process *proc, target_address_t addr, uint32_t *lp) + } + + static int +-read_target_8(struct Process *proc, target_address_t addr, uint64_t *lp) ++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) +@@ -135,7 +135,7 @@ read_target_8(struct Process *proc, target_address_t addr, uint64_t *lp) + } + + int +-read_target_long(struct Process *proc, target_address_t addr, uint64_t *lp) ++read_target_long(struct Process *proc, arch_addr_t addr, uint64_t *lp) + { + if (proc->e_machine == EM_PPC) { + uint32_t w; +@@ -223,7 +223,7 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela) + * already. */ + int + arch_translate_address_dyn(struct Process *proc, +- target_address_t addr, target_address_t *ret) ++ arch_addr_t addr, arch_addr_t *ret) + { + if (proc->e_machine == EM_PPC64) { + uint64_t value; +@@ -232,8 +232,8 @@ arch_translate_address_dyn(struct Process *proc, + return -1; + } + /* XXX The double cast should be removed when +- * target_address_t becomes integral type. */ +- *ret = (target_address_t)(uintptr_t)value; ++ * arch_addr_t becomes integral type. */ ++ *ret = (arch_addr_t)(uintptr_t)value; + return 0; + } + +@@ -243,11 +243,11 @@ arch_translate_address_dyn(struct Process *proc, + + int + arch_translate_address(struct ltelf *lte, +- target_address_t addr, target_address_t *ret) ++ arch_addr_t addr, arch_addr_t *ret) + { + if (lte->ehdr.e_machine == EM_PPC64) { + /* XXX The double cast should be removed when +- * target_address_t becomes integral type. */ ++ * arch_addr_t becomes integral type. */ + GElf_Xword offset + = (GElf_Addr)(uintptr_t)addr - lte->arch.opd_base; + uint64_t value; +@@ -256,7 +256,7 @@ arch_translate_address(struct ltelf *lte, + elf_errmsg(-1)); + return -1; + } +- *ret = (target_address_t)(uintptr_t)(value + lte->bias); ++ *ret = (arch_addr_t)(uintptr_t)(value + lte->bias); + return 0; + } + +@@ -509,8 +509,8 @@ arch_elf_init(struct ltelf *lte, struct library *lib) + } + + /* XXX The double cast should be removed when +- * target_address_t becomes integral type. */ +- target_address_t addr = (target_address_t) ++ * arch_addr_t becomes integral type. */ ++ arch_addr_t addr = (arch_addr_t) + (uintptr_t)sym.st_value + lte->bias; + if (library_symbol_init(libsym, addr, sym_name, 1, + LS_TOPLT_EXEC) < 0) +@@ -533,7 +533,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, (target_address_t)(uintptr_t)addr, &l) < 0) { ++ if (read_target_8(proc, (arch_addr_t)(uintptr_t)addr, &l) < 0) { + error(0, errno, "ptrace .plt slot value @%#" PRIx64, addr); + return -1; + } +@@ -621,9 +621,9 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte, + } + + /* XXX The double cast should be removed when +- * target_address_t becomes integral type. */ ++ * arch_addr_t becomes integral type. */ + if (library_symbol_init(libsym, +- (target_address_t)(uintptr_t)plt_entry_addr, ++ (arch_addr_t)(uintptr_t)plt_entry_addr, + name, 1, LS_TOPLT_EXEC) < 0) + goto fail; + libsym->arch.plt_slot_addr = plt_slot_addr; +@@ -760,7 +760,7 @@ cb_keep_stepping_p(struct process_stopping_handler *self) + /* We need to install to the next instruction. ADDR points to + * a store instruction, so moving the breakpoint one + * instruction forward is safe. */ +- target_address_t addr = get_instruction_pointer(proc) + 4; ++ arch_addr_t addr = get_instruction_pointer(proc) + 4; + leader->arch.dl_plt_update_bp = insert_breakpoint(proc, addr, NULL); + if (leader->arch.dl_plt_update_bp == NULL) + goto done; +@@ -784,8 +784,8 @@ static void + jump_to_entry_point(struct Process *proc, struct breakpoint *bp) + { + /* XXX The double cast should be removed when +- * target_address_t becomes integral type. */ +- target_address_t rv = (target_address_t) ++ * arch_addr_t becomes integral type. */ ++ arch_addr_t rv = (arch_addr_t) + (uintptr_t)bp->libsym->arch.resolved_value; + set_instruction_pointer(proc, rv); + } +diff --git a/sysdeps/linux-gnu/ppc/trace.c b/sysdeps/linux-gnu/ppc/trace.c +index 0b734e4..2bb317f 100644 +--- a/sysdeps/linux-gnu/ppc/trace.c ++++ b/sysdeps/linux-gnu/ppc/trace.c +@@ -94,14 +94,14 @@ syscall_p(Process *proc, int status, int *sysnum) { + #define BRANCH_MASK 0xfc000000 + + /* In plt.h. XXX make this official interface. */ +-int read_target_4(struct Process *proc, target_address_t addr, uint32_t *lp); ++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) + { +- target_address_t ip = get_instruction_pointer(proc); ++ 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)", +@@ -129,7 +129,7 @@ arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp, + debug(1, "singlestep over atomic block at %p", ip); + + int insn_count; +- target_address_t addr = ip; ++ arch_addr_t addr = ip; + for (insn_count = 0; ; ++insn_count) { + addr += 4; + unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0); +@@ -149,7 +149,7 @@ arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp, + int absolute = insn & 2; + + /* XXX drop the following casts. */ +- target_address_t branch_addr; ++ arch_addr_t branch_addr; + if (absolute) + branch_addr = (void *)(uintptr_t)immediate; + else +diff --git a/sysdeps/linux-gnu/proc.c b/sysdeps/linux-gnu/proc.c +index e7556f5..d05da13 100644 +--- a/sysdeps/linux-gnu/proc.c ++++ b/sysdeps/linux-gnu/proc.c +@@ -288,7 +288,7 @@ select_32_64(struct Process *proc, void *p32, void *p64) + } + + static int +-fetch_dyn64(struct Process *proc, target_address_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 +297,7 @@ fetch_dyn64(struct Process *proc, target_address_t *addr, Elf64_Dyn *ret) + } + + static int +-fetch_dyn32(struct Process *proc, target_address_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)) +@@ -312,14 +312,14 @@ fetch_dyn32(struct Process *proc, target_address_t *addr, Elf64_Dyn *ret) + + static int (* + dyn_fetcher(struct Process *proc))(struct Process *, +- target_address_t *, Elf64_Dyn *) ++ arch_addr_t *, Elf64_Dyn *) + { + return select_32_64(proc, fetch_dyn32, fetch_dyn64); + } + + static int +-find_dynamic_entry_addr(struct Process *proc, target_address_t src_addr, +- int d_tag, target_address_t *ret) ++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()"); + +@@ -340,8 +340,8 @@ find_dynamic_entry_addr(struct Process *proc, target_address_t src_addr, + + if (entry.d_tag == d_tag) { + /* XXX The double cast should be removed when +- * target_address_t becomes integral type. */ +- *ret = (target_address_t)(uintptr_t)entry.d_un.d_val; ++ * arch_addr_t becomes integral type. */ ++ *ret = (arch_addr_t)(uintptr_t)entry.d_un.d_val; + debug(2, "found address: %p in dtag %d", *ret, d_tag); + return 0; + } +@@ -364,7 +364,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, target_address_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 +373,7 @@ fetch_lm64(struct Process *proc, target_address_t addr, + } + + static int +-fetch_lm32(struct Process *proc, target_address_t addr, ++fetch_lm32(struct Process *proc, arch_addr_t addr, + struct lt_link_map_64 *ret) + { + struct lt_link_map_32 lm; +@@ -391,7 +391,7 @@ fetch_lm32(struct Process *proc, target_address_t addr, + + static int (* + lm_fetcher(struct Process *proc))(struct Process *, +- target_address_t, struct lt_link_map_64 *) ++ arch_addr_t, struct lt_link_map_64 *) + { + return select_32_64(proc, fetch_lm32, fetch_lm64); + } +@@ -410,7 +410,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, target_address_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 +419,7 @@ fetch_rd64(struct Process *proc, target_address_t addr, + } + + static int +-fetch_rd32(struct Process *proc, target_address_t addr, ++fetch_rd32(struct Process *proc, arch_addr_t addr, + struct lt_r_debug_64 *ret) + { + struct lt_r_debug_32 rd; +@@ -437,7 +437,7 @@ fetch_rd32(struct Process *proc, target_address_t addr, + + static int (* + rdebug_fetcher(struct Process *proc))(struct Process *, +- target_address_t, struct lt_r_debug_64 *) ++ arch_addr_t, struct lt_r_debug_64 *) + { + return select_32_64(proc, fetch_rd32, fetch_rd64); + } +@@ -453,8 +453,8 @@ crawl_linkmap(struct Process *proc, struct lt_r_debug_64 *dbg) + } + + /* XXX The double cast should be removed when +- * target_address_t becomes integral type. */ +- target_address_t addr = (target_address_t)(uintptr_t)dbg->r_map; ++ * arch_addr_t becomes integral type. */ ++ arch_addr_t addr = (arch_addr_t)(uintptr_t)dbg->r_map; + + while (addr != 0) { + struct lt_link_map_64 rlm; +@@ -463,10 +463,10 @@ crawl_linkmap(struct Process *proc, struct lt_r_debug_64 *dbg) + return; + } + +- target_address_t key = addr; ++ arch_addr_t key = addr; + /* XXX The double cast should be removed when +- * target_address_t becomes integral type. */ +- addr = (target_address_t)(uintptr_t)rlm.l_next; ++ * arch_addr_t becomes integral type. */ ++ addr = (arch_addr_t)(uintptr_t)rlm.l_next; + if (rlm.l_name == 0) { + debug(2, "Name of mapped library is NULL"); + return; +@@ -474,8 +474,8 @@ crawl_linkmap(struct Process *proc, struct lt_r_debug_64 *dbg) + + char lib_name[BUFSIZ]; + /* XXX The double cast should be removed when +- * target_address_t becomes integral type. */ +- umovebytes(proc, (target_address_t)(uintptr_t)rlm.l_name, ++ * arch_addr_t becomes integral type. */ ++ umovebytes(proc, (arch_addr_t)(uintptr_t)rlm.l_name, + lib_name, sizeof(lib_name)); + + if (*lib_name == '\0') { +@@ -512,7 +512,7 @@ crawl_linkmap(struct Process *proc, struct lt_r_debug_64 *dbg) + /* A struct stored at proc->debug. */ + struct debug_struct + { +- target_address_t debug_addr; ++ arch_addr_t debug_addr; + int state; + }; + +@@ -561,7 +561,7 @@ rdebug_bp_on_hit(struct breakpoint *bp, struct Process *proc) + } + + int +-linkmap_init(struct Process *proc, target_address_t dyn_addr) ++linkmap_init(struct Process *proc, arch_addr_t dyn_addr) + { + debug(DEBUG_FUNCTION, "linkmap_init()"); + +@@ -590,8 +590,8 @@ linkmap_init(struct Process *proc, target_address_t dyn_addr) + } + + /* XXX The double cast should be removed when +- * target_address_t becomes integral type. */ +- target_address_t addr = (target_address_t)(uintptr_t)rdbg.r_brk; ++ * arch_addr_t becomes integral type. */ ++ arch_addr_t addr = (arch_addr_t)(uintptr_t)rdbg.r_brk; + if (arch_translate_address_dyn(proc, addr, &addr) < 0) + goto fail; + +@@ -634,8 +634,8 @@ auxv_fetcher(struct Process *proc))(int, + + int + process_get_entry(struct Process *proc, +- target_address_t *entryp, +- target_address_t *interp_biasp) ++ arch_addr_t *entryp, ++ arch_addr_t *interp_biasp) + { + PROC_PID_FILE(fn, "/proc/%d/auxv", proc->pid); + int fd = open(fn, O_RDONLY); +@@ -648,8 +648,8 @@ process_get_entry(struct Process *proc, + return fd == -1 ? -1 : 0; + } + +- target_address_t at_entry = 0; +- target_address_t at_bias = 0; ++ arch_addr_t at_entry = 0; ++ arch_addr_t at_bias = 0; + while (1) { + Elf64_auxv_t entry; + if (auxv_fetcher(proc)(fd, &entry) < 0) +@@ -658,15 +658,15 @@ process_get_entry(struct Process *proc, + switch (entry.a_type) { + case AT_BASE: + /* XXX The double cast should be removed when +- * target_address_t becomes integral type. */ +- at_bias = (target_address_t) ++ * arch_addr_t becomes integral type. */ ++ at_bias = (arch_addr_t) + (uintptr_t)entry.a_un.a_val; + continue; + + case AT_ENTRY: + /* XXX The double cast should be removed when +- * target_address_t becomes integral type. */ +- at_entry = (target_address_t) ++ * arch_addr_t becomes integral type. */ ++ at_entry = (arch_addr_t) + (uintptr_t)entry.a_un.a_val; + default: + continue; +diff --git a/sysdeps/linux-gnu/s390/Makefile.am b/sysdeps/linux-gnu/s390/Makefile.am +index 19e447f..0235d66 100644 +--- a/sysdeps/linux-gnu/s390/Makefile.am ++++ b/sysdeps/linux-gnu/s390/Makefile.am +@@ -4,7 +4,8 @@ noinst_LTLIBRARIES = \ + ___libcpu_la_SOURCES = \ + plt.c \ + regs.c \ +- trace.c ++ trace.c \ ++ fetch.c + + noinst_HEADERS = \ + arch.h \ +diff --git a/sysdeps/linux-gnu/s390/arch.h b/sysdeps/linux-gnu/s390/arch.h +index 6597355..0d412dc 100644 +--- a/sysdeps/linux-gnu/s390/arch.h ++++ b/sysdeps/linux-gnu/s390/arch.h +@@ -22,18 +22,14 @@ + #define BREAKPOINT_LENGTH 2 + #define DECR_PC_AFTER_BREAK 2 + #define ARCH_ENDIAN_BIG ++#define ARCH_HAVE_FETCH_ARG ++#define ARCH_HAVE_SIZEOF ++#define ARCH_HAVE_ALIGNOF + +-#ifdef __s390x__ +-#define LT_ELFCLASS ELFCLASS64 +-#define LT_ELF_MACHINE EM_S390 +-#define LT_ELFCLASS2 ELFCLASS32 +-#define LT_ELF_MACHINE2 EM_S390 +- +-/* __NR_fork, __NR_clone, __NR_clone2, __NR_vfork and __NR_execve +- from asm-s390/unistd.h. */ +-#define FORK_EXEC_SYSCALLS , { 2, 120, -1, 190, 11 } +- +-#else + #define LT_ELFCLASS ELFCLASS32 + #define LT_ELF_MACHINE EM_S390 ++ ++#ifdef __s390x__ ++#define LT_ELFCLASS2 ELFCLASS64 ++#define LT_ELF_MACHINE2 EM_S390 + #endif +diff --git a/sysdeps/linux-gnu/s390/fetch.c b/sysdeps/linux-gnu/s390/fetch.c +new file mode 100644 +index 0000000..5d26b35 +--- /dev/null ++++ b/sysdeps/linux-gnu/s390/fetch.c +@@ -0,0 +1,316 @@ ++/* ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "backend.h" ++#include "fetch.h" ++#include "type.h" ++#include "proc.h" ++#include "value.h" ++ ++struct fetch_context { ++ struct user_regs_struct regs; ++ arch_addr_t stack_pointer; ++ int greg; ++ int freg; ++}; ++ ++static int ++s390x(struct fetch_context *ctx) ++{ ++ /* +--------+--------+--------+ ++ * | PSW.31 | PSW.32 | mode | ++ * +--------+--------+--------+ ++ * | 0 | 0 | 24-bit | Not supported in Linux ++ * | 0 | 1 | 31-bit | s390 compatible mode ++ * | 1 | 1 | 64-bit | z/Architecture, "s390x" ++ * +--------+--------+--------+ ++ * (Note: The leftmost bit is PSW.0, rightmost PSW.63.) ++ */ ++ ++#ifdef __s390x__ ++ if ((ctx->regs.psw.mask & 0x180000000UL) == 0x180000000UL) ++ return 1; ++#endif ++ return 0; ++} ++ ++static int ++fp_equivalent(struct arg_type_info *info) ++{ ++ switch (info->type) { ++ case ARGTYPE_VOID: ++ case ARGTYPE_INT: ++ case ARGTYPE_UINT: ++ case ARGTYPE_LONG: ++ case ARGTYPE_ULONG: ++ case ARGTYPE_CHAR: ++ case ARGTYPE_SHORT: ++ case ARGTYPE_USHORT: ++ case ARGTYPE_ARRAY: ++ case ARGTYPE_POINTER: ++ return 0; ++ ++ case ARGTYPE_FLOAT: ++ case ARGTYPE_DOUBLE: ++ return 1; ++ ++ case ARGTYPE_STRUCT: ++ if (type_struct_size(info) != 1) ++ return 0; ++ return fp_equivalent(type_element(info, 0)); ++ } ++ assert(info->type != info->type); ++ abort(); ++} ++ ++static int ++fetch_register_banks(struct Process *proc, struct fetch_context *ctx) ++{ ++ ptrace_area parea; ++ parea.len = sizeof(ctx->regs); ++ parea.process_addr = (uintptr_t)&ctx->regs; ++ parea.kernel_addr = 0; ++ if (ptrace(PTRACE_PEEKUSR_AREA, proc->pid, &parea, NULL) < 0) { ++ fprintf(stderr, "fetch_register_banks GPR: %s\n", ++ strerror(errno)); ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++fetch_context_init(struct Process *proc, struct fetch_context *context) ++{ ++ context->greg = 2; ++ context->freg = 0; ++ return fetch_register_banks(proc, context); ++} ++ ++struct fetch_context * ++arch_fetch_arg_init(enum tof type, struct Process *proc, ++ struct arg_type_info *ret_info) ++{ ++ struct fetch_context *context = malloc(sizeof(*context)); ++ if (context == NULL ++ || fetch_context_init(proc, context) < 0) { ++ fprintf(stderr, "arch_fetch_arg_init: %s\n", ++ strerror(errno)); ++ free(context); ++ return NULL; ++ } ++ ++ context->stack_pointer = get_stack_pointer(proc) ++ + (s390x(context) ? 160 : 96); ++ if (ret_info->type == ARGTYPE_STRUCT) ++ ++context->greg; ++ ++ return context; ++} ++ ++struct fetch_context * ++arch_fetch_arg_clone(struct Process *proc, ++ struct fetch_context *context) ++{ ++ struct fetch_context *clone = malloc(sizeof(*context)); ++ if (clone == NULL) ++ return NULL; ++ *clone = *context; ++ return clone; ++} ++ ++static int ++allocate_stack_slot(struct fetch_context *ctx, struct Process *proc, ++ struct arg_type_info *info, struct value *valuep, ++ size_t sz) ++{ ++ /* Note: here we shouldn't see large composite types, those ++ * are passed by reference, which is handled below. Here we ++ * only deal with integers, floats, small structs, etc. */ ++ ++ size_t a; ++ if (s390x(ctx)) { ++ assert(sz <= 8); ++ a = 8; ++ } else { ++ /* Note: double is 8 bytes. */ ++ assert(sz <= 8); ++ a = 4; ++ } ++ ++ size_t off = sz < a ? a - sz : 0; ++ ++ valuep->where = VAL_LOC_INFERIOR; ++ valuep->u.address = ctx->stack_pointer + off; ++ ++ ctx->stack_pointer += sz > a ? sz : a; ++ return 0; ++} ++ ++static void ++copy_gpr(struct fetch_context *ctx, struct value *valuep, int regno) ++{ ++ value_set_word(valuep, ctx->regs.gprs[regno]); ++} ++ ++static int ++allocate_gpr(struct fetch_context *ctx, struct Process *proc, ++ struct arg_type_info *info, struct value *valuep, ++ size_t sz) ++{ ++ if (ctx->greg > 6) ++ return allocate_stack_slot(ctx, proc, info, valuep, sz); ++ ++ copy_gpr(ctx, valuep, ctx->greg++); ++ return 0; ++} ++ ++static int ++allocate_gpr_pair(struct fetch_context *ctx, struct Process *proc, ++ struct arg_type_info *info, struct value *valuep, ++ size_t sz) ++{ ++ assert(!s390x(ctx)); ++ assert(sz <= 8); ++ ++ if (ctx->greg > 5) { ++ ctx->greg = 7; ++ return allocate_stack_slot(ctx, proc, info, valuep, sz); ++ } ++ ++ if (value_reserve(valuep, sz) == NULL) ++ return -1; ++ ++ unsigned char *ptr = value_get_raw_data(valuep); ++ union { ++ struct { ++ uint32_t a; ++ uint32_t b; ++ }; ++ unsigned char buf[8]; ++ } u; ++ u.a = ctx->regs.gprs[ctx->greg++]; ++ u.b = ctx->regs.gprs[ctx->greg++]; ++ memcpy(ptr, u.buf, sz); ++ ++ return 0; ++} ++ ++static int ++allocate_fpr(struct fetch_context *ctx, struct Process *proc, ++ struct arg_type_info *info, struct value *valuep, ++ size_t sz) ++{ ++ int pool = s390x(ctx) ? 6 : 2; ++ ++ if (ctx->freg > pool) ++ return allocate_stack_slot(ctx, proc, info, valuep, sz); ++ ++ if (value_reserve(valuep, sz) == NULL) ++ return -1; ++ ++ memcpy(value_get_raw_data(valuep), ++ &ctx->regs.fp_regs.fprs[ctx->freg], sz); ++ ctx->freg += 2; ++ ++ return 0; ++} ++ ++int ++arch_fetch_arg_next(struct fetch_context *ctx, enum tof type, ++ struct Process *proc, ++ struct arg_type_info *info, struct value *valuep) ++{ ++ size_t sz = type_sizeof(proc, info); ++ if (sz == (size_t)-1) ++ return -1; ++ ++ switch (info->type) { ++ case ARGTYPE_VOID: ++ value_set_word(valuep, 0); ++ return 0; ++ ++ case ARGTYPE_STRUCT: ++ if (fp_equivalent(info)) ++ /* fall through */ ++ case ARGTYPE_FLOAT: ++ case ARGTYPE_DOUBLE: ++ return allocate_fpr(ctx, proc, info, valuep, sz); ++ ++ /* Structures<4 bytes on s390 and structures<8 bytes ++ * on s390x are passed in register. On s390, long ++ * long and structures<8 bytes are passed in two ++ * consecutive registers (if two are available). */ ++ ++ if (sz <= (s390x(ctx) ? 8 : 4)) ++ return allocate_gpr(ctx, proc, info, valuep, sz); ++ else if (sz <= 8) ++ return allocate_gpr_pair(ctx, proc, info, valuep, sz); ++ ++ /* fall through */ ++ ++ case ARGTYPE_ARRAY: ++ if (value_pass_by_reference(valuep) < 0) ++ return -1; ++ /* fall through */ ++ ++ case ARGTYPE_INT: ++ case ARGTYPE_UINT: ++ case ARGTYPE_LONG: ++ case ARGTYPE_ULONG: ++ case ARGTYPE_CHAR: ++ case ARGTYPE_SHORT: ++ case ARGTYPE_USHORT: ++ case ARGTYPE_POINTER: ++ return allocate_gpr(ctx, proc, info, valuep, sz); ++ } ++ return -1; ++} ++ ++int ++arch_fetch_retval(struct fetch_context *ctx, enum tof type, ++ struct Process *proc, struct arg_type_info *info, ++ struct value *valuep) ++{ ++ if (info->type == ARGTYPE_STRUCT) { ++ if (value_pass_by_reference(valuep) < 0) ++ return -1; ++ copy_gpr(ctx, valuep, 2); ++ return 0; ++ } ++ ++ if (fetch_context_init(proc, ctx) < 0) ++ return -1; ++ return arch_fetch_arg_next(ctx, type, proc, info, valuep); ++} ++ ++void ++arch_fetch_arg_done(struct fetch_context *context) ++{ ++ free(context); ++} +diff --git a/sysdeps/linux-gnu/s390/plt.c b/sysdeps/linux-gnu/s390/plt.c +index 754d270..cd6454e 100644 +--- a/sysdeps/linux-gnu/s390/plt.c ++++ b/sysdeps/linux-gnu/s390/plt.c +@@ -1,6 +1,7 @@ + #include + #include "proc.h" + #include "common.h" ++#include "library.h" + + GElf_Addr + arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { +diff --git a/sysdeps/linux-gnu/s390/trace.c b/sysdeps/linux-gnu/s390/trace.c +index 3381ccc..4f6eb8d 100644 +--- a/sysdeps/linux-gnu/s390/trace.c ++++ b/sysdeps/linux-gnu/s390/trace.c +@@ -1,24 +1,38 @@ + /* +-** S390 specific part of trace.c +-** +-** Other routines are in ../trace.c and need to be combined +-** at link time with this code. +-** +-** Copyright (C) 2001,2005 IBM Corp. +-*/ ++ * This file is part of ltrace. ++ * Copyright (C) 2012 Petr Machata, Red Hat Inc. ++ * Copyright (C) 2001,2005 IBM Corp. ++ * ++ * 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 "config.h" + +-#include +-#include ++#include ++#include + #include + #include ++#include ++#include + #include +-#include +-#include ++#include + +-#include "proc.h" + #include "common.h" ++#include "proc.h" ++#include "type.h" + + #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) + # define PTRACE_PEEKUSER PTRACE_PEEKUSR +@@ -160,44 +174,82 @@ syscall_p(Process *proc, int status, int *sysnum) { + return 0; + } + +-long +-gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info) ++size_t ++arch_type_sizeof(struct Process *proc, struct arg_type_info *info) + { +- long ret; ++ if (proc == NULL) ++ return (size_t)-2; ++ ++ switch (info->type) { ++ case ARGTYPE_VOID: ++ return 0; ++ ++ case ARGTYPE_CHAR: ++ return 1; ++ ++ case ARGTYPE_SHORT: ++ case ARGTYPE_USHORT: ++ return 2; ++ ++ case ARGTYPE_INT: ++ case ARGTYPE_UINT: ++ return 4; ++ ++ case ARGTYPE_LONG: ++ case ARGTYPE_ULONG: ++ case ARGTYPE_POINTER: ++ return proc->e_class == ELFCLASS64 ? 8 : 4; ++ ++ case ARGTYPE_FLOAT: ++ return 4; ++ case ARGTYPE_DOUBLE: ++ return 8; ++ ++ case ARGTYPE_ARRAY: ++ case ARGTYPE_STRUCT: ++ /* Use default value. */ ++ return (size_t)-2; ++ } ++ assert(info->type != info->type); ++ abort(); ++} + +- switch (arg_num) { +- case -1: /* return value */ +- ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR2, 0); +- break; +- case 0: +- ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_ORIGGPR2, 0); +- break; +- case 1: +- ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR3, 0); +- break; +- case 2: +- ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR4, 0); +- break; +- case 3: +- ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR5, 0); +- break; +- case 4: +- ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR6, 0); ++size_t ++arch_type_alignof(struct Process *proc, struct arg_type_info *info) ++{ ++ if (proc == NULL) ++ return (size_t)-2; ++ ++ switch (info->type) { ++ case ARGTYPE_VOID: ++ assert(info->type != ARGTYPE_VOID); + break; +- default: +- /*Rest of the params saved in stack */ +- if (arg_num >= 5) { +- ret = ptrace(PTRACE_PEEKUSER, proc->pid, +- proc->stack_pointer + 96 + +- 4 * (arg_num - 5), 0); +- } else { +- fprintf(stderr, "gimme_arg called with wrong arguments\n"); +- exit(2); +- } ++ ++ case ARGTYPE_CHAR: ++ return 1; ++ ++ case ARGTYPE_SHORT: ++ case ARGTYPE_USHORT: ++ return 2; ++ ++ case ARGTYPE_INT: ++ case ARGTYPE_UINT: ++ return 4; ++ ++ case ARGTYPE_LONG: ++ case ARGTYPE_ULONG: ++ case ARGTYPE_POINTER: ++ return proc->e_class == ELFCLASS64 ? 8 : 4; ++ ++ case ARGTYPE_FLOAT: ++ return 4; ++ case ARGTYPE_DOUBLE: ++ return 8; ++ ++ case ARGTYPE_ARRAY: ++ case ARGTYPE_STRUCT: ++ /* Use default value. */ ++ return (size_t)-2; + } +-#ifdef __s390x__ +- if (proc->mask_32bit) +- ret &= 0xffffffff; +-#endif +- return ret; ++ abort(); + } +diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c +index cef8e3d..0829bdb 100644 +--- a/sysdeps/linux-gnu/trace.c ++++ b/sysdeps/linux-gnu/trace.c +@@ -782,7 +782,7 @@ process_stopping_on_event(struct event_handler *super, Event *event) + * reason for the re-enablement. In that case + * handle it. */ + if (event->type == EVENT_BREAKPOINT) { +- target_address_t ip ++ arch_addr_t ip + = get_instruction_pointer(task); + struct breakpoint *other + = address2bpstruct(leader, ip); +diff --git a/sysdeps/linux-gnu/x86/fetch.c b/sysdeps/linux-gnu/x86/fetch.c +index 64f57f3..8df900e 100644 +--- a/sysdeps/linux-gnu/x86/fetch.c ++++ b/sysdeps/linux-gnu/x86/fetch.c +@@ -592,14 +592,14 @@ arch_fetch_retval_32(struct fetch_context *context, enum tof type, + abort(); + } + +-static target_address_t ++static arch_addr_t + fetch_stack_pointer(struct fetch_context *context) + { +- target_address_t sp; ++ arch_addr_t sp; + #ifdef __x86_64__ +- sp = (target_address_t)context->iregs.rsp; ++ sp = (arch_addr_t)context->iregs.rsp; + #else +- sp = (target_address_t)context->iregs.esp; ++ sp = (arch_addr_t)context->iregs.esp; + #endif + return sp; + } +diff --git a/sysdeps/linux-gnu/x86/regs.c b/sysdeps/linux-gnu/x86/regs.c +index 477abca..ca6470b 100644 +--- a/sysdeps/linux-gnu/x86/regs.c ++++ b/sysdeps/linux-gnu/x86/regs.c +@@ -47,12 +47,12 @@ + # define XSP (4 * UESP) + #endif + +-static target_address_t +-conv_32(target_address_t val) ++static arch_addr_t ++conv_32(arch_addr_t val) + { +- /* XXX Drop the multiple double casts when target_address_t ++ /* XXX Drop the multiple double casts when arch_addr_t + * becomes integral. */ +- return (target_address_t)(uintptr_t)(uint32_t)(uintptr_t)val; ++ return (arch_addr_t)(uintptr_t)(uint32_t)(uintptr_t)val; + } + + void * +@@ -65,7 +65,7 @@ get_instruction_pointer(struct Process *proc) + } + + void +-set_instruction_pointer(struct Process *proc, target_address_t addr) ++set_instruction_pointer(struct Process *proc, arch_addr_t addr) + { + if (proc->e_machine == EM_386) + addr = conv_32(addr); +@@ -82,9 +82,9 @@ get_stack_pointer(struct Process *proc) + return NULL; + } + +- /* XXX Drop the multiple double casts when target_address_t ++ /* XXX Drop the multiple double casts when arch_addr_t + * becomes integral. */ +- target_address_t ret = (target_address_t)(uintptr_t)sp; ++ arch_addr_t ret = (arch_addr_t)(uintptr_t)sp; + if (proc->e_machine == EM_386) + ret = conv_32(ret); + return ret; +@@ -100,9 +100,9 @@ get_return_addr(struct Process *proc, void *sp) + return NULL; + } + +- /* XXX Drop the multiple double casts when target_address_t ++ /* XXX Drop the multiple double casts when arch_addr_t + * becomes integral. */ +- target_address_t ret = (target_address_t)(uintptr_t)a; ++ arch_addr_t ret = (arch_addr_t)(uintptr_t)a; + if (proc->e_machine == EM_386) + ret = conv_32(ret); + return ret; +diff --git a/sysdeps/sysdep.h b/sysdeps/sysdep.h +index 96b3857..70a4fa7 100644 +--- a/sysdeps/sysdep.h ++++ b/sysdeps/sysdep.h +@@ -28,4 +28,13 @@ struct arch_process_data { + }; + #endif + ++#ifndef ARCH_HAVE_ADDRESS_TYPES ++/* We should in general be able to trace 64-bit processes with 32-bit ++ * ltrace. (At least PPC has several PTRACE requests related to ++ * tracing 64-on-32, so presumably it should be possible.) But ltrace ++ * is currently hopelessly infested with using void* for host address. ++ * So keep with it, for now. */ ++typedef void *arch_addr_t; ++#endif ++ + #endif /* LTRACE_SYSDEP_H */ +diff --git a/testsuite/ltrace.main/parameters-lib.c b/testsuite/ltrace.main/parameters-lib.c +index f9a869d..27fe569 100644 +--- a/testsuite/ltrace.main/parameters-lib.c ++++ b/testsuite/ltrace.main/parameters-lib.c +@@ -241,3 +241,63 @@ void + func_charp_string(char *p) + { + } ++ ++struct dbl_eqv1 { double d; }; ++struct dbl_eqv2 { struct dbl_eqv1 d; }; ++struct dbl_eqv3 { struct dbl_eqv2 d; }; ++struct dbl_eqv4 { struct dbl_eqv3 d; }; ++ ++struct flt_eqv1 { float d; }; ++struct flt_eqv2 { struct flt_eqv1 d; }; ++struct flt_eqv3 { struct flt_eqv2 d; }; ++struct flt_eqv4 { struct flt_eqv3 d; }; ++ ++struct dbl_eqv1 ++func_dbl_eqv(struct dbl_eqv1 a, struct dbl_eqv2 b, ++ struct dbl_eqv3 c, struct dbl_eqv4 d) ++{ ++ return (struct dbl_eqv1){ a.d + b.d.d + c.d.d.d + d.d.d.d.d }; ++} ++ ++struct flt_eqv1 ++func_flt_eqv(struct flt_eqv1 a, struct flt_eqv2 b, ++ struct flt_eqv3 c, struct flt_eqv4 d) ++{ ++ return (struct flt_eqv1){ a.d + b.d.d + c.d.d.d + d.d.d.d.d }; ++} ++ ++struct struct_empty {}; ++struct struct_size1 { char a; }; ++struct struct_size2 { short a; }; ++struct struct_size4 { int a; }; ++struct struct_size8 { int a; int b; }; ++ ++struct struct_empty ++func_struct_empty(struct struct_empty e) ++{ ++ return e; ++} ++ ++struct struct_size1 ++func_struct_size1(struct struct_size1 e) ++{ ++ return e; ++} ++ ++struct struct_size2 ++func_struct_size2(struct struct_size2 e) ++{ ++ return e; ++} ++ ++struct struct_size4 ++func_struct_size4(struct struct_size4 e) ++{ ++ return e; ++} ++ ++struct struct_size8 ++func_struct_size8(struct struct_size8 e) ++{ ++ return e; ++} +diff --git a/testsuite/ltrace.main/parameters.c b/testsuite/ltrace.main/parameters.c +index e8207fe..6318e60 100644 +--- a/testsuite/ltrace.main/parameters.c ++++ b/testsuite/ltrace.main/parameters.c +@@ -218,5 +218,49 @@ main () + void func_charp_string(char *p); + func_charp_string("null-terminated string"); + ++ struct dbl_eqv1 { double d; }; ++ struct dbl_eqv2 { struct dbl_eqv1 d; }; ++ struct dbl_eqv3 { struct dbl_eqv2 d; }; ++ struct dbl_eqv4 { struct dbl_eqv3 d; }; ++ ++ struct flt_eqv1 { float d; }; ++ struct flt_eqv2 { struct flt_eqv1 d; }; ++ struct flt_eqv3 { struct flt_eqv2 d; }; ++ struct flt_eqv4 { struct flt_eqv3 d; }; ++ ++ struct dbl_eqv1 func_dbl_eqv(struct dbl_eqv1 a, struct dbl_eqv2 b, ++ struct dbl_eqv3 c, struct dbl_eqv4 d); ++ func_dbl_eqv((struct dbl_eqv1){ 2.5 }, ++ (struct dbl_eqv2){ { 1.5 } }, ++ (struct dbl_eqv3){ { { 0.5 } } }, ++ (struct dbl_eqv4){ { { { -0.5 } } } }); ++ ++ struct flt_eqv1 func_flt_eqv(struct flt_eqv1 a, struct flt_eqv2 b, ++ struct flt_eqv3 c, struct flt_eqv4 d); ++ func_flt_eqv((struct flt_eqv1){ 2.5 }, ++ (struct flt_eqv2){ { 1.5 } }, ++ (struct flt_eqv3){ { { 0.5 } } }, ++ (struct flt_eqv4){ { { { -0.5 } } } }); ++ ++ struct struct_empty {}; ++ struct struct_empty func_struct_empty(struct struct_empty e); ++ func_struct_empty((struct struct_empty) {}); ++ ++ struct struct_size1 { char a; }; ++ struct struct_size1 func_struct_size1(struct struct_size1 e); ++ func_struct_size1((struct struct_size1){ '5' }); ++ ++ struct struct_size2 { short a; }; ++ struct struct_size2 func_struct_size2(struct struct_size2 e); ++ func_struct_size2((struct struct_size2){ 5 }); ++ ++ struct struct_size4 { int a; }; ++ struct struct_size4 func_struct_size4(struct struct_size4 e); ++ func_struct_size4((struct struct_size4){ 5 }); ++ ++ struct struct_size8 { int a; int b; }; ++ struct struct_size8 func_struct_size8(struct struct_size8 e); ++ func_struct_size8((struct struct_size8){ 5, 6 }); ++ + return 0; + } +diff --git a/testsuite/ltrace.main/parameters.conf b/testsuite/ltrace.main/parameters.conf +index 9e0c967..ea1c55d 100644 +--- a/testsuite/ltrace.main/parameters.conf ++++ b/testsuite/ltrace.main/parameters.conf +@@ -29,3 +29,10 @@ void func_hide(int, hide(int), hide(int), int, hide(int), int); + array(enum[long](A,B), 4) *func_short_enums(array(enum[short](A,B), 4)); + enum[long](A=-1) func_negative_enum(enum[short](A=-1), enum[ushort](A=-1), enum[int](A=-1), enum[uint](A=-1), enum[long](A=-1), enum[ulong](A=-1)); + void func_charp_string(string(char *)); ++struct(double) func_dbl_eqv(struct(double), struct(struct(double)), struct(struct(struct(double))), struct(struct(struct(struct(double))))); ++struct(float) func_flt_eqv(struct(float), struct(struct(float)), struct(struct(struct(float))), struct(struct(struct(struct(float))))); ++struct() func_struct_empty(struct()); ++struct(char) func_struct_size1(struct(char)); ++struct(short) func_struct_size2(struct(short)); ++struct(int) func_struct_size4(struct(int)); ++struct(int,int) func_struct_size8(struct(int,int)); +diff --git a/testsuite/ltrace.main/parameters.exp b/testsuite/ltrace.main/parameters.exp +index 8403721..b62315d 100644 +--- a/testsuite/ltrace.main/parameters.exp ++++ b/testsuite/ltrace.main/parameters.exp +@@ -135,3 +135,24 @@ ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1 + + set pattern "func_charp_string(\\\"null-terminated string\\\")" + ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1 ++ ++set pattern "func_dbl_eqv({ 2.500* }, { { 1.50* } }, { { { 0.50* } } }, { { { { -0.50* } } } }).*= { 4.00* }" ++ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1 ++ ++set pattern "func_flt_eqv({ 2.500* }, { { 1.50* } }, { { { 0.50* } } }, { { { { -0.50* } } } }).*= { 4.00* }" ++ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1 ++ ++set pattern "func_struct_empty({ *}).*= { *}" ++ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1 ++ ++set pattern "func_struct_size1({ '5' }).*= { '5' }" ++ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1 ++ ++set pattern "func_struct_size2({ 5 }).*= { 5 }" ++ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1 ++ ++set pattern "func_struct_size4({ 5 }).*= { 5 }" ++ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1 ++ ++set pattern "func_struct_size8({ 5, 6 }).*= { 5, 6 }" ++ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1 diff --git a/ltrace.spec b/ltrace.spec index 4ec51b2..b4cd0d8 100644 --- a/ltrace.spec +++ b/ltrace.spec @@ -1,7 +1,7 @@ Summary: Tracks runtime library calls from dynamically linked executables Name: ltrace Version: 0.6.0 -Release: 14%{?dist} +Release: 15%{?dist} URL: http://ltrace.alioth.debian.org/ License: GPLv2+ Group: Development/Debuggers @@ -34,6 +34,7 @@ Patch18: ltrace-0.6.0-libs.patch Patch19: ltrace-0.6.0-libs-fixes-1.patch Patch20: ltrace-0.6.0-dash-n.patch Patch21: ltrace-0.6.0-abi.patch +Patch22: ltrace-0.6.0-abi-s390.patch %description Ltrace is a debugging program which runs a specified command until the @@ -66,6 +67,7 @@ execution of processes. %patch19 -p1 %patch20 -p1 %patch21 -p1 +%patch22 -p1 %build # This ugly hack is necessary to build and link files for correct @@ -93,6 +95,10 @@ echo ====================TESTING END===================== %config(noreplace) %{_sysconfdir}/ltrace.conf %changelog +* Thu May 31 2012 Petr Machata - 0.6.0-15 +- Add upstream patches for parameter passing. Apart from a couple of + fixes, this brings in s390 support (ltrace-0.6.0-abi-s390.patch) + * Fri May 18 2012 Petr Machata - 0.6.0-14 - Add upstream patch that improves parameter passing support (the upstream "revamp" branch) (ltrace-0.6.0-abi.patch)