summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/coredump/_UCD_access_reg_linux.c24
-rw-r--r--src/coredump/_UCD_create.c9
-rw-r--r--src/coredump/_UCD_get_threadinfo_prstatus.c8
-rw-r--r--src/coredump/_UCD_internal.h12
-rw-r--r--src/coredump/_UPT_access_fpreg.c21
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
}