diff options
-rw-r--r-- | src/coredump/_UCD_access_reg_linux.c | 24 | ||||
-rw-r--r-- | src/coredump/_UCD_create.c | 9 | ||||
-rw-r--r-- | src/coredump/_UCD_get_threadinfo_prstatus.c | 8 | ||||
-rw-r--r-- | src/coredump/_UCD_internal.h | 12 | ||||
-rw-r--r-- | src/coredump/_UPT_access_fpreg.c | 21 |
5 files changed, 64 insertions, 10 deletions
diff --git a/src/coredump/_UCD_access_reg_linux.c b/src/coredump/_UCD_access_reg_linux.c index 99c28a4c..6ec50bac 100644 --- a/src/coredump/_UCD_access_reg_linux.c +++ b/src/coredump/_UCD_access_reg_linux.c @@ -54,9 +54,6 @@ _UCD_access_reg (unw_addr_space_t as, #elif defined(UNW_TARGET_TILEGX) if (regnum > UNW_TILEGX_CFA) goto badreg; -#elif defined(UNW_TARGET_S390X) - if (regnum > UNW_S390X_R15) - goto badreg; #elif defined(UNW_TARGET_IA64) || defined(UNW_TARGET_HPPA) || defined(UNW_TARGET_PPC32) || defined(UNW_TARGET_PPC64) if (regnum >= ARRAY_SIZE(ui->prstatus->pr_reg)) goto badreg; @@ -138,6 +135,27 @@ _UCD_access_reg (unw_addr_space_t as, [UNW_MIPS_R31] = EF_REG31, [UNW_MIPS_PC] = EF_CP0_EPC, }; +#elif defined(UNW_TARGET_S390X) + static const uint8_t remap_regs[] = + { + [UNW_S390X_IP] = offsetof(struct user_regs_struct, psw.addr) / sizeof(long), + [UNW_S390X_R0] = offsetof(struct user_regs_struct, gprs[0]) / sizeof(long), + [UNW_S390X_R1] = offsetof(struct user_regs_struct, gprs[1]) / sizeof(long), + [UNW_S390X_R2] = offsetof(struct user_regs_struct, gprs[2]) / sizeof(long), + [UNW_S390X_R3] = offsetof(struct user_regs_struct, gprs[3]) / sizeof(long), + [UNW_S390X_R4] = offsetof(struct user_regs_struct, gprs[4]) / sizeof(long), + [UNW_S390X_R5] = offsetof(struct user_regs_struct, gprs[5]) / sizeof(long), + [UNW_S390X_R6] = offsetof(struct user_regs_struct, gprs[6]) / sizeof(long), + [UNW_S390X_R7] = offsetof(struct user_regs_struct, gprs[7]) / sizeof(long), + [UNW_S390X_R8] = offsetof(struct user_regs_struct, gprs[8]) / sizeof(long), + [UNW_S390X_R9] = offsetof(struct user_regs_struct, gprs[9]) / sizeof(long), + [UNW_S390X_R10] = offsetof(struct user_regs_struct, gprs[10]) / sizeof(long), + [UNW_S390X_R11] = offsetof(struct user_regs_struct, gprs[11]) / sizeof(long), + [UNW_S390X_R12] = offsetof(struct user_regs_struct, gprs[12]) / sizeof(long), + [UNW_S390X_R13] = offsetof(struct user_regs_struct, gprs[13]) / sizeof(long), + [UNW_S390X_R14] = offsetof(struct user_regs_struct, gprs[14]) / sizeof(long), + [UNW_S390X_R15] = offsetof(struct user_regs_struct, gprs[15]) / sizeof(long), + }; #elif defined(UNW_TARGET_X86) static const uint8_t remap_regs[] = { diff --git a/src/coredump/_UCD_create.c b/src/coredump/_UCD_create.c index 9b4b7fe3..21fd0b92 100644 --- a/src/coredump/_UCD_create.c +++ b/src/coredump/_UCD_create.c @@ -218,7 +218,8 @@ _UCD_create(const char *filename) goto err; } - ui->prstatus = &ui->threads[0]; + ui->prstatus = &ui->threads[0].prstatus; + ui->fpregset = &ui->threads[0].fpregset; return ui; @@ -234,8 +235,10 @@ int _UCD_get_num_threads(struct UCD_info *ui) void _UCD_select_thread(struct UCD_info *ui, int n) { - if (n >= 0 && n < ui->n_threads) - ui->prstatus = &ui->threads[n]; + if (n >= 0 && n < ui->n_threads) { + ui->prstatus = &ui->threads[n].prstatus; + ui->fpregset = &ui->threads[n].fpregset; + } } pid_t _UCD_get_pid(struct UCD_info *ui) diff --git a/src/coredump/_UCD_get_threadinfo_prstatus.c b/src/coredump/_UCD_get_threadinfo_prstatus.c index 45552566..cd03ce36 100644 --- a/src/coredump/_UCD_get_threadinfo_prstatus.c +++ b/src/coredump/_UCD_get_threadinfo_prstatus.c @@ -62,9 +62,13 @@ _save_thread_notes(uint32_t n_namesz, uint32_t n_descsz, uint32_t n_type, char * struct UCD_info *ui = (struct UCD_info *)arg; if (n_type == NT_PRSTATUS) { - memcpy(&ui->threads[ui->n_threads], desc, sizeof(struct PRSTATUS_STRUCT)); + memcpy(&ui->threads[ui->n_threads].prstatus, desc, sizeof(struct PRSTATUS_STRUCT)); ++ui->n_threads; } + if (n_type == NT_FPREGSET) + { + memcpy(&ui->threads[ui->n_threads-1].fpregset, desc, sizeof(elf_fpregset_t)); + } return UNW_ESUCCESS; } @@ -102,7 +106,7 @@ _UCD_get_threadinfo(struct UCD_info *ui, coredump_phdr_t *phdrs, unsigned phdr_s _UCD_elf_visit_notes(segment, segment_size, _count_thread_notes, &thread_count); Debug(2, "found %zu threads\n", thread_count); - size_t new_size = sizeof(struct PRSTATUS_STRUCT) * (ui->n_threads + thread_count); + size_t new_size = sizeof(struct UCD_thread_info) * (ui->n_threads + thread_count); ui->threads = realloc(ui->threads, new_size); if (ui->threads == NULL) { diff --git a/src/coredump/_UCD_internal.h b/src/coredump/_UCD_internal.h index f5150205..e980aa29 100644 --- a/src/coredump/_UCD_internal.h +++ b/src/coredump/_UCD_internal.h @@ -34,6 +34,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifdef HAVE_SYS_PROCFS_H #include <sys/procfs.h> /* struct elf_prstatus */ #endif +#ifdef HAVE_ASM_PTRACE_H +#include <asm/ptrace.h> /* struct user_regs_struct on s390x */ +#endif #include <errno.h> #include <string.h> #include <limits.h> @@ -82,6 +85,12 @@ typedef struct coredump_phdr coredump_phdr_t; #define PRSTATUS_STRUCT non_existent #endif +struct UCD_thread_info + { + struct PRSTATUS_STRUCT prstatus; + elf_fpregset_t fpregset; + }; + struct UCD_info { int big_endian; /* bool */ @@ -91,8 +100,9 @@ struct UCD_info unsigned phdrs_count; void *note_phdr; /* allocated or NULL */ struct PRSTATUS_STRUCT *prstatus; /* points inside note_phdr */ + elf_fpregset_t *fpregset; int n_threads; - struct PRSTATUS_STRUCT *threads; + struct UCD_thread_info *threads; struct elf_dyn_info edi; }; diff --git a/src/coredump/_UPT_access_fpreg.c b/src/coredump/_UPT_access_fpreg.c index 0b8b86ac..a6d0bcea 100644 --- a/src/coredump/_UPT_access_fpreg.c +++ b/src/coredump/_UPT_access_fpreg.c @@ -28,7 +28,26 @@ int _UCD_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, int write, void *arg) { + struct UCD_info *ui UNUSED = arg; + + if (write) + { + Debug(0, "write is not supported\n"); + return -UNW_EINVAL; + } + +#ifdef __s390x__ + if (reg < UNW_S390X_F0 || reg > UNW_S390X_F15) + { + Debug(0, "bad regnum:%d\n", reg); + return -UNW_EINVAL; + } + + *val = ui->fpregset->fprs[reg - UNW_S390X_F0].d; + return 0; +#else print_error (__func__); - print_error (" not implemented\n"); + print_error (" not implemented for this architecture\n"); return -UNW_EINVAL; +#endif } |