LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
 endif
 
+ifeq ($(ARCH),s390)
+  NO_PERF_REGS := 0
+endif
+
 ifeq ($(NO_PERF_REGS),0)
   $(call detected,CONFIG_PERF_REGS)
 endif
 # Disable it on all other architectures in case libdw unwind
 # support is detected in system. Add supported architectures
 # to the check.
-ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc))
+ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc s390))
   NO_LIBDW_DWARF_UNWIND := 1
 endif
 
 
--- /dev/null
+#ifndef ARCH_PERF_REGS_H
+#define ARCH_PERF_REGS_H
+
+#include <stdlib.h>
+#include <linux/types.h>
+#include <../../../../arch/s390/include/uapi/asm/perf_regs.h>
+
+void perf_regs_load(u64 *regs);
+
+#define PERF_REGS_MASK ((1ULL << PERF_REG_S390_MAX) - 1)
+#define PERF_REGS_MAX PERF_REG_S390_MAX
+#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64
+
+#define PERF_REG_IP PERF_REG_S390_PC
+#define PERF_REG_SP PERF_REG_S390_R15
+
+static inline const char *perf_reg_name(int id)
+{
+       switch (id) {
+       case PERF_REG_S390_R0:
+               return "R0";
+       case PERF_REG_S390_R1:
+               return "R1";
+       case PERF_REG_S390_R2:
+               return "R2";
+       case PERF_REG_S390_R3:
+               return "R3";
+       case PERF_REG_S390_R4:
+               return "R4";
+       case PERF_REG_S390_R5:
+               return "R5";
+       case PERF_REG_S390_R6:
+               return "R6";
+       case PERF_REG_S390_R7:
+               return "R7";
+       case PERF_REG_S390_R8:
+               return "R8";
+       case PERF_REG_S390_R9:
+               return "R9";
+       case PERF_REG_S390_R10:
+               return "R10";
+       case PERF_REG_S390_R11:
+               return "R11";
+       case PERF_REG_S390_R12:
+               return "R12";
+       case PERF_REG_S390_R13:
+               return "R13";
+       case PERF_REG_S390_R14:
+               return "R14";
+       case PERF_REG_S390_R15:
+               return "R15";
+       case PERF_REG_S390_MASK:
+               return "MASK";
+       case PERF_REG_S390_PC:
+               return "PC";
+       default:
+               return NULL;
+       }
+
+       return NULL;
+}
+
+#endif /* ARCH_PERF_REGS_H */
 
--- /dev/null
+#include <elfutils/libdwfl.h>
+#include "../../util/unwind-libdw.h"
+#include "../../util/perf_regs.h"
+#include "../../util/event.h"
+
+
+bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
+{
+       struct unwind_info *ui = arg;
+       struct regs_dump *user_regs = &ui->sample->user_regs;
+       Dwarf_Word dwarf_regs[PERF_REG_S390_MAX];
+
+#define REG(r) ({                                              \
+       Dwarf_Word val = 0;                                     \
+       perf_reg_value(&val, user_regs, PERF_REG_S390_##r);     \
+       val;                                                    \
+})
+
+       dwarf_regs[0]  = REG(R0);
+       dwarf_regs[1]  = REG(R1);
+       dwarf_regs[2]  = REG(R2);
+       dwarf_regs[3]  = REG(R3);
+       dwarf_regs[4]  = REG(R4);
+       dwarf_regs[5]  = REG(R5);
+       dwarf_regs[6]  = REG(R6);
+       dwarf_regs[7]  = REG(R7);
+       dwarf_regs[8]  = REG(R8);
+       dwarf_regs[9]  = REG(R9);
+       dwarf_regs[10] = REG(R10);
+       dwarf_regs[11] = REG(R11);
+       dwarf_regs[12] = REG(R12);
+       dwarf_regs[13] = REG(R13);
+       dwarf_regs[14] = REG(R14);
+       dwarf_regs[15] = REG(R15);
+       dwarf_regs[16] = REG(MASK);
+       dwarf_regs[17] = REG(PC);
+
+       dwfl_thread_state_register_pc(thread, dwarf_regs[17]);
+       return dwfl_thread_state_registers(thread, 0, 16, dwarf_regs);
+}