Initial s390-tools-2.0.0 import

This commit is based on the s390-tools-1.39.0 version.

Changes on top of s390-tools-1.39.0:

 - Add MIT license to all source files
 - Add LICENSE file
 - Transform REAMDE to README.md (markdown)
 - Add AUTHORS.md file
 - Add CONTRIBUTING.md file
 - Move changelog from README to CHANGELOG.md file

Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com>
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
This commit is contained in:
Michael Holzheu
2017-08-07 16:13:17 +02:00
commit b627b8d8e1
647 changed files with 168974 additions and 0 deletions
+80
View File
@@ -0,0 +1,80 @@
include ../common.mak
#
# HAVE_FUSE: Allow to build zgetdump without mount support
#
ifeq (${HAVE_FUSE},0)
check_dep_fuse:
else
check_dep_fuse:
$(call check_dep, \
"zgetdump mount support", \
"fuse.h", \
"fuse-devel or libfuse-dev", \
"HAVE_FUSE=0")
endif
#
# HAVE_ZLIB: Allow skip zgetdump build, when no zlib-devel is available
#
ifeq (${HAVE_ZLIB},0)
all:
$(SKIP) HAVE_ZLIB=0
install:
$(SKIP) HAVE_ZLIB=0
else
check_dep_zlib:
$(call check_dep, \
"zgetdump", \
"zlib.h", \
"zlib-devel or libz-dev", \
"HAVE_ZLIB=0")
all: check_dep_fuse check_dep_zlib zgetdump
OBJECTS = zgetdump.o opts.o zg.o \
dfi.o dfi_vmcoreinfo.o \
dfi_lkcd.o dfi_elf.o dfi_s390.o dfi_s390mv.o dfi_s390tape.o \
dfi_kdump.o dfi_devmem.o \
dfo.o dfo_elf.o dfo_s390.o \
df_s390.o \
dt.o dt_s390sv.o dt_s390mv.o dt_scsi.o \
stdout.o
ifeq ("$(HAVE_FUSE)","0")
FUSE_CFLAGS = -DHAVE_FUSE=0 -D_FILE_OFFSET_BITS=64
FUSE_LDLIBS =
else ifneq ($(shell sh -c 'command -v pkg-config'),)
FUSE_CFLAGS = -DHAVE_FUSE=1 $(shell pkg-config --silence-errors --cflags fuse)
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
else
FUSE_CFLAGS = -DHAVE_FUSE=1 -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse
FUSE_LDLIBS = -lfuse
endif
LDLIBS += -lz $(FUSE_LDLIBS)
ALL_CFLAGS += $(FUSE_CFLAGS)
ifneq ("$(HAVE_FUSE)","0")
OBJECTS += zfuse.o
endif
libs = $(rootdir)/libutil/libutil.a
zgetdump: $(OBJECTS) $(libs)
install: all
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man8 $(DESTDIR)$(BINDIR)
$(INSTALL) -m 755 zgetdump $(DESTDIR)$(BINDIR)
$(INSTALL) -m 644 zgetdump.8 $(DESTDIR)$(MANDIR)/man8
clean:
rm -f *.o *~ zgetdump core.*
endif
.PHONY: all install clean check_dep_fuse check_dep_zlib
+117
View File
@@ -0,0 +1,117 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* ELF core dump format definitions
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef DF_ELF_H
#define DF_ELF_H
#include <elf.h>
#include <linux/types.h>
#include "dfo.h"
#include "zg.h"
/*
* S390 CPU timer note (u64)
*/
#ifndef NT_S390_TIMER
#define NT_S390_TIMER 0x301
#endif
/*
* S390 TOD clock comparator note (u64)
*/
#ifndef NT_S390_TODCMP
#define NT_S390_TODCMP 0x302
#endif
/*
* S390 TOD programmable register note (u32)
*/
#ifndef NT_S390_TODPREG
#define NT_S390_TODPREG 0x303
#endif
/*
* S390 control registers note (16 * u32)
*/
#ifndef NT_S390_CTRS
#define NT_S390_CTRS 0x304
#endif
/*
* S390 prefix note (u32)
*/
#ifndef NT_S390_PREFIX
#define NT_S390_PREFIX 0x305
#endif
/*
* S390 vector registers 0-15 upper half note (16 * u64)
*/
#ifndef NT_S390_VXRS_LOW
#define NT_S390_VXRS_LOW 0x309
#endif
/*
* S390 vector registers 16-31 note (16 * u128)
*/
#ifndef NT_S390_VXRS_HIGH
#define NT_S390_VXRS_HIGH 0x30a
#endif
/*
* prstatus ELF Note
*/
struct nt_prstatus_64 {
u8 pad1[32];
u32 pr_pid;
u8 pad2[76];
u64 psw[2];
u64 gprs[16];
u32 acrs[16];
u64 orig_gpr2;
u32 pr_fpvalid;
u8 pad3[4];
} __attribute__ ((packed));
/*
* fpregset ELF Note
*/
struct nt_fpregset_64 {
u32 fpc;
u32 pad;
u64 fprs[16];
} __attribute__ ((packed));
/*
* prpsinfo ELF Note
*/
struct nt_prpsinfo_64 {
char pr_state;
char pr_sname;
char pr_zomb;
char pr_nice;
u64 pr_flag;
u32 pr_uid;
u32 pr_gid;
u32 pr_pid, pr_ppid, pr_pgrp, pr_sid;
char pr_fname[16];
char pr_psargs[80];
};
static inline void df_elf_ensure_s390x(void)
{
#ifndef __s390x__
ERR_EXIT("The ELF dump format is only supported on s390x (64 bit)");
#endif
}
#endif /* DF_ELF_H */
+79
View File
@@ -0,0 +1,79 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* LKCD dump format definitions
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef DF_LKCD_H
#define DF_LKCD_H
#define DF_LKCD_MAGIC 0xa8190173618f23edULL
#define DF_LKCD_MAGIC_ASM 0x733339302d64756dULL
#define DF_LKCD_VERSION 0x8 /* dump version number */
#define DF_LKCD_PANIC_LEN 0x100 /* dump panic string length */
#define DF_LKCD_HDR_SIZE 0x10000 /* Max space for the dump header */
#define DF_LKCD_COMPRESS_NONE 0x0 /* don't compress this dump */
#define DF_LKCD_COMPRESS_GZIP 0x2 /* use GZIP compression */
#define DF_LKCD_DH_RAW 0x1 /* raw pg (no compression) */
#define DF_LKCD_DH_COMPRESSED 0x2 /* pg is compressed */
#define DF_LKCD_DH_END 0x4 /* end marker on a full dump */
#define DF_LKCD_UCP_SIZE (PAGE_SIZE + sizeof(struct df_lkcd_pg_hdr))
/*
* LKCD standard header
*/
struct df_lkcd_hdr {
u64 magic;
u32 version;
u32 hdr_size;
u32 dump_level;
u32 page_size;
u64 mem_size;
u64 mem_start;
u64 mem_end;
u32 num_dump_pgs;
char panic_string[0x100];
u64 time_tv_sec;
u64 time_tv_usec;
char utsname_sysname[65];
char utsname_nodename[65];
char utsname_release[65];
char utsname_version[65];
char utsname_machine[65];
char utsname_domainname[65];
u64 current_task;
u32 dump_compress;
u32 dump_flags;
u32 dump_device;
} __attribute__((packed));
/*
* s390 LKCD asm header
*/
struct df_lkcd_hdr_asm {
u64 magic;
u32 version;
u32 hdr_size;
u16 cpu_cnt;
u16 real_cpu_cnt;
u32 lc_vec[512];
} __attribute__((packed));
/*
* Page header
*/
struct df_lkcd_pg_hdr {
u64 addr; /* Address of dump page */
u32 size; /* Size of dump page */
u32 flags; /* flags (DF_LKCD_COMPRESSED, DF_LKCD_RAW,...) */
} __attribute__((packed));
#endif /* DF_LKCD_H */
+131
View File
@@ -0,0 +1,131 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* S390 dump format common functions
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "zgetdump.h"
/*
* Check, if we can access the lowcore information in the dump
*/
static int check_addr_max(struct df_s390_hdr *hdr, u64 addr_max)
{
unsigned int i, lc_size;
lc_size = dfi_lc_size(df_s390_to_dfi_arch(hdr->arch));
for (i = 0; i < hdr->cpu_cnt; i++) {
if (hdr->lc_vec[i] + lc_size > addr_max)
return -1;
}
return 0;
}
/*
* Convert lowcore information into internal CPU representation
*/
void df_s390_cpu_info_add(struct df_s390_hdr *hdr, u64 addr_max)
{
unsigned int i;
if (hdr->version < 5) {
/* No Prefix registers in header */
hdr->cpu_cnt = 0;
dfi_cpu_info_init(DFI_CPU_CONTENT_NONE);
} else if (check_addr_max(hdr, addr_max) != 0) {
/* Only lowcore pointers available */
dfi_cpu_info_init(DFI_CPU_CONTENT_LC);
} else {
/* All register info available */
dfi_cpu_info_init(DFI_CPU_CONTENT_ALL);
}
for (i = 0; i < hdr->cpu_cnt; i++)
dfi_cpu_add_from_lc(hdr->lc_vec[i]);
}
/*
* Convert s390 TOD clock into timeval structure
*/
static void tod2timeval(struct timeval *xtime, u64 todval)
{
/* adjust todclock to 1970 */
todval -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
todval >>= 12;
xtime->tv_sec = todval / 1000000;
xtime->tv_usec = todval % 1000000;
}
/*
* Convert s390 header information into internal representation
*/
void df_s390_hdr_add(struct df_s390_hdr *hdr)
{
struct timeval timeval;
if (hdr->tod) {
tod2timeval(&timeval, hdr->tod);
dfi_attr_time_set(&timeval);
}
dfi_attr_version_set(hdr->version);
dfi_arch_set(df_s390_to_dfi_arch(hdr->arch));
if (hdr->cpu_id)
dfi_attr_cpu_id_set(hdr->cpu_id);
if (hdr->version >= 3 && hdr->mem_size_real)
dfi_attr_mem_size_real_set(hdr->mem_size_real);
if (hdr->version >= 2 && hdr->build_arch)
dfi_attr_build_arch_set(df_s390_to_dfi_arch(hdr->build_arch));
if (hdr->version >= 5 && hdr->real_cpu_cnt)
dfi_attr_real_cpu_cnt_set(hdr->real_cpu_cnt);
}
/*
* Add end marker information to internal representation
*/
void df_s390_em_add(struct df_s390_em *em)
{
struct timeval timeval;
if (em->tod) {
tod2timeval(&timeval, em->tod);
dfi_attr_time_end_set(&timeval);
}
}
/*
* Verify end marker
*/
int df_s390_em_verify(struct df_s390_em *em, struct df_s390_hdr *hdr)
{
if (strncmp(em->str, DF_S390_EM_STR, strlen(DF_S390_EM_STR)) != 0)
return -EINVAL;
if (hdr->tod > em->tod)
return -EINVAL;
return 0;
}
/*
* Read s390 dump tool from DASD with given block size
*/
void df_s390_dumper_read(struct zg_fh *fh, int blk_size,
struct df_s390_dumper *dumper)
{
int offset = DF_S390_MAGIC_BLK_ECKD * blk_size;
zg_seek(fh, offset, ZG_CHECK);
zg_read(fh, dumper, sizeof(*dumper), ZG_CHECK);
}
+194
View File
@@ -0,0 +1,194 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* S390 dump format common functions
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef DF_S390_H
#define DF_S390_H
#include "dt.h"
#include "zg.h"
#define DF_S390_MAGIC 0xa8190173618f23fdULL
#define DF_S390_HDR_SIZE 0x1000
#define DF_S390_EM_SIZE 16
#define DF_S390_EM_STR "DUMP_END"
#define DF_S390_CPU_MAX 512
#define DF_S390_MAGIC_BLK_ECKD 3
/*
* Architecture of dumped system
*/
enum df_s390_arch {
DF_S390_ARCH_32 = 1,
DF_S390_ARCH_64 = 2,
};
/*
* s390 dump header format
*/
struct df_s390_hdr {
u64 magic; /* 0x000 */
u32 version; /* 0x008 */
u32 hdr_size; /* 0x00c */
u32 dump_level; /* 0x010 */
u32 page_size; /* 0x014 */
u64 mem_size; /* 0x018 */
u64 mem_start; /* 0x020 */
u64 mem_end; /* 0x028 */
u32 num_pages; /* 0x030 */
u32 pad; /* 0x034 */
u64 tod; /* 0x038 */
u64 cpu_id; /* 0x040 */
u32 arch; /* 0x048 */
u32 volnr; /* 0x04c */
u32 build_arch; /* 0x050 */
u64 mem_size_real; /* 0x054 */
u8 mvdump; /* 0x05c */
u16 cpu_cnt; /* 0x05d */
u16 real_cpu_cnt; /* 0x05f */
u8 end_pad1[0x200-0x061]; /* 0x061 */
u64 mvdump_sign; /* 0x200 */
u64 mvdump_zipl_time; /* 0x208 */
u8 end_pad2[0x800-0x210]; /* 0x210 */
u32 lc_vec[DF_S390_CPU_MAX]; /* 0x800 */
} __attribute__((packed));
/*
* End marker: Should be at the end of every valid s390 crash dump.
*/
struct df_s390_em {
char str[8];
u64 tod;
} __attribute__((packed));
/*
* Convert DFI arch to s390 arch
*/
static inline enum df_s390_arch df_s390_from_dfi_arch(enum dfi_arch dfi_arch)
{
return dfi_arch == DFI_ARCH_64 ? DF_S390_ARCH_64 : DF_S390_ARCH_32;
}
/*
* Convert s390 arch to DFI arch
*/
static inline enum dfi_arch df_s390_to_dfi_arch(enum df_s390_arch df_s390_arch)
{
return df_s390_arch == DF_S390_ARCH_64 ? DFI_ARCH_64 : DFI_ARCH_32;
}
/*
* Dump tool structure (version 1)
*/
struct df_s390_dumper_v1 {
char code[0xff7 - 0x8];
u8 force;
u64 mem;
} __attribute__ ((packed));
#define DF_S390_DUMPER_SIZE_V1 0x1000
/*
* Dump tool structure (version 2)
*/
struct df_s390_dumper_v2 {
char code[0x1ff7 - 0x8];
u8 force;
u64 mem;
} __attribute__ ((packed));
#define DF_S390_DUMPER_SIZE_V2 0x2000
/*
* Dump tool structure (version 3 and 4)
*/
struct df_s390_dumper_v3 {
char code[0x2ff7 - 0x8];
u8 force;
u64 mem;
} __attribute__ ((packed));
#define DF_S390_DUMPER_SIZE_V3 0x3000
/*
* Dump tool structure
*/
struct df_s390_dumper {
char magic[7];
u8 version;
union {
struct df_s390_dumper_v1 v1;
struct df_s390_dumper_v2 v2;
struct df_s390_dumper_v3 v3;
} d;
} __attribute__ ((packed));
/*
* Dumper member access helpers
*/
#define df_s390_dumper_magic(dumper) ((dumper).magic)
#define df_s390_dumper_version(dumper) ((dumper).version)
static inline u64 df_s390_dumper_mem(struct df_s390_dumper *dumper)
{
switch (dumper->version) {
case 1:
return dumper->d.v1.mem;
case 2:
return dumper->d.v2.mem;
case 3:
default:
return dumper->d.v3.mem;
}
}
static inline u8 df_s390_dumper_force(struct df_s390_dumper *dumper)
{
switch (dumper->version) {
case 1:
return dumper->d.v1.force;
case 2:
return dumper->d.v2.force;
case 3:
default:
return dumper->d.v3.force;
}
}
static inline unsigned long df_s390_dumper_size(struct df_s390_dumper *dumper)
{
switch (dumper->version) {
case 1:
return 0x1000;
case 2:
return 0x2000;
case 3:
default:
return 0x3000;
}
}
/*
* s390 dump helpers
*/
extern void df_s390_hdr_add(struct df_s390_hdr *hdr);
extern void df_s390_em_add(struct df_s390_em *em);
extern void df_s390_cpu_info_add(struct df_s390_hdr *hdr, u64 addr_max);
extern int df_s390_em_verify(struct df_s390_em *em, struct df_s390_hdr *hdr);
extern void df_s390_dumper_read(struct zg_fh *fh, int32_t blk_size,
struct df_s390_dumper *dumper);
/*
* DASD multi-volume dumper functions
*/
extern int dt_s390mv_init(void);
extern void dt_s390mv_exit(void);
extern void dt_s390mv_info(void);
#endif /* DF_S390_H */
+1141
View File
File diff suppressed because it is too large Load Diff
+283
View File
@@ -0,0 +1,283 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* Generic input dump format functions (DFI - Dump Format Input)
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef DFI_H
#define DFI_H
#include <linux/utsname.h>
#include "lib/util_list.h"
#include "zg.h"
/*
* CPU info functions and definitions
*/
enum dfi_arch {
DFI_ARCH_32 = 0,
DFI_ARCH_64 = 1,
DFI_ARCH_UNKNOWN = 2,
};
struct dfi_lowcore_32 {
u8 pad_0x0000[0x0084 - 0x0000]; /* 0x0000 */
u16 cpu_addr; /* 0x0084 */
u8 pad_0x0086[0x00d4 - 0x0086]; /* 0x0086 */
u32 extended_save_area_addr; /* 0x00d4 */
u32 timer_save_area[2]; /* 0x00d8 */
u32 clock_comp_save_area[2]; /* 0x00e0 */
u32 mcck_interruption_code[2]; /* 0x00e8 */
u8 pad_0x00f0[0x00f4-0x00f0]; /* 0x00f0 */
u32 external_damage_code; /* 0x00f4 */
u32 failing_storage_address; /* 0x00f8 */
u8 pad_0x00fc[0x0100-0x00fc]; /* 0x00fc */
u32 st_status_fixed_logout[2]; /* 0x0100 */
u32 prefixreg_save_area; /* 0x0108 */
u8 pad_0x0110[0x0120-0x010c]; /* 0x010c */
u32 access_regs_save_area[16]; /* 0x0120 */
u32 floating_pt_save_area[8]; /* 0x0160 */
u32 gpregs_save_area[16]; /* 0x0180 */
u32 cregs_save_area[16]; /* 0x01c0 */
u8 pad_0x0200[0x1000 - 0x0200]; /* 0x0200 */
};
struct dfi_lowcore_64 {
u8 pad_0x0000[0x0084 - 0x0000]; /* 0x0000 */
u16 cpu_addr; /* 0x0084 */
u8 pad_0x0086[0x11b0 - 0x0086]; /* 0x0086 */
u64 vector_save_area_addr; /* 0x11b0 */
u8 pad_0x11b8[0x1200 - 0x11b8]; /* 0x11b8 */
u64 floating_pt_save_area[16]; /* 0x1200 */
u64 gpregs_save_area[16]; /* 0x1280 */
u32 st_status_fixed_logout[4]; /* 0x1300 */
u8 pad_0x1310[0x1318-0x1310]; /* 0x1310 */
u32 prefixreg_save_area; /* 0x1318 */
u32 fpt_creg_save_area; /* 0x131c */
u8 pad_0x1320[0x1324-0x1320]; /* 0x1320 */
u32 tod_progreg_save_area; /* 0x1324 */
u32 timer_save_area[2]; /* 0x1328 */
u32 clock_comp_save_area[2]; /* 0x1330 */
u8 pad_0x1338[0x1340-0x1338]; /* 0x1338 */
u32 access_regs_save_area[16]; /* 0x1340 */
u64 cregs_save_area[16]; /* 0x1380 */
u8 pad_0x1400[0x2000-0x1400]; /* 0x1400 */
} __attribute__((packed));
static inline u64 dfi_lc_size(enum dfi_arch arch)
{
if (arch == DFI_ARCH_64)
return 0x2000;
else
return 0x1000;
}
struct dfi_vxrs {
u64 low;
u64 high;
};
struct dfi_cpu {
struct util_list_node list;
u64 gprs[16];
u64 ctrs[16];
u32 acrs[16];
u64 fprs[16];
u32 fpc;
u64 psw[2];
u32 prefix;
u64 timer;
u64 todcmp;
u32 todpreg;
u64 vxrs_low[16];
struct dfi_vxrs vxrs_high[16];
};
struct dfi_cpu_32 {
u32 gprs[16];
u32 ctrs[16];
u32 acrs[16];
u64 fprs[4];
u32 psw[2];
u32 prefix;
u64 timer;
u64 todcmp;
u64 vxrs_low[16];
struct dfi_vxrs vxrs_high[16];
};
extern void dfi_cpu_64_to_32(struct dfi_cpu_32 *cpu_32, struct dfi_cpu *cpu_64);
extern enum dfi_arch dfi_arch(void);
extern void dfi_arch_set(enum dfi_arch arch);
extern const char *dfi_arch_str(enum dfi_arch arch);
enum dfi_cpu_content {
DFI_CPU_CONTENT_NONE, /* No register information available */
DFI_CPU_CONTENT_LC, /* Only lowcore information available */
DFI_CPU_CONTENT_ALL, /* Complete register information available */
};
#define DFI_CPU_CONTENT_FAC_VX 0x00000001
extern int dfi_cpu_content_fac_check(int falgs);
extern void dfi_cpu_content_fac_add(int flags);
#define dfi_cpu_iterate(cpu) \
util_list_iterate(dfi_cpu_list(), cpu)
extern struct util_list *dfi_cpu_list(void);
extern void dfi_cpu_info_init(enum dfi_cpu_content content);
extern struct dfi_cpu *dfi_cpu_alloc(void);
extern struct dfi_cpu *dfi_cpu(unsigned int cpu_nr);
extern void dfi_cpu_add(struct dfi_cpu *cpu);
extern unsigned int dfi_cpu_cnt(void);
extern enum dfi_cpu_content dfi_cpu_content(void);
extern void dfi_cpu_add_from_lc(u32 lc_addr);
#define DFI_VX_SA_SIZE (32 * 16)
extern int dfi_cpu_lc_has_vx_sa(void *lc);
extern void dfi_cpu_vx_copy(void *buf, struct dfi_cpu *cpu);
/*
* Mem chunk functions and definitions
*/
struct dfi_mem_chunk;
typedef void (*dfi_mem_chunk_read_fn)(struct dfi_mem_chunk *mem_chunk,
u64 off, void *buf, u64 cnt);
typedef void (*dfi_mem_chunk_free_fn)(void *data);
struct dfi_mem_chunk {
struct util_list_node list; /* List */
u64 start; /* Start address in memory */
u64 end; /* End address in memory */
u64 size; /* Size of chunk in dump file */
u64 out_start; /* Start offset in dump file */
u64 out_end; /* End offset in dump file */
dfi_mem_chunk_read_fn read_fn; /* Chunk read callback */
dfi_mem_chunk_free_fn free_fn; /* Free data callback */
void *data; /* Data for callback */
};
extern void dfi_mem_chunk_add(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn);
extern void dfi_mem_chunk_virt_add(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn);
extern u64 dfi_mem_range(void);
extern int dfi_mem_range_valid(u64 addr, u64 len);
extern unsigned int dfi_mem_chunk_cnt(void);
extern struct dfi_mem_chunk *dfi_mem_chunk_first(void);
extern struct dfi_mem_chunk *dfi_mem_chunk_next(struct dfi_mem_chunk *chunk);
extern struct dfi_mem_chunk *dfi_mem_chunk_prev(struct dfi_mem_chunk *chunk);
extern struct dfi_mem_chunk *dfi_mem_chunk_find(u64 addr);
extern struct util_list *dfi_mem_chunk_list(void);
#define dfi_mem_chunk_iterate(mem_chunk) \
util_list_iterate(dfi_mem_chunk_list(), mem_chunk)
/*
* Dump header attribute set/get functions
*/
extern void dfi_attr_time_set(struct timeval *time);
extern struct timeval *dfi_attr_time(void);
extern void dfi_attr_time_end_set(struct timeval *time_end);
extern struct timeval *dfi_attr_time_end(void);
extern void dfi_attr_cpu_id_set(u64 cpu_id);
extern u64 *dfi_attr_cpu_id(void);
extern void dfi_attr_utsname_set(struct new_utsname *utsname);
extern struct new_utsname *dfi_attr_utsname(void);
extern void dfi_attr_dump_method_set(char *dump_method);
extern char *dfi_attr_dump_method(void);
extern void dfi_attr_mem_size_real_set(u64 mem_size_real);
extern u64 *dfi_attr_mem_size_real();
extern void dfi_attr_vol_nr_set(unsigned int vol_nr);
extern unsigned int *dfi_attr_vol_nr(void);
extern void dfi_attr_version_set(unsigned int dfi_version);
extern unsigned int *dfi_attr_dfi_version(void);
extern void dfi_attr_build_arch_set(enum dfi_arch build_arch);
extern enum dfi_arch *dfi_attr_build_arch(void);
extern void dfi_attr_real_cpu_cnt_set(u32 real_cpu_cnt);
extern u32 *dfi_attr_real_cpu_cnt(void);
/*
* DFI external functions
*/
extern void dfi_mem_read(u64 addr, void *buf, size_t cnt);
extern int dfi_mem_read_rc(u64 addr, void *buf, size_t cnt);
extern void dfi_mem_phys_read(u64 addr, void *buf, size_t cnt);
extern void dfi_info_print(void);
/*
* DFI feature bits
*/
#define DFI_FEAT_SEEK 0x1 /* Necessary for fuse mount */
#define DFI_FEAT_COPY 0x2 /* Necessary for stdout */
extern int dfi_feat_seek(void);
extern int dfi_feat_copy(void);
/*
* DFI kdump functions
*/
extern unsigned long dfi_kdump_base(void);
/*
* DFI vmcoreinfo functions
*/
extern void dfi_vmcoreinfo_init(void);
extern char *dfi_vmcoreinfo_get(void);
extern int dfi_vmcoreinfo_tag(char *str, int len, const char *sym);
extern int dfi_vmcoreinfo_symbol(unsigned long *val, const char *sym);
extern int dfi_vmcoreinfo_offset(unsigned long *offs, const char *sym);
extern int dfi_vmcoreinfo_size(unsigned long *size, const char *sym);
extern int dfi_vmcoreinfo_length(unsigned long *len, const char *sym);
extern int dfi_vmcoreinfo_val(unsigned long *val, const char *sym);
/*
* DFI operations
*/
struct dfi {
const char *name;
int (*init)(void);
void (*exit)(void);
void (*info_dump)(void);
int feat_bits;
};
extern const char *dfi_name(void);
extern int dfi_init(void);
extern void dfi_exit(void);
/*
* Dump access
*/
extern struct zg_fh *dfi_dump_open(const char *path);
/*
* Live dump memory magic
*/
extern u64 dfi_live_dump_magic;
/*
* Dump methods
*/
#define DFI_DUMP_METHOD_LIVE "live"
#endif /* DFI_H */
+158
View File
@@ -0,0 +1,158 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* /dev/mem and /dev/crash dump input format
*
* Copyright IBM Corp. 2012, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <fcntl.h>
#include <limits.h>
#include <linux/fs.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <time.h>
#include <unistd.h>
#include "zgetdump.h"
/*
* Add live dump magic to buffer
*/
static void add_live_magic(void *buf, u64 off, u64 cnt)
{
if (off >= sizeof(dfi_live_dump_magic))
return;
memcpy(buf, &dfi_live_dump_magic,
MIN(cnt, sizeof(dfi_live_dump_magic)));
}
/*
* "devmem" mem chunk read callback
*
* This functions reads page wise in order to detect unreadable pages
*/
static void dfi_devmem_mem_chunk_read(struct dfi_mem_chunk *mem_chunk, u64 off,
void *buf, u64 cnt)
{
u64 copied = 0, len = PAGE_SIZE;
(void) mem_chunk;
if (off % PAGE_SIZE)
len = MIN(len, PAGE_SIZE - off % PAGE_SIZE);
len = MIN(len, cnt);
do {
zg_seek(g.fh, mem_chunk->start + off + copied, ZG_CHECK);
if (zg_read(g.fh, buf + copied, len, ZG_CHECK_NONE) < 0) {
if (errno == EFAULT) {
/* This can happen when using CMM */
memset(buf + copied, 0, len);
} else {
ERR_EXIT_ERRNO("Could not read %s",
g.opts.device);
}
}
copied += len;
len = MIN(PAGE_SIZE, cnt - copied);
} while (len);
add_live_magic(buf, mem_chunk->start + off, cnt);
}
/*
* Detect memory chunks via /proc/iomem
*
* check = 0: Initialize memory map
* check = 1: Verifiy that current system memory map is same as DFI memory map
*/
static int detect_mem_chunks(int check)
{
char line[4096], type1[4096], type2[4096];
unsigned long start, end, cnt = 0;
struct dfi_mem_chunk *mem_chunk;
struct zg_fh *fh;
ssize_t rc;
fh = zg_open("/proc/iomem", O_RDONLY, ZG_CHECK);
do {
rc = zg_gets(fh, line, sizeof(line), ZG_CHECK);
if (rc == 0)
break;
sscanf(line, "%lx-%lx : %s %s", &start, &end, type1, type2);
if (strcmp(type1, "System") != 0)
continue;
if (strcmp(type2, "RAM") != 0 && strcmp(type2, "ROM") != 0)
continue;
if (check) {
mem_chunk = dfi_mem_chunk_find(start);
if (!mem_chunk)
return -EINVAL;
if (mem_chunk->start != start)
return -EINVAL;
if (mem_chunk->end != end)
return -EINVAL;
cnt++;
} else {
dfi_mem_chunk_add(start, end - start + 1, NULL,
dfi_devmem_mem_chunk_read, NULL);
}
} while (1);
if (check && cnt != dfi_mem_chunk_cnt())
return -EINVAL;
return 0;
}
/*
* Return architecture of running system
*/
static enum dfi_arch system_arch(void)
{
struct utsname utsname;
uname(&utsname);
if (memcmp(utsname.machine, "s390x", 5) == 0)
return DFI_ARCH_64;
if (memcmp(utsname.machine, "s390", 4) == 0)
return DFI_ARCH_32;
return DFI_ARCH_UNKNOWN;
}
/*
* Initialize devmem DFI
*/
static int dfi_devmem_init(void)
{
if (strcmp(g.fh->path, "/dev/mem") != 0 &&
strcmp(g.fh->path, "/dev/crash") != 0)
return -ENODEV;
dfi_arch_set(system_arch());
dfi_cpu_info_init(DFI_CPU_CONTENT_NONE);
detect_mem_chunks(0);
dfi_attr_dump_method_set(DFI_DUMP_METHOD_LIVE);
zg_seek(g.fh, 0, ZG_CHECK);
return 0;
}
/*
* Cleanup devmem DFI
*/
static void dfi_devmem_exit(void)
{
if (detect_mem_chunks(1))
STDERR("Warning: memory map has changed\n");
}
/*
* devmem DFI operations
*/
struct dfi dfi_devmem = {
.name = "devmem",
.init = dfi_devmem_init,
.exit = dfi_devmem_exit,
.feat_bits = DFI_FEAT_COPY | DFI_FEAT_SEEK,
};
+322
View File
@@ -0,0 +1,322 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* ELF core dump input format
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <assert.h>
#include <elf.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "zgetdump.h"
/*
* Read memory for given memory chunk
*/
static void dfi_elf_mem_chunk_read_fn(struct dfi_mem_chunk *mem_chunk, u64 off,
void *buf, u64 cnt)
{
u64 elf_load_off = *((u64 *) mem_chunk->data);
zg_seek(g.fh, elf_load_off + off, ZG_CHECK);
zg_read(g.fh, buf, cnt, ZG_CHECK);
}
/*
* Add load (memory chunk) to DFI dump
*/
static int pt_load_add(Elf64_Phdr *phdr)
{
u64 *off_ptr;
if (phdr->p_paddr != phdr->p_vaddr) {
phdr->p_paddr = phdr->p_vaddr;
STDERR("Dump file \"%s\" is a user space core dump\n",
g.opts.device);
}
if (phdr->p_filesz == 0) /* Skip null pt loads */
return 0;
off_ptr = zg_alloc(sizeof(*off_ptr));
*off_ptr = phdr->p_offset;
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_filesz, off_ptr,
dfi_elf_mem_chunk_read_fn, zg_free);
if (phdr->p_offset + phdr->p_filesz > zg_size(g.fh))
return -EINVAL;
return 0;
}
/*
* Skip name of note
*/
static void nt_name_skip(Elf64_Nhdr *note)
{
zg_seek_cur(g.fh, ROUNDUP(note->n_namesz, 4), ZG_CHECK);
}
/*
* Read note
*/
static int nt_read(Elf64_Nhdr *note, void *buf)
{
off_t buf_len = ROUNDUP(note->n_descsz, 4);
char tmp_buf[buf_len];
nt_name_skip(note);
if (zg_read(g.fh, tmp_buf, buf_len, ZG_CHECK_ERR) != buf_len)
return -EINVAL;
if (buf)
memcpy(buf, tmp_buf, note->n_descsz);
return 0;
}
/*
* Skip note
*/
static int nt_skip(Elf64_Nhdr *note)
{
return nt_read(note, NULL);
}
/*
* Ensure that CPU is already defined by prstatus note
*/
static void check_cpu(struct dfi_cpu *cpu, const char *note_str)
{
if (cpu)
return;
ERR_EXIT("Invalid ELF dump (%s before prstatus found)", note_str);
}
/*
* Read prstatus note and return new DFI CPU
*/
static struct dfi_cpu *nt_prstatus_read(Elf64_Nhdr *note)
{
struct dfi_cpu *cpu = dfi_cpu_alloc();
struct nt_prstatus_64 nt_prstatus;
if (nt_read(note, &nt_prstatus))
return NULL;
memcpy(cpu->gprs, &nt_prstatus.gprs, sizeof(cpu->gprs));
memcpy(cpu->psw, &nt_prstatus.psw, sizeof(cpu->psw));
memcpy(cpu->acrs, &nt_prstatus.acrs, sizeof(cpu->acrs));
dfi_cpu_add(cpu);
return cpu;
}
/*
* Read fpregset note
*/
static int nt_fpregset_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
{
struct nt_fpregset_64 nt_fpregset;
check_cpu(cpu, "FPREGSET");
if (nt_read(note, &nt_fpregset))
return -EINVAL;
memcpy(&cpu->fpc, &nt_fpregset.fpc, sizeof(cpu->fpc));
memcpy(cpu->fprs, &nt_fpregset.fprs, sizeof(cpu->fprs));
return 0;
}
/*
* Read s390 timer note
*/
static int nt_s390_timer_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
{
check_cpu(cpu, "S390_TIMER");
return nt_read(note, &cpu->timer);
}
/*
* Read s390 todcmp note
*/
static int nt_s390_todcmp_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
{
check_cpu(cpu, "S390_TODCMP");
return nt_read(note, &cpu->todcmp);
}
/*
* Read s390 todpreg note
*/
static int nt_s390_todpreg_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
{
check_cpu(cpu, "S390_TODPREG");
return nt_read(note, &cpu->todpreg);
}
/*
* Read s390 ctrs note
*/
static int nt_s390_ctrs_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
{
check_cpu(cpu, "S390_CTRS");
return nt_read(note, &cpu->ctrs);
}
/*
* Read s390 prefix note
*/
static int nt_s390_prefix_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
{
check_cpu(cpu, "S390_PREFIX");
return nt_read(note, &cpu->prefix);
}
/*
* Read s390 vxrs_low note
*/
static int nt_s390_vxrs_low_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
{
check_cpu(cpu, "S390_VXRS_LOW");
return nt_read(note, &cpu->vxrs_low);
}
/*
* Read s390 vxrs_high note
*/
static int nt_s390_vxrs_high_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
{
check_cpu(cpu, "S390_VXRS_HIGH");
return nt_read(note, &cpu->vxrs_high);
}
/*
* Add all notes for notes phdr
*/
static int pt_notes_add(Elf64_Phdr *phdr)
{
u64 start_off = zg_tell(g.fh, ZG_CHECK);
struct dfi_cpu *cpu_current = NULL;
u64 notes_start_off;
Elf64_Nhdr note;
int rc;
zg_seek(g.fh, phdr->p_offset, ZG_CHECK);
notes_start_off = zg_tell(g.fh, ZG_CHECK);
while (zg_tell(g.fh, ZG_CHECK) - notes_start_off < phdr->p_filesz) {
rc = zg_read(g.fh, &note, sizeof(note), ZG_CHECK_ERR);
if (rc != sizeof(note))
return -EINVAL;
switch (note.n_type) {
case NT_PRSTATUS:
cpu_current = nt_prstatus_read(&note);
if (!cpu_current)
return -EINVAL;
break;
case NT_FPREGSET:
if (nt_fpregset_read(cpu_current, &note))
return -EINVAL;
break;
case NT_S390_TIMER:
if (nt_s390_timer_read(cpu_current, &note))
return -EINVAL;
break;
case NT_S390_TODCMP:
if (nt_s390_todcmp_read(cpu_current, &note))
return -EINVAL;
break;
case NT_S390_TODPREG:
if (nt_s390_todpreg_read(cpu_current, &note))
return -EINVAL;
break;
case NT_S390_CTRS:
if (nt_s390_ctrs_read(cpu_current, &note))
return -EINVAL;
break;
case NT_S390_PREFIX:
if (nt_s390_prefix_read(cpu_current, &note))
return -EINVAL;
break;
case NT_S390_VXRS_LOW:
if (nt_s390_vxrs_low_read(cpu_current, &note))
return -EINVAL;
dfi_cpu_content_fac_add(DFI_CPU_CONTENT_FAC_VX);
break;
case NT_S390_VXRS_HIGH:
if (nt_s390_vxrs_high_read(cpu_current, &note))
return -EINVAL;
dfi_cpu_content_fac_add(DFI_CPU_CONTENT_FAC_VX);
break;
default:
if (nt_skip(&note))
return -EINVAL;
break;
}
}
zg_seek(g.fh, start_off, ZG_CHECK);
return 0;
}
/*
* Read ELF header
*/
static int read_elf_hdr(Elf64_Ehdr *ehdr)
{
if (zg_size(g.fh) < sizeof(*ehdr))
return -ENODEV;
zg_read(g.fh, ehdr, sizeof(*ehdr), ZG_CHECK);
if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0)
return -ENODEV;
if (ehdr->e_type != ET_CORE)
return -ENODEV;
if (ehdr->e_machine != EM_S390 || ehdr->e_ident[EI_CLASS] != ELFCLASS64)
ERR_EXIT("Only s390x (64 bit) core dump files are supported");
return 0;
}
/*
* Initialize ELF input dump format
*/
static int dfi_elf_init(void)
{
Elf64_Ehdr ehdr;
Elf64_Phdr phdr;
int i;
if (read_elf_hdr(&ehdr) != 0)
return -ENODEV;
df_elf_ensure_s390x();
dfi_arch_set(DFI_ARCH_64);
dfi_cpu_info_init(DFI_CPU_CONTENT_ALL);
for (i = 0; i < ehdr.e_phnum; i++) {
zg_read(g.fh, &phdr, sizeof(phdr), ZG_CHECK);
switch (phdr.p_type) {
case PT_LOAD:
if (pt_load_add(&phdr))
return -EINVAL;
break;
case PT_NOTE:
if (pt_notes_add(&phdr))
return -EINVAL;
break;
default:
break;
}
}
dfi_attr_version_set(ehdr.e_ident[EI_VERSION]);
return 0;
}
/*
* ELF DFI operations
*/
struct dfi dfi_elf = {
.name = "elf",
.init = dfi_elf_init,
.feat_bits = DFI_FEAT_COPY | DFI_FEAT_SEEK,
};
+223
View File
@@ -0,0 +1,223 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* kdump and kdump_flat input format
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include "zgetdump.h"
struct df_kdump_hdr {
char signature[8];
int header_version;
struct new_utsname utsname;
struct timeval timestamp;
unsigned int status;
int block_size;
int sub_hdr_size;
unsigned int bitmap_blocks;
unsigned int max_mapnr;
unsigned int total_ram_blocks;
unsigned int device_blocks;
unsigned int written_blocks;
unsigned int current_cpu;
int nr_cpus;
void *tasks[0];
};
struct df_kdump_sub_hdr {
unsigned long phys_base;
int dump_level;
int split;
unsigned long start_pfn;
unsigned long end_pfn;
off_t offset_vmcoreinfo;
unsigned long size_vmcoreinfo;
};
struct df_kdump_flat_hdr {
char signature[16];
u64 type;
u64 version;
};
struct df_kdump_flat_data_hdr {
s64 offs;
s64 size;
};
/*
* File local static data
*/
static struct {
struct df_kdump_hdr hdr; /* kdump (diskdump) dump header */
struct df_kdump_sub_hdr shdr; /* kdump subheader */
} l;
#ifdef DEBUG
static void print_header(void)
{
STDERR("diskdump main header\n");
STDERR(" signature : %s\n", l.hdr.signature);
STDERR(" header_version : %d\n", l.hdr.header_version);
STDERR(" status : %d\n", l.hdr.status);
STDERR(" block_size : %d\n", l.hdr.block_size);
STDERR(" sub_hdr_size : %d\n", l.hdr.sub_hdr_size);
STDERR(" bitmap_blocks : %d\n", l.hdr.bitmap_blocks);
STDERR(" max_mapnr : 0x%x\n", l.hdr.max_mapnr);
STDERR(" total_ram_blocks : %d\n", l.hdr.total_ram_blocks);
STDERR(" device_blocks : %d\n", l.hdr.device_blocks);
STDERR(" written_blocks : %d\n", l.hdr.written_blocks);
STDERR(" current_cpu : %d\n", l.hdr.current_cpu);
STDERR(" nr_cpus : %d\n", l.hdr.nr_cpus);
}
static void print_sub_header(void)
{
STDERR("kdump sub header\n");
STDERR(" phys_base : 0x%lx\n", l.shdr.phys_base);
STDERR(" dump_level : %d\n", l.shdr.dump_level);
STDERR(" split : %d\n", l.shdr.split);
STDERR(" start_pfn : 0x%lx\n", l.shdr.start_pfn);
STDERR(" end_pfn : 0x%lx\n", l.shdr.end_pfn);
}
#endif
/*
* Check for kdump flat end marker
*/
static inline int kdump_flat_endmarker(struct df_kdump_flat_data_hdr *d_hdr)
{
return (d_hdr->offs == -1) && (d_hdr->size == -1);
}
/*
* Init kdump dump header
*/
static int init_kdump_hdr(struct df_kdump_hdr *hdr)
{
if (memcmp(hdr->signature, "KDUMP", 5) != 0)
return -ENODEV;
dfi_attr_version_set(hdr->header_version);
dfi_attr_real_cpu_cnt_set(hdr->nr_cpus);
dfi_attr_utsname_set(&hdr->utsname);
dfi_attr_time_set(&hdr->timestamp);
dfi_arch_set(DFI_ARCH_64);
dfi_mem_chunk_add(0, (unsigned long) hdr->max_mapnr * PAGE_SIZE,
NULL, NULL, NULL);
return 0;
}
/*
* Initialize kdump DFI
*/
static int dfi_kdump_init(void)
{
if ((zg_type(g.fh) == ZG_TYPE_FILE) && (zg_size(g.fh) < sizeof(l.hdr)))
return -ENODEV;
if (zg_read(g.fh, &l.hdr, sizeof(l.hdr), ZG_CHECK_ERR) != sizeof(l.hdr))
return -ENODEV;
if (memcmp(l.hdr.signature, "KDUMP", 5) != 0)
return -ENODEV;
zg_seek(g.fh, l.hdr.block_size, ZG_CHECK);
zg_read(g.fh, &l.shdr, sizeof(l.shdr), ZG_CHECK);
#ifdef DEBUG
print_header();
print_sub_header();
#endif
return init_kdump_hdr(&l.hdr);
}
/*
* kdump DFI operations
*/
struct dfi dfi_kdump = {
.name = "kdump",
.init = dfi_kdump_init,
.feat_bits = 0,
};
#ifdef DEBUG
static void print_kdump_flat_header(struct df_kdump_flat_hdr *hdr)
{
STDERR("diskdump main header\n");
STDERR(" signature : %s\n", hdr->signature);
STDERR(" version : %lld\n", hdr->version);
STDERR(" type : %lld\n", hdr->type);
}
#endif
/*
* Read makedumpfile dump header
*/
static int read_kdump_flat_hdr(void)
{
struct df_kdump_flat_hdr hdr;
if ((zg_type(g.fh) == ZG_TYPE_FILE) && (zg_size(g.fh) < sizeof(l.hdr)))
return -ENODEV;
if (zg_read(g.fh, &hdr, sizeof(hdr), ZG_CHECK_ERR) != sizeof(hdr))
return -ENODEV;
if (memcmp(hdr.signature, "makedumpfile", 12) != 0)
return -ENODEV;
if (hdr.type != 1)
return -ENODEV;
#ifdef DEBUG
print_kdump_flat_header(&hdr);
#endif
return 0;
}
/*
* Read kdump header from fh
*/
static int read_kdump_hdr(struct zg_fh *fh, s64 size)
{
struct df_kdump_hdr hdr;
if (size < (s64) sizeof(hdr))
ERR_EXIT("Can't get kdump header");
if (zg_read(fh, &hdr, sizeof(hdr), ZG_CHECK_ERR) != sizeof(hdr))
return -EINVAL;
if (init_kdump_hdr(&hdr))
return -EINVAL;
zg_seek_cur(fh, -sizeof(hdr), ZG_CHECK_NONE);
return 0;
}
/*
* Initialize kdump_flat DFI
*/
static int dfi_kdump_flat_init(void)
{
struct df_kdump_flat_data_hdr d_hdr;
if (read_kdump_flat_hdr() != 0)
return -ENODEV;
zg_seek(g.fh, 4096, ZG_CHECK);
zg_read(g.fh, &d_hdr, sizeof(d_hdr), ZG_CHECK);
do {
if (d_hdr.offs == 0 && read_kdump_hdr(g.fh, d_hdr.size) != 0)
return -EINVAL;
zg_seek_cur(g.fh, d_hdr.size, ZG_CHECK_NONE);
if (zg_read(g.fh, &d_hdr, sizeof(d_hdr),
ZG_CHECK_ERR) != sizeof(d_hdr))
return -EINVAL;
} while ((d_hdr.offs >= 0) && (d_hdr.size > 0));
if (kdump_flat_endmarker(&d_hdr))
return 0;
return -EINVAL;
}
/*
* kdump_flat DFI operations
*/
struct dfi dfi_kdump_flat = {
.name = "kdump_flat",
.init = dfi_kdump_flat_init,
.feat_bits = 0,
};
+335
View File
@@ -0,0 +1,335 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* LKCD dump input format
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <zlib.h>
#include "zgetdump.h"
#define MEM_HOLE_SIZE_MIN (1024 * 1024)
#define IDX_KIB 64 /* One index entry per IDX_KIB */
#define IDX_TO_ADDR(idx) (idx * IDX_KIB * 1024)
#define ADDR_TO_IDX(addr) (addr / (1024 * IDX_KIB))
/*
* File local static data
*/
static struct {
u64 *pg_hdr_idx;
u64 page_last;
struct df_lkcd_hdr hdr;
struct df_lkcd_hdr_asm hdr_asm;
int dump_full;
} l;
/*
* Read LKCD page buffer, either compressed or uncompressed
*/
static void read_page_buf(struct df_lkcd_pg_hdr *pg_hdr, void *buf)
{
unsigned long size = PAGE_SIZE;
unsigned char cbuf[PAGE_SIZE];
switch (pg_hdr->flags) {
case DF_LKCD_DH_RAW:
zg_read(g.fh, buf, pg_hdr->size, ZG_CHECK);
break;
case DF_LKCD_DH_COMPRESSED:
zg_read(g.fh, cbuf, pg_hdr->size, ZG_CHECK);
uncompress(buf, &size, cbuf, pg_hdr->size);
if (size != PAGE_SIZE)
ABORT("Invalid page size: %ld", size);
break;
default:
ERR_EXIT("Unsupported page flags: %x at addr %Lx",
pg_hdr->flags, pg_hdr->addr);
}
}
/*
* Read next LKCD page from current file position
*
* If we find the page, we copy the page content. If the page is not present
* we copy zeroes and skip it. If the page address is not yet reached, we just
* skip it.
*/
static int read_next_page(u64 addr, void *buf)
{
struct df_lkcd_pg_hdr pg_hdr;
zg_read(g.fh, &pg_hdr, sizeof(pg_hdr), ZG_CHECK);
l.page_last = pg_hdr.addr / PAGE_SIZE;
if (pg_hdr.addr == addr) {
read_page_buf(&pg_hdr, buf);
return 0;
}
if (pg_hdr.addr > addr) {
memset(buf, 0, PAGE_SIZE);
zg_seek_cur(g.fh, pg_hdr.size, ZG_CHECK);
return 0;
}
zg_seek_cur(g.fh, pg_hdr.size, ZG_CHECK);
return -ENODEV;
}
/*
* Read LKCD dump page for flex dump
*
* If the page after the last read page should be read, we just read
* the next one. Otherwise we seek to the beginning of the page cluster
* of the page index and search the page there.
*/
static void read_page_flex(u64 pg_num, void *buf)
{
u64 addr = pg_num * PAGE_SIZE;
if (l.pg_hdr_idx[ADDR_TO_IDX(addr)] == 0)
ABORT("Dump page index broken");
if (l.page_last == pg_num - 1) {
read_next_page(addr, buf);
return;
}
zg_seek(g.fh, l.pg_hdr_idx[ADDR_TO_IDX(addr)], ZG_CHECK);
do {
if (read_next_page(addr, buf) == 0)
break;
} while (1);
}
/*
* Read lkcd page for full dump
*/
static void read_page_full(u64 pg_num, void *buf)
{
zg_seek(g.fh, DF_LKCD_HDR_SIZE + pg_num * DF_LKCD_UCP_SIZE +
sizeof(struct df_lkcd_pg_hdr), ZG_CHECK);
zg_read(g.fh, buf, PAGE_SIZE, ZG_CHECK);
}
/*
* Read lkcd page
*/
static void read_page(u64 pg_num, void *buf)
{
if (l.dump_full)
read_page_full(pg_num, buf);
else
read_page_flex(pg_num, buf);
}
/*
* LKCD mem chunk read callback
*/
static void dfi_lkcd_mem_chunk_read_fn(struct dfi_mem_chunk *mem_chunk, u64 off,
void *buf, u64 cnt)
{
u64 copied = 0, size, pg_nr, addr = off + mem_chunk->start;
char pg_buf[PAGE_SIZE];
unsigned int pg_off;
while (copied != cnt) {
pg_nr = (addr + copied) / PAGE_SIZE;
pg_off = (addr + copied) % PAGE_SIZE;
size = MIN(cnt - copied, PAGE_SIZE - pg_off);
read_page(pg_nr, pg_buf);
memcpy(buf + copied, &pg_buf[pg_off], size);
copied += size;
}
}
/*
* Did we find the end of the LCKD dump?
*/
static int dump_end(u64 addr, struct df_lkcd_pg_hdr *pg_hdr)
{
if (addr == pg_hdr->addr) {
/*
* This is a workaroud for a bug in vmconvert,
* where instaed of the end marker the last
* page was written twice. Sorry for that...
*/
return 1;
}
if (pg_hdr->addr == 0 && pg_hdr->size == 4 && pg_hdr->flags == 0) {
/*
* zfcpdump bug (wrong end marker)
*/
return 1;
}
if (pg_hdr->flags == DF_LKCD_DH_END)
return 1;
return 0;
}
/*
* Init memory chunks for full dump
*
* Full dump: It is not compressed and it does not have any memory holes.
*/
static int mem_init_full(void)
{
dfi_mem_chunk_add(0, l.hdr.mem_end, NULL, dfi_lkcd_mem_chunk_read_fn,
NULL);
l.dump_full = 1;
return 0;
}
/*
* Init memory chunks for flex dump
*
* Flex dump: It is compressed and/or it has memory holes.
*/
static int mem_init_flex(void)
{
u64 addr = U64_MAX, idx = 0, mem_chunk_start = 0, rc;
struct df_lkcd_pg_hdr pg_hdr;
int dump_incomplete = 0;
l.pg_hdr_idx = zg_alloc(sizeof(u64) * (ADDR_TO_IDX(l.hdr.mem_end) + 1));
zg_seek(g.fh, DF_LKCD_HDR_SIZE, ZG_CHECK_NONE);
zg_progress_init("Analyzing dump", l.hdr.mem_end);
do {
rc = zg_read(g.fh, &pg_hdr, sizeof(pg_hdr), ZG_CHECK_ERR);
if (rc != sizeof(pg_hdr)) {
dump_incomplete = 1;
break;
}
if (dump_end(addr, &pg_hdr))
break;
if (pg_hdr.addr - addr > MEM_HOLE_SIZE_MIN) {
dfi_mem_chunk_add(mem_chunk_start,
addr + PAGE_SIZE - mem_chunk_start,
NULL, dfi_lkcd_mem_chunk_read_fn,
NULL);
mem_chunk_start = pg_hdr.addr;
}
addr = pg_hdr.addr;
zg_progress(addr);
if (addr >= IDX_TO_ADDR(idx)) {
idx = ADDR_TO_IDX(addr);
l.pg_hdr_idx[idx] = zg_tell(g.fh, ZG_CHECK) -
sizeof(pg_hdr);
idx++;
}
zg_seek_cur(g.fh, pg_hdr.size, ZG_CHECK);
} while (1);
if (addr != mem_chunk_start) {
dfi_mem_chunk_add(mem_chunk_start,
l.hdr.mem_end - mem_chunk_start,
NULL, dfi_lkcd_mem_chunk_read_fn, NULL);
}
zg_progress(l.hdr.mem_end);
if (g.opts.action != ZG_ACTION_MOUNT)
fprintf(stderr, "\n");
if (dump_incomplete)
return -EINVAL;
return 0;
}
/*
* Do we have a full dump?
*/
static int is_full_dump(void)
{
u64 full_size;
int pages;
if (l.hdr.dump_compress != DF_LKCD_COMPRESS_NONE)
return 0;
pages = l.hdr.mem_end / PAGE_SIZE;
full_size = DF_LKCD_HDR_SIZE + pages * DF_LKCD_UCP_SIZE +
sizeof(struct df_lkcd_pg_hdr);
if (zg_size(g.fh) != full_size)
return 0;
return 1;
}
/*
* Init memory chunks
*/
static int mem_init(void)
{
if (is_full_dump())
return mem_init_full();
else
return mem_init_flex();
}
/*
* Initialize CPU information
*/
static void cpu_init(void)
{
unsigned int i;
if (l.hdr_asm.magic != DF_LKCD_MAGIC_ASM) {
/* Old LKCD dump without asm header */
dfi_cpu_info_init(DFI_CPU_CONTENT_NONE);
return;
}
dfi_cpu_info_init(DFI_CPU_CONTENT_ALL);
for (i = 0; i < l.hdr_asm.cpu_cnt; i++)
dfi_cpu_add_from_lc(l.hdr_asm.lc_vec[i]);
}
/*
* Read LKCD dump header and dump asm header
*/
static int read_lkcd_hdr(void)
{
if (zg_size(g.fh) < DF_LKCD_HDR_SIZE)
return -ENODEV;
/* Read dump header */
zg_read(g.fh, &l.hdr, sizeof(l.hdr), ZG_CHECK);
if (l.hdr.magic != DF_LKCD_MAGIC)
return -ENODEV;
/* Read asm header */
zg_seek(g.fh, l.hdr.hdr_size, ZG_CHECK);
zg_read(g.fh, &l.hdr_asm, sizeof(l.hdr_asm), ZG_CHECK);
if (strncmp(l.hdr.utsname_machine, "s390x", sizeof("s390x")) == 0)
dfi_arch_set(DFI_ARCH_64);
else if (strncmp(l.hdr.utsname_machine, "s390", sizeof("s390")) == 0)
dfi_arch_set(DFI_ARCH_32);
else
ERR_EXIT("Dump architecture \"%s\" is not supported",
l.hdr.utsname_machine);
if (l.hdr_asm.magic == DF_LKCD_MAGIC_ASM)
dfi_attr_real_cpu_cnt_set(l.hdr_asm.real_cpu_cnt);
dfi_attr_version_set(l.hdr.version);
return 0;
}
/*
* Initialize LKCD DFI
*/
static int dfi_lkcd_init(void)
{
if (read_lkcd_hdr() != 0)
return -ENODEV;
if (mem_init() != 0)
return -EINVAL;
cpu_init();
return 0;
}
/*
* LKCD DFI operations
*/
struct dfi dfi_lkcd = {
.name = "lkcd",
.init = dfi_lkcd_init,
.feat_bits = DFI_FEAT_COPY | DFI_FEAT_SEEK,
};
+100
View File
@@ -0,0 +1,100 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* S390 dump input format
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <fcntl.h>
#include <linux/fs.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "zgetdump.h"
/*
* File local static data
*/
static struct {
struct df_s390_hdr hdr; /* s390 dump header */
struct df_s390_em em; /* s390 end marker */
} l;
/*
* S390 mem chunk read callback
*/
static void dfi_s390_mem_chunk_read(struct dfi_mem_chunk *mem_chunk, u64 off,
void *buf, u64 cnt)
{
(void) mem_chunk;
zg_seek(g.fh, off + DF_S390_HDR_SIZE, ZG_CHECK);
zg_read(g.fh, buf, cnt, ZG_CHECK);
}
/*
* Read s390 dump header
*/
static int read_s390_hdr(void)
{
if ((zg_type(g.fh) == ZG_TYPE_FILE) && (zg_size(g.fh) < sizeof(l.hdr)))
return -ENODEV;
if (zg_read(g.fh, &l.hdr, sizeof(l.hdr), ZG_CHECK_ERR) != sizeof(l.hdr))
return -ENODEV;
if (l.hdr.magic != DF_S390_MAGIC)
return -ENODEV;
df_s390_hdr_add(&l.hdr);
return 0;
}
/*
* Init end marker
*/
static int read_s390_em(void)
{
u64 rc;
rc = zg_seek(g.fh, l.hdr.mem_size + DF_S390_HDR_SIZE, ZG_CHECK_NONE);
if (rc != l.hdr.mem_size + DF_S390_HDR_SIZE)
return -EINVAL;
rc = zg_read(g.fh, &l.em, sizeof(l.em), ZG_CHECK_ERR);
if (rc != sizeof(l.em))
return -EINVAL;
if (df_s390_em_verify(&l.em, &l.hdr) != 0)
return -EINVAL;
df_s390_em_add(&l.em);
return 0;
}
/*
* Initialize s390 DFI
*/
static int dfi_s390_init(void)
{
if (read_s390_hdr() != 0)
return -ENODEV;
dfi_mem_chunk_add(0, l.hdr.mem_size, NULL, dfi_s390_mem_chunk_read,
NULL);
if (read_s390_em() != 0)
return -EINVAL;
df_s390_cpu_info_add(&l.hdr, l.hdr.mem_size);
zg_seek(g.fh, sizeof(l.hdr), ZG_CHECK);
return 0;
}
/*
* S390 DFI operations
*/
struct dfi dfi_s390 = {
.name = "s390",
.init = dfi_s390_init,
.feat_bits = DFI_FEAT_COPY | DFI_FEAT_SEEK,
};
+554
View File
@@ -0,0 +1,554 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* S390 multi-volume dump input format
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <dirent.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <time.h>
#include <unistd.h>
#include "zgetdump.h"
#define SYSFS_BUSDIR "/sys/bus/ccw/devices"
#define MAX_VOLUMES 32
/*
* Parameter for DASD multi-volume dump
*/
struct vol_parm {
u16 devno;
u32 start_blk;
u32 end_blk;
u8 blk_size;
u8 end_sec;
u8 num_heads;
} __attribute__ ((packed));
struct vol_parm_table {
u64 timestamp;
u16 vol_cnt;
struct vol_parm vol_parm[MAX_VOLUMES];
u8 ssid[MAX_VOLUMES];
} __attribute__ ((packed));
/*
* Device signature
*/
enum dev_sign {
SIGN_INVALID = 0, /* No dumper installed */
SIGN_VALID = 1, /* dumper installed, but volume not used */
SIGN_ACTIVE = 2, /* dumper installed and volume userd */
};
static char *dev_sign_str[] = {"invalid", "valid", "active"};
#define dev_sign_str(x) (dev_sign_str[x])
/*
* Device status
*/
enum dev_status {
DEV_ONLINE = 0,
DEV_OFFLINE = 1,
DEV_UNDEFINED = 2,
};
static char *dev_status_str[] = {"online", "offline", "undefined"};
#define dev_status_str(x) (dev_status_str[x])
/*
* Volume information
*/
struct vol {
dev_t dev;
struct zg_fh *fh;
char *devnode;
enum dev_status status;
enum dev_sign sign;
off_t part_off;
u64 part_size;
u64 mem_start;
u64 mem_end;
char bus_id[9];
u32 nr;
u16 blk_size;
struct df_s390_dumper dumper;
struct df_s390_hdr hdr;
};
/*
* File local static data
*/
static struct {
struct df_s390_hdr hdr;
struct df_s390_em em;
struct vol vol_vec[MAX_VOLUMES];
struct vol_parm_table table;
int blk_size;
struct df_s390_dumper dumper;
int dump_incomplete;
} l;
/*
* Read volume parameter table
*/
static void table_read(struct zg_fh *fh, u16 blk_size,
struct vol_parm_table *table)
{
int off;
off = DF_S390_MAGIC_BLK_ECKD * blk_size +
df_s390_dumper_size(&l.dumper);
zg_seek(fh, off, ZG_CHECK);
zg_read(fh, table, sizeof(*table), ZG_CHECK);
}
/*
* Initialize dump end marker
*/
static void em_init(struct vol *vol)
{
off_t em_off;
em_off = vol->part_off + (vol->mem_end + 1 - vol->mem_start) +
DF_S390_HDR_SIZE;
zg_seek(vol->fh, em_off, ZG_CHECK);
zg_read(vol->fh, &l.em, sizeof(l.em), ZG_CHECK);
if (df_s390_em_verify(&l.em, &l.hdr) != 0)
l.dump_incomplete = 1;
}
/*
* Check sysfs, whether a device specified by its bus ID is defined and online.
* Find out the corresponding dev_t
*/
static enum dev_status dev_from_busid(char *bus_id, dev_t *dev)
{
char tmp_file[PATH_MAX], dev_file[PATH_MAX];
struct dirent *direntp;
int fh, minor, major;
char buf[10];
DIR *fh_dir;
snprintf(dev_file, PATH_MAX, "%s/%s", SYSFS_BUSDIR, bus_id);
fh_dir = opendir(dev_file);
if (!fh_dir)
return DEV_UNDEFINED;
snprintf(tmp_file, PATH_MAX, "%s/online", dev_file);
fh = open(tmp_file, O_RDONLY);
if (read(fh, buf, 1) == -1)
ERR_EXIT_ERRNO("Could not read online attribute");
close(fh);
if (buf[0] != '1')
return DEV_OFFLINE;
while ((direntp = readdir(fh_dir)))
if (strncmp(direntp->d_name, "block:", 6) == 0)
break;
closedir(fh_dir);
if (direntp == NULL) {
snprintf(dev_file, PATH_MAX, "%s/%s/block", SYSFS_BUSDIR,
bus_id);
fh_dir = opendir(dev_file);
if (!fh_dir)
ERR_EXIT_ERRNO("Could not open \"%s\"", dev_file);
while ((direntp = readdir(fh_dir)))
if (strncmp(direntp->d_name, "dasd", 4) == 0)
break;
closedir(fh_dir);
if (direntp == NULL)
ERR_EXIT("Problem with contents of \"%s\"", dev_file);
}
snprintf(tmp_file, PATH_MAX, "%s/%s/dev", dev_file, direntp->d_name);
fh = open(tmp_file, O_RDONLY);
if (read(fh, buf, sizeof(buf)) == -1)
ERR_EXIT_ERRNO("Could not read dev file");
close(fh);
if (sscanf(buf, "%i:%i", &major, &minor) != 2)
ERR_EXIT("Malformed content of \"%s\": %s", tmp_file, buf);
*dev = makedev(major, minor);
return DEV_ONLINE;
}
/*
* Check whether dump table on user specified dump device is
* identical to the one found on this device.
*/
static void check_vol_table(struct vol *vol)
{
struct vol_parm_table vol_table;
table_read(vol->fh, vol->blk_size, &vol_table);
if (memcmp(&vol_table, &l.table, sizeof(vol_table)))
ERR_EXIT("Orphaned multi-volume dump device '%s'",
g.opts.device);
}
/*
* Read dump tool, multi-volume dump parameter table, and dump header from the
* input dump volume. Check input dump volume for:
* - identical dump parameter table (that is it belongs to the same dump set)
* - valid magic number in the dump tool
* - valid dump sign in the dump header
*
* We read partition data via the device node. If another process
* has changed partition data via the partition node, the corresponding
* device node might still have old data in its buffers. Flush buffers
* to keep things in sync.
*/
static void vol_read(struct vol *vol)
{
zg_ioctl(vol->fh, BLKFLSBUF, NULL, "BLKFLSBUF", ZG_CHECK);
df_s390_dumper_read(vol->fh, vol->blk_size, &vol->dumper);
check_vol_table(vol);
zg_seek(vol->fh, vol->part_off, ZG_CHECK);
zg_read(vol->fh, &vol->hdr, DF_S390_HDR_SIZE, ZG_CHECK);
}
/*
* Read memory
*/
static void df_s390mv_mem_read(struct dfi_mem_chunk *mem_chunk, u64 off,
void *buf, u64 cnt)
{
struct vol *vol = mem_chunk->data;
zg_seek(vol->fh, vol->part_off + off + DF_S390_HDR_SIZE, ZG_CHECK);
zg_read(vol->fh, buf, cnt, ZG_CHECK);
}
/*
* Initialize DASD volume
*/
static void vol_init(struct vol *vol, struct vol_parm *vol_parm, int ssid,
u64 *mem_off)
{
u64 blk_cnt = vol_parm->end_blk - vol_parm->start_blk + 1;
sprintf(vol->bus_id, "0.%x.%04x", ssid, vol_parm->devno);
vol->blk_size = vol_parm->blk_size << 8;
vol->part_off = vol_parm->start_blk * vol->blk_size;
vol->part_size = blk_cnt * vol->blk_size;
vol->status = dev_from_busid(vol->bus_id, &vol->dev);
vol->sign = SIGN_VALID;
if (vol->status != DEV_ONLINE)
return;
vol->devnode = zg_devnode_create(vol->dev);
vol->fh = dfi_dump_open(vol->devnode);
vol_read(vol);
if ((vol->hdr.volnr == vol->nr) && (vol->hdr.mem_size != 0))
vol->sign = SIGN_ACTIVE;
if (vol->hdr.mvdump_sign != DF_S390_MAGIC) {
vol->sign = SIGN_INVALID;
l.dump_incomplete = 1;
}
if (strncmp(df_s390_dumper_magic(vol->dumper), "ZMULT64", 7) != 0) {
vol->sign = SIGN_INVALID;
l.dump_incomplete = 1;
}
if (vol->nr == 0)
l.hdr = vol->hdr;
if (*mem_off == l.hdr.mem_size) {
/* Unused volume */
vol->mem_start = 0;
vol->mem_end = 0;
if (vol->sign == SIGN_ACTIVE)
vol->sign = SIGN_VALID;
} else {
/* Used volume */
vol->mem_start = *mem_off;
vol->mem_end = *mem_off + PAGE_ALIGN(vol->part_size) -
DF_S390_HDR_SIZE - 1;
vol->mem_end = MIN(vol->mem_end, l.hdr.mem_size - 1);
if (vol->mem_end == l.hdr.mem_size - 1)
em_init(vol);
*mem_off += vol->mem_end - vol->mem_start + 1;
}
}
/*
* Print volume information
*/
static void vol_print(struct vol *vol)
{
STDERR(" Volume %i: %s (%s", vol->nr, vol->bus_id,
dev_status_str(vol->status));
if (vol->status == DEV_ONLINE)
STDERR("/%s)\n", dev_sign_str(vol->sign));
else
STDERR(")\n");
}
/*
* Print information for all volumes
*/
static void vol_print_all(void)
{
unsigned int i;
for (i = 0; i < l.table.vol_cnt; i++)
vol_print(&l.vol_vec[i]);
}
/*
* Add memory chunks
*/
static void mem_chunks_add(void)
{
unsigned int i;
for (i = 0; i < l.table.vol_cnt; i++) {
struct vol *vol = &l.vol_vec[i];
if (vol->sign != SIGN_ACTIVE)
continue;
dfi_mem_chunk_add(vol->mem_start,
vol->mem_end - vol->mem_start + 1,
vol, df_s390mv_mem_read, NULL);
}
}
/*
* Print hint for setting all offline volumes online
*/
static void vol_offline_msg(void)
{
unsigned int i, first = 1;
STDERR("\n");
STDERR("Set all devices online using:\n");
STDERR("# chccwdev -e ");
for (i = 0; i < l.table.vol_cnt; i++) {
if (l.vol_vec[i].status == DEV_OFFLINE) {
if (first)
first = 0;
else
STDERR(",");
STDERR("%s", l.vol_vec[i].bus_id);
}
}
STDERR("\n");
}
/*
* Print error for all undefined volumes
*/
static void vol_undefined_msg(void)
{
unsigned int i;
STDERR("\n");
STDERR("Ensure that the following devices are available to the "
"system:\n");
for (i = 0; i < l.table.vol_cnt; i++) {
if (l.vol_vec[i].status == DEV_UNDEFINED)
STDERR("* %s\n", l.vol_vec[i].bus_id);
}
}
/*
* Check that all volumes are in online state
*/
static int vol_online_check(void)
{
unsigned int i, offline = 0, undefined = 0;
for (i = 0; i < l.table.vol_cnt; i++) {
if (l.vol_vec[i].status == DEV_OFFLINE)
offline = 1;
if (l.vol_vec[i].status == DEV_UNDEFINED)
undefined = 1;
}
if (!offline && !undefined)
return 0;
STDERR("Found multi-volume dump tool:\n\n");
vol_print_all();
if (offline)
vol_offline_msg();
if (undefined)
vol_undefined_msg();
return -ENODEV;
}
/*
* Check if on device is a multi-volume dump
*/
static int mvdump_hdr_check(const char *file)
{
struct df_s390_hdr hdr;
struct zg_fh *fh;
int rc = -ENODEV;
fh = zg_open(file, O_RDONLY, ZG_CHECK);
if (zg_read(fh, &hdr, sizeof(hdr), ZG_CHECK_ERR) != sizeof(hdr))
goto fail;
if (hdr.magic != DF_S390_MAGIC)
goto fail;
if (hdr.mvdump_sign != DF_S390_MAGIC)
goto fail;
rc = 0;
fail:
zg_close(fh);
return rc;
}
/*
* Check if sysfs is available
*/
static void check_sysfs(void)
{
DIR *fh_dir;
fh_dir = opendir(SYSFS_BUSDIR);
if (!fh_dir)
ERR_EXIT_ERRNO("Could not open %s\n", SYSFS_BUSDIR);
closedir(fh_dir);
}
/*
* Print dump information (dfi operation)
*/
static void dfi_s390mvfo_dump(void)
{
vol_print_all();
}
/*
* Read dump tool from DASD and check if we have a multi-volume dump tool
*/
static int mv_dumper_read(void)
{
if (zg_ioctl(g.fh, BLKSSZGET, &l.blk_size, "BLKSSZGET",
ZG_CHECK_NONE) == -1)
return -ENODEV;
df_s390_dumper_read(g.fh, l.blk_size, &l.dumper);
if (memcmp(df_s390_dumper_magic(l.dumper), "ZMULT64", 7) != 0)
return -ENODEV;
table_read(g.fh, l.blk_size, &l.table);
return 0;
}
/*
* Initialize all volumes
*/
static void volumes_init(void)
{
u64 mem_off = 0;
unsigned int i;
check_sysfs();
for (i = 0; i < l.table.vol_cnt; i++) {
l.vol_vec[i].nr = i;
vol_init(&l.vol_vec[i], &l.table.vol_parm[i], l.table.ssid[i],
&mem_off);
}
if (mem_off != l.hdr.mem_size)
l.dump_incomplete = 1;
}
/*
* Open dump - If partition is specified open device instead
*/
static int open_dump(void)
{
const struct stat *stat = zg_stat(g.fh);
unsigned dev_minor;
enum zg_type type;
char *path;
type = zg_type(g.fh);
if (type != ZG_TYPE_DASD && type != ZG_TYPE_DASD_PART)
return -ENODEV;
if (type == ZG_TYPE_DASD_PART) {
dev_minor = minor(stat->st_rdev) - (minor(stat->st_rdev) % 4);
if (mvdump_hdr_check(zg_path(g.fh)) != 0)
return -ENODEV;
path = zg_devnode_create(makedev(major(stat->st_rdev),
dev_minor));
zg_close(g.fh);
g.fh = zg_open(path, O_RDONLY, ZG_CHECK);
}
if (mv_dumper_read() != 0)
return -ENODEV;
zg_close(g.fh);
return 0;
}
/*
* Initialize s390 multi-volume input dump format
*/
static int dfi_s390mv_init(void)
{
if (open_dump() != 0)
return -ENODEV;
volumes_init();
if (vol_online_check() != 0)
zg_exit(1);
if (l.hdr.mem_size == 0)
return -ENODEV;
df_s390_hdr_add(&l.hdr);
mem_chunks_add();
if (l.dump_incomplete)
return -EINVAL;
df_s390_cpu_info_add(&l.hdr, l.hdr.mem_end);
df_s390_em_add(&l.em);
return 0;
}
/*
* Initialize s390 multi-volume dump tool (for -d option)
*/
int dt_s390mv_init(void)
{
if (open_dump() != 0)
return -ENODEV;
volumes_init();
dt_arch_set(DFI_ARCH_64);
dt_version_set(df_s390_dumper_version(l.dumper));
dt_attr_mem_limit_set(df_s390_dumper_mem(&l.dumper));
dt_attr_force_set(df_s390_dumper_force(&l.dumper));
return 0;
}
/*
* s390 multi-volume dump tool info function (for -d option)
*/
void dt_s390mv_info(void)
{
vol_print_all();
}
/*
* S390 multi-volume DFI operations
*/
struct dfi dfi_s390mv = {
.name = "s390mv",
.init = dfi_s390mv_init,
.info_dump = dfi_s390mvfo_dump,
.feat_bits = DFI_FEAT_COPY | DFI_FEAT_SEEK,
};
+201
View File
@@ -0,0 +1,201 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* S390 tape dump input format
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/mtio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "zgetdump.h"
#define TAPE_BLK_SIZE 32768 /* Defined by zipl tape dumper */
/*
* File local static data
*
* blk_buf_addr: Memory address of last read memory block
* blk_buf: Content of the last read memory block
* blk: The next block number that will be read relative to blk_start
* blk_start: The absolute block number on the tape where the dump starts
*/
static struct {
char blk_buf[TAPE_BLK_SIZE];
u64 blk_buf_addr;
u64 blk;
int blk_start;
} l;
/*
* MT ioctls
*/
struct mtioctl {
int op;
const char *desc;
};
static struct mtioctl mt_fsfm = {MTFSFM, "forward space file"};
static struct mtioctl mt_bsr = {MTBSR, "backward space record"};
static struct mtioctl mt_tell = {MTTELL, "tell"};
static struct mtioctl mt_seek = {MTSEEK, "seek"};
/*
* Do MT ioctl with count argument
*/
static int mtioctl(struct mtioctl *op, int cnt, enum zg_check check)
{
struct mtop mtop;
mtop.mt_count = cnt;
mtop.mt_op = op->op;
return zg_ioctl(g.fh, MTIOCTOP, &mtop, op->desc, check);
}
/*
* Verify end marker
*/
static int em_verify(struct df_s390_em *em)
{
if ((memcmp(em->str, "DUMP_END", 8) == 0)) {
df_s390_em_add(em);
return 0;
} else {
return -EINVAL;
}
}
/*
* Verify dump header
*/
static void hdr_verify(struct df_s390_hdr *hdr)
{
if (hdr->magic != DF_S390_MAGIC)
ERR_EXIT("No valid dump found on tape");
if (hdr->volnr != 0) {
STDERR_PR("Found volume number: %d\n", hdr->volnr);
ERR_EXIT("Multi-volume dumps are no longer supported");
}
}
/*
* Seek to relative block number in dump (block 0 is the dump header)
*/
static void seek_blk(u64 blk)
{
if (l.blk == blk)
return;
mtioctl(&mt_seek, l.blk_start + blk, ZG_CHECK);
l.blk = blk;
}
/*
* Read memory from cartridge
*/
static void df_s390tape_mem_read(struct dfi_mem_chunk *mem_chunk, u64 addr,
void *buf, u64 cnt)
{
unsigned int copied = 0, size;
(void) mem_chunk;
u64 blk, off;
do {
blk = addr / TAPE_BLK_SIZE + 1;
if (addr >= l.blk_buf_addr + TAPE_BLK_SIZE ||
addr < l.blk_buf_addr) {
seek_blk(blk);
zg_read(g.fh, l.blk_buf, sizeof(l.blk_buf),
ZG_CHECK);
l.blk_buf_addr = (l.blk - 1) * TAPE_BLK_SIZE;
l.blk++;
}
off = addr - l.blk_buf_addr;
size = MIN(cnt - copied, TAPE_BLK_SIZE - off);
memcpy(buf + copied, &l.blk_buf[off], size);
addr += size;
copied += size;
} while (copied != cnt);
}
/*
* Initialize cache for memory read (block 0 is the dump header)
*/
static void mem_read_init(void)
{
mtioctl(&mt_seek, l.blk_start + 1, ZG_CHECK);
zg_read(g.fh, l.blk_buf, sizeof(l.blk_buf), ZG_CHECK);
l.blk_buf_addr = 0;
l.blk = 2;
}
/*
* Init a new tape volume
*/
static int vol_init(void)
{
struct df_s390_hdr hdr;
struct df_s390_em em;
int rc;
STDERR("Checking tape, this can take a while...\n");
/* Init dump header */
l.blk_start = mtioctl(&mt_tell, 1, ZG_CHECK);
zg_read(g.fh, &hdr, sizeof(hdr), ZG_CHECK);
hdr_verify(&hdr);
df_s390_hdr_add(&hdr);
dfi_mem_chunk_add(0, hdr.mem_size, NULL, df_s390tape_mem_read, NULL);
/* Init end marker */
mtioctl(&mt_fsfm, 1, ZG_CHECK_NONE);
mtioctl(&mt_bsr, 1, ZG_CHECK);
rc = zg_read(g.fh, &em, sizeof(em), ZG_CHECK_ERR);
if (rc != 8 && rc != 16)
return -EINVAL;
if (em_verify(&em) != 0)
return -EINVAL;
/* Init memory read & CPU info */
mem_read_init();
df_s390_cpu_info_add(&hdr, hdr.mem_size - 1);
return 0;
}
/*
* Exit function: Seek to block 0
*/
static void dfi_s390tape_exit(void)
{
seek_blk(0);
}
/*
* Initialize s390 tape DFI
*/
static int dfi_s390tape_init(void)
{
if (zg_type(g.fh) != ZG_TYPE_TAPE)
return -ENODEV;
if (vol_init() != 0)
return -EINVAL;
zg_atexit(dfi_s390tape_exit);
return 0;
}
/*
* S390 tape DFI operations
*/
struct dfi dfi_s390tape = {
.name = "s390tape",
.init = dfi_s390tape_init,
.feat_bits = DFI_FEAT_SEEK | DFI_FEAT_COPY,
};
+209
View File
@@ -0,0 +1,209 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* vmcoreinfo access functions
*
* Copyright IBM Corp. 2011, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <elf.h>
#include "zgetdump.h"
#ifdef __s390x__
#define LC_VMCORE_INFO 0xe0c
#else
#define LC_VMCORE_INFO 0xe08
#endif
#define LC_OS_INFO 0xe18
#define OS_INFO_MAGIC 0x4f53494e464f535aULL /* OSINFOSZ */
struct os_info {
u64 magic;
u32 csum;
u16 version_major;
u16 version_minor;
u64 crashkernel_addr;
u64 crashkernel_size;
u64 vmcoreinfo_addr;
u64 vmcoreinfo_size;
u32 vmcoreinfo_csum;
u64 reipl_block_addr;
u64 reipl_block_size;
u32 reipl_block_csum;
u64 init_fn_addr;
u64 init_fn_size;
u32 init_fn_csum;
u8 reserved[4004];
} __attribute__ ((packed));
/*
* File local static data
*/
static struct {
char *vmcoreinfo;
struct os_info *os_info;
} l;
static u32 os_info_csum(struct os_info *os_info)
{
int size = sizeof(*os_info) - offsetof(struct os_info, version_major);
return zg_csum_partial(&os_info->version_major, size, 0);
}
static struct os_info *os_info_get(void)
{
static struct os_info os_info;
unsigned long addr;
dfi_mem_read(LC_OS_INFO, &addr, sizeof(addr));
if (addr % 0x1000)
return NULL;
if (dfi_mem_read_rc(addr, &os_info, sizeof(os_info)))
return NULL;
if (os_info.magic != OS_INFO_MAGIC)
return NULL;
if (os_info.csum != os_info_csum(&os_info))
return NULL;
return &os_info;
}
/*
* Initialize vmcoreinfo
*/
void dfi_vmcoreinfo_init(void)
{
unsigned long addr, size;
Elf64_Nhdr note;
char str[128];
l.os_info = os_info_get();
if (l.os_info && l.os_info->vmcoreinfo_size) {
addr = l.os_info->vmcoreinfo_addr;
size = l.os_info->vmcoreinfo_size;
} else {
dfi_mem_read(LC_VMCORE_INFO, &addr, sizeof(addr));
if (addr == 0)
return;
if (dfi_mem_read_rc(addr, &note, sizeof(note)))
return;
memset(str, 0, sizeof(str));
if (dfi_mem_read_rc(addr + sizeof(note), str, note.n_namesz))
return;
if (memcmp(str, "VMCOREINFO", sizeof("VMCOREINFO")) != 0)
return;
size = note.n_descsz;
addr += 24;
}
l.vmcoreinfo = zg_alloc(size + 1);
if (dfi_mem_read_rc(addr, l.vmcoreinfo, size)) {
zg_free(l.vmcoreinfo);
l.vmcoreinfo = NULL;
return;
}
l.vmcoreinfo[size] = 0;
}
/*
* Return vmcoreinfo data
*/
char *dfi_vmcoreinfo_get(void)
{
return l.vmcoreinfo;
}
/*
* Generic function: Return vmcoreinfo item (-1 on failure)
*/
static int vmcoreinfo_item(char *buf, int UNUSED(len), const char *fmt,
const char *sym)
{
char str[1024], *sym_str, *sym_str_end;
if (!l.vmcoreinfo)
return -1;
if (fmt)
snprintf(str, sizeof(str), "%s(%s)=", fmt, sym);
else
snprintf(str, sizeof(str), "%s=", sym);
sym_str = strstr(l.vmcoreinfo, str);
if (!sym_str)
return -1;
sym_str += strlen(str);
sym_str_end = strchr(sym_str, '\n');
if (!sym_str_end)
sym_str_end = strchr(sym_str, '\0');
memset(str, 0, sizeof(str));
memcpy(str, sym_str, (unsigned long) (sym_str_end - sym_str));
strcpy(buf, str);
return 0;
}
/*
* Generic function: Return vmcoreinfo ulong item (-1 on failure)
*/
static int vmcoreinfo_item_ulong(unsigned long *val, const char *fmt,
const char *sym, unsigned long base)
{
char str[1024];
int rc;
rc = vmcoreinfo_item(str, sizeof(str), fmt, sym);
if (rc)
return rc;
*val = strtoul(str, NULL, base);
return 0;
}
/*
* Return vmcoreinfo tag (-1 on failure)
*/
int dfi_vmcoreinfo_tag(char *str, int len, const char *sym)
{
return vmcoreinfo_item(str, len, NULL, sym);
}
/*
* Return vmcoreinfo symbol address (-1 on failure)
*/
int dfi_vmcoreinfo_symbol(unsigned long *addr, const char *sym)
{
return vmcoreinfo_item_ulong(addr, "SYMBOL", sym, 16);
}
/*
* Return vmcoreinfo offset of a member of a datastructure (-1 on failure)
*/
int dfi_vmcoreinfo_offset(unsigned long *off, const char *sym)
{
return vmcoreinfo_item_ulong(off, "OFFSET", sym, 10);
}
/*
* Return vmcoreinfo datatype size (-1 on failure)
*/
int dfi_vmcoreinfo_size(unsigned long *size, const char *sym)
{
return vmcoreinfo_item_ulong(size, "SIZE", sym, 10);
}
/*
* Return vmcoreinfo symbol length (-1 on failure)
*/
int dfi_vmcoreinfo_length(unsigned long *len, const char *sym)
{
return vmcoreinfo_item_ulong(len, "LENGTH", sym, 10);
}
/*
* Return vmcoreinfo number (-1 on failure)
*/
int dfi_vmcoreinfo_val(unsigned long *val, const char *sym)
{
return vmcoreinfo_item_ulong(val, NULL, sym, 10);
}
+206
View File
@@ -0,0 +1,206 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* Generic output dump format functions (DFO - Dump Format Output)
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <time.h>
#include "zgetdump.h"
#define dfo_chunk_iterate(dfo_chunk) \
util_list_iterate(&l.dump.chunk_list, dfo_chunk)
/*
* DFO vector
*/
static struct dfo *dfo_vec[] = {
&dfo_s390,
&dfo_elf,
NULL,
};
/*
* Dump (output) information
*/
struct dump {
u64 off; /* Current file offset in dump */
u64 size; /* Size of dump in bytes */
unsigned int chunk_cnt; /* Number of dump chunks */
struct util_list chunk_list; /* DFO chunk list */
};
/*
* File local static data
*/
static struct {
struct dump dump;
struct dfo *dfo;
} l;
/*
* Add dump chunk
*/
void dfo_chunk_add(u64 start, u64 size, void *data, dfo_chunk_read_fn read_fn)
{
struct dfo_chunk *dfo_chunk;
dfo_chunk = zg_alloc(sizeof(*dfo_chunk));
dfo_chunk->start = start;
dfo_chunk->end = start + size - 1;
dfo_chunk->size = size;
dfo_chunk->data = data;
dfo_chunk->read_fn = read_fn;
util_list_add_head(&l.dump.chunk_list, dfo_chunk);
l.dump.chunk_cnt++;
l.dump.size = MAX(l.dump.size, dfo_chunk->end + 1);
}
/*
* Dump chunk function: Copy zero pages for chunk
*/
void dfo_chunk_zero_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
{
(void) dfo_chunk;
(void) off;
memset(buf, 0, cnt);
}
/*
* Dump chunk function: Copy given buffer for chunk
*/
void dfo_chunk_buf_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
{
memcpy(buf, dfo_chunk->data + off, cnt);
}
/*
* Dump chunk function: Copy given memory range for chunk
*/
void dfo_chunk_mem_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
{
struct dfi_mem_chunk *mem_chunk = dfo_chunk->data;
mem_chunk->read_fn(mem_chunk, off, buf, cnt);
}
/*
* Get DFO name
*/
const char *dfo_name(void)
{
return l.dfo->name;
}
/*
* Set DFO by name
*/
int dfo_set(const char *dfo_name)
{
struct dfo *dfo;
int i = 0;
while ((dfo = dfo_vec[i])) {
if (strcmp(dfo->name, dfo_name) == 0) {
l.dfo = dfo;
return 0;
}
i++;
}
return -ENODEV;
}
/*
* Initialize output dump format
*/
void dfo_init(void)
{
if (!l.dfo)
ABORT("DFO not set");
util_list_init(&l.dump.chunk_list, struct dfo_chunk, list);
l.dfo->init();
}
/*
* Find dump chunk for offset "off"
*
* This function is a bit hacky. DFO chunks can overlap. If two DFO chunks
* overlap, the last registered chunk wins. The dfo_chunk_find() function
* reflects that by returning the first memory chunk that is found in
* the dfo chunk list.
*
* In addition to that it calculates the "virtual end" of that chunk. An
* overlapping chunk can limit the "virtual end" of an underlying chunk so
* that the "virtual end" of that chunk is lower than the "real end".
*
* Example:
*
* chunk 1.: |------|
* chunk 2.: |---------------------|
* off.....: ^
* virt end: ^
* real end: ^
*
* In this case chunk 2 will be returned and "end" is set to the start of
* chunk 1.
*/
static struct dfo_chunk *dfo_chunk_find(u64 off, u64 *end)
{
struct dfo_chunk *dfo_chunk;
*end = U64_MAX;
dfo_chunk_iterate(dfo_chunk) {
if (dfo_chunk->start <= off && dfo_chunk->end >= off) {
*end = MIN(*end, dfo_chunk->end);
return dfo_chunk;
} else if (dfo_chunk->start > off) {
*end = MIN(*end, dfo_chunk->start - 1);
}
}
return NULL;
}
/*
* Seek to output dump offset "off"
*/
void dfo_seek(u64 off)
{
l.dump.off = off;
}
/*
* Read "cnt" bytes of output dump at current offest
*/
u64 dfo_read(void *buf, u64 cnt)
{
struct dfo_chunk *dfo_chunk;
u64 copied = 0, end, size;
u64 off = l.dump.off;
while (copied != cnt) {
dfo_chunk = dfo_chunk_find(off, &end);
if (!dfo_chunk)
goto out;
size = MIN(cnt - copied, end - off + 1);
dfo_chunk->read_fn(dfo_chunk, off - dfo_chunk->start,
buf + copied, size);
copied += size;
off += size;
}
out:
l.dump.off = off;
return copied;
}
/*
* Return output dump size
*/
u64 dfo_size(void)
{
return l.dump.size;
}
+56
View File
@@ -0,0 +1,56 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* Generic output dump format functions (DFO - Dump Format Output)
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef DFO_H
#define DFO_H
#include "lib/util_list.h"
#include "zg.h"
struct dfo_chunk;
typedef void (*dfo_chunk_read_fn)(struct dfo_chunk *chunk, u64 off,
void *buf, u64 cnt);
struct dfo_chunk {
struct util_list_node list;
u64 start;
u64 end;
u64 size;
dfo_chunk_read_fn read_fn;
void *data;
};
extern void dfo_chunk_zero_fn(struct dfo_chunk *chunk, u64 off, void *buf,
u64 cnt);
extern void dfo_chunk_buf_fn(struct dfo_chunk *chunk, u64 off, void *buf,
u64 cnt);
extern void dfo_chunk_mem_fn(struct dfo_chunk *chunk, u64 off, void *buf,
u64 cnt);
extern void dfo_chunk_add(u64 start, u64 size, void *data,
dfo_chunk_read_fn read_fn);
extern u64 dfo_read(void *buf, u64 cnt);
extern void dfo_seek(u64 addr);
extern u64 dfo_size(void);
extern const char *dfo_name(void);
extern void dfo_init(void);
extern int dfo_set(const char *dfo_name);
/*
* DFO operations
*/
struct dfo {
const char *name;
void (*init)(void);
};
#endif /* DFO_H */
+337
View File
@@ -0,0 +1,337 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* ELF core dump output format
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <assert.h>
#include <elf.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "zgetdump.h"
#define HDR_PER_CPU_SIZE 0x4a0
#define HDR_PER_MEMC_SIZE 0x100
#define HDR_BASE_SIZE 0x2000
/*
* File local static data
*/
static struct {
void *hdr;
u32 hdr_size;
} l;
/*
* Initialize ELF header
*/
static void *ehdr_init(Elf64_Ehdr *ehdr)
{
memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
ehdr->e_ident[EI_CLASS] = ELFCLASS64;
ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
ehdr->e_ident[EI_ABIVERSION] = 0;
memset(ehdr->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
ehdr->e_type = ET_CORE;
ehdr->e_machine = EM_S390;
ehdr->e_version = EV_CURRENT;
ehdr->e_entry = 0;
ehdr->e_phoff = sizeof(Elf64_Ehdr);
ehdr->e_shoff = 0;
ehdr->e_flags = 0;
ehdr->e_ehsize = sizeof(Elf64_Ehdr);
ehdr->e_phentsize = sizeof(Elf64_Phdr);
ehdr->e_phnum = dfi_mem_chunk_cnt() + 1;
ehdr->e_shentsize = 0;
ehdr->e_shnum = 0;
ehdr->e_shstrndx = 0;
return ehdr + 1;
}
/*
* Initialize ELF loads
*/
static u64 loads_init(Elf64_Phdr *phdr, u64 loads_offset)
{
struct dfi_mem_chunk *mem_chunk;
u64 mem_size = 0;
dfi_mem_chunk_iterate(mem_chunk) {
phdr->p_type = PT_LOAD;
phdr->p_offset = loads_offset;
phdr->p_vaddr = mem_chunk->start;
phdr->p_paddr = mem_chunk->start;
phdr->p_filesz = mem_chunk->end - mem_chunk->start + 1;
phdr->p_memsz = phdr->p_filesz;
phdr->p_flags = PF_R | PF_W | PF_X;
phdr->p_align = PAGE_SIZE;
loads_offset += phdr->p_filesz;
mem_size += phdr->p_memsz;
phdr++;
}
return mem_size;
}
/*
* Initialize ELF note
*/
static void *nt_init(void *buf, Elf64_Word type, void *desc, int d_len,
const char *name)
{
Elf64_Nhdr *note;
u64 len;
note = (Elf64_Nhdr *)buf;
note->n_namesz = strlen(name) + 1;
note->n_descsz = d_len;
note->n_type = type;
len = sizeof(Elf64_Nhdr);
memcpy(buf + len, name, note->n_namesz);
len = ROUNDUP(len + note->n_namesz, 4);
memcpy(buf + len, desc, note->n_descsz);
len = ROUNDUP(len + note->n_descsz, 4);
return PTR_ADD(buf, len);
}
/*
* Initialize prstatus note
*/
static void *nt_prstatus(void *ptr, struct dfi_cpu *cpu)
{
struct nt_prstatus_64 nt_prstatus;
static int cpu_nr = 1;
memset(&nt_prstatus, 0, sizeof(nt_prstatus));
memcpy(&nt_prstatus.gprs, cpu->gprs, sizeof(cpu->gprs));
memcpy(&nt_prstatus.psw, cpu->psw, sizeof(cpu->psw));
memcpy(&nt_prstatus.acrs, cpu->acrs, sizeof(cpu->acrs));
nt_prstatus.pr_pid = cpu_nr;
cpu_nr++;
return nt_init(ptr, NT_PRSTATUS, &nt_prstatus, sizeof(nt_prstatus),
"CORE");
}
/*
* Initialize fpregset (floating point) note
*/
static void *nt_fpregset(void *ptr, struct dfi_cpu *cpu)
{
struct nt_fpregset_64 nt_fpregset;
memset(&nt_fpregset, 0, sizeof(nt_fpregset));
memcpy(&nt_fpregset.fpc, &cpu->fpc, sizeof(cpu->fpc));
memcpy(&nt_fpregset.fprs, &cpu->fprs, sizeof(cpu->fprs));
return nt_init(ptr, NT_FPREGSET, &nt_fpregset, sizeof(nt_fpregset),
"CORE");
}
/*
* Initialize timer note
*/
static void *nt_s390_timer(void *ptr, struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_TIMER, &cpu->timer, sizeof(cpu->timer),
"LINUX");
}
/*
* Initialize TOD clock comparator note
*/
static void *nt_s390_tod_cmp(void *ptr, struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_TODCMP, &cpu->todcmp,
sizeof(cpu->todcmp), "LINUX");
}
/*
* Initialize TOD programmable register note
*/
static void *nt_s390_tod_preg(void *ptr, struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_TODPREG, &cpu->todpreg,
sizeof(cpu->todpreg), "LINUX");
}
/*
* Initialize control register note
*/
static void *nt_s390_ctrs(void *ptr, struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_CTRS, &cpu->ctrs, sizeof(cpu->ctrs),
"LINUX");
}
/*
* Initialize prefix register note
*/
static void *nt_s390_prefix(void *ptr, struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_PREFIX, &cpu->prefix,
sizeof(cpu->prefix), "LINUX");
}
/*
* Initialize vxrs_low register note
*/
static void *nt_s390_vxrs_low(void *ptr, struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_VXRS_LOW, &cpu->vxrs_low,
sizeof(cpu->vxrs_low), "LINUX");
}
/*
* Initialize vxrs_high register note
*/
static void *nt_s390_vxrs_high(void *ptr, struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_VXRS_HIGH, &cpu->vxrs_high,
sizeof(cpu->vxrs_high), "LINUX");
}
/*
* Initialize prpsinfo note
*/
static void *nt_prpsinfo(void *ptr)
{
struct nt_prpsinfo_64 prpsinfo;
memset(&prpsinfo, 0, sizeof(prpsinfo));
prpsinfo.pr_state = 0;
prpsinfo.pr_sname = 'R';
prpsinfo.pr_zomb = 0;
strcpy(prpsinfo.pr_fname, "vmlinux");
return nt_init(ptr, NT_PRPSINFO, &prpsinfo, sizeof(prpsinfo), "CORE");
}
/*
* Initialize vmcoreinfo note
*/
static void *nt_vmcoreinfo(void *ptr)
{
char *vmcoreinfo = dfi_vmcoreinfo_get();
if (!vmcoreinfo)
return ptr;
return nt_init(ptr, 0, vmcoreinfo, strlen(vmcoreinfo), "VMCOREINFO");
}
/*
* Initialize notes
*/
static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
{
void *ptr_start = ptr;
struct dfi_cpu *cpu;
ptr = nt_prpsinfo(ptr);
if (dfi_cpu_content() != DFI_CPU_CONTENT_ALL)
goto out;
dfi_cpu_iterate(cpu) {
ptr = nt_prstatus(ptr, cpu);
ptr = nt_fpregset(ptr, cpu);
ptr = nt_s390_timer(ptr, cpu);
ptr = nt_s390_tod_cmp(ptr, cpu);
ptr = nt_s390_tod_preg(ptr, cpu);
ptr = nt_s390_ctrs(ptr, cpu);
ptr = nt_s390_prefix(ptr, cpu);
if (dfi_cpu_content_fac_check(DFI_CPU_CONTENT_FAC_VX)) {
ptr = nt_s390_vxrs_low(ptr, cpu);
ptr = nt_s390_vxrs_high(ptr, cpu);
}
}
out:
ptr = nt_vmcoreinfo(ptr);
memset(phdr, 0, sizeof(*phdr));
phdr->p_type = PT_NOTE;
phdr->p_offset = notes_offset;
phdr->p_filesz = (unsigned long) PTR_SUB(ptr, ptr_start);
return ptr;
}
/*
* Setup dump chunks
*/
static void dump_chunks_init(void)
{
struct dfi_mem_chunk *mem_chunk;
u64 off = 0;
dfo_chunk_add(0, l.hdr_size, l.hdr, dfo_chunk_buf_fn);
off = l.hdr_size;
dfi_mem_chunk_iterate(mem_chunk) {
dfo_chunk_add(off, mem_chunk->size, mem_chunk,
dfo_chunk_mem_fn);
off += mem_chunk->size;
}
}
/*
* ELF DFO is only supported for 64 bit (s390x)
*/
static void ensure_s390x(void)
{
if (dfi_arch() != DFI_ARCH_64)
ERR_EXIT("Error: The ELF dump format is only supported for "
"s390x source dumps");
df_elf_ensure_s390x();
}
/*
* Initialize ELF output dump format
*/
static void dfo_elf_init(void)
{
Elf64_Phdr *phdr_notes, *phdr_loads;
u32 alloc_size;
u64 hdr_off;
void *ptr;
ensure_s390x();
alloc_size = HDR_BASE_SIZE +
dfi_cpu_cnt() * HDR_PER_CPU_SIZE +
dfi_mem_chunk_cnt() * HDR_PER_MEMC_SIZE;
l.hdr = zg_alloc(alloc_size);
/* Init elf header */
ptr = ehdr_init(l.hdr);
/* Init program headers */
phdr_notes = ptr;
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr));
phdr_loads = ptr;
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr) * dfi_mem_chunk_cnt());
/* Init notes */
hdr_off = PTR_DIFF(ptr, l.hdr);
ptr = notes_init(phdr_notes, ptr, hdr_off);
/* Init loads */
hdr_off = PTR_DIFF(ptr, l.hdr);
loads_init(phdr_loads, hdr_off);
l.hdr_size = hdr_off;
if (l.hdr_size > alloc_size)
ABORT("hdr_size=%u alloc_size=%u", l.hdr_size, alloc_size);
dump_chunks_init();
}
/*
* ELF DFO operations
*/
struct dfo dfo_elf = {
.name = "elf",
.init = dfo_elf_init,
};
+234
View File
@@ -0,0 +1,234 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* S390 dump output format
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "zgetdump.h"
/*
* File local static data
*/
static struct {
struct df_s390_hdr hdr;
struct df_s390_em em;
} l;
/*
* Copy internal register set to 64 bit lowcore
*/
static void cpu2lc_64(void *lc_64, struct dfi_cpu *cpu)
{
struct dfi_lowcore_64 *lc = lc_64;
memcpy(lc->gpregs_save_area, &cpu->gprs, sizeof(cpu->gprs));
memcpy(lc->cregs_save_area, &cpu->ctrs, sizeof(cpu->ctrs));
memcpy(lc->access_regs_save_area, &cpu->acrs, sizeof(cpu->acrs));
memcpy(lc->floating_pt_save_area, &cpu->fprs, sizeof(cpu->fprs));
memcpy(&lc->fpt_creg_save_area, &cpu->fpc, sizeof(cpu->fpc));
memcpy(lc->st_status_fixed_logout, &cpu->psw, sizeof(cpu->psw));
memcpy(&lc->prefixreg_save_area, &cpu->prefix, sizeof(cpu->prefix));
memcpy(lc->timer_save_area, &cpu->timer, sizeof(cpu->timer));
memcpy(lc->clock_comp_save_area, &cpu->todcmp, sizeof(cpu->todcmp));
}
/*
* Copy internal register set to 32 bit lowcore
*/
static void cpu2lc_32(void *lc_32, struct dfi_cpu *cpu_64)
{
struct dfi_lowcore_32 *lc = lc_32;
struct dfi_cpu_32 cpu;
dfi_cpu_64_to_32(&cpu, cpu_64);
memcpy(lc->gpregs_save_area, &cpu.gprs, sizeof(cpu.gprs));
memcpy(lc->cregs_save_area, &cpu.ctrs, sizeof(cpu.ctrs));
memcpy(lc->access_regs_save_area, &cpu.acrs, sizeof(cpu.acrs));
memcpy(lc->floating_pt_save_area, &cpu.fprs, sizeof(cpu.fprs));
memcpy(lc->st_status_fixed_logout, &cpu.psw, sizeof(cpu.psw));
memcpy(&lc->prefixreg_save_area, &cpu.prefix, sizeof(cpu.prefix));
memcpy(lc->timer_save_area, &cpu.timer, sizeof(cpu.timer));
memcpy(lc->clock_comp_save_area, &cpu.todcmp, sizeof(cpu.todcmp));
}
/*
* Convert timeval to s390 TOD clock
*/
static void timeval2tod(u64 *tod, struct timeval *xtime)
{
u64 us = xtime->tv_sec * 1000000 + xtime->tv_usec;
*tod = (us << 12);
*tod += 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
}
/*
* Setup lowcore array in dump header
*/
static void lc_setup(struct df_s390_hdr *dh)
{
struct dfi_cpu *cpu;
unsigned int i = 0;
dfi_cpu_iterate(cpu) {
if (i >= DF_S390_CPU_MAX)
ERR_EXIT("Too many CPUs in source dump (%i)", i);
dh->lc_vec[i] = cpu->prefix;
i++;
}
}
/*
* Copy register set to prefix page
*/
static void dfo_s390_dump_chunk_lc_fn(struct dfo_chunk *dump_chunk,
u64 off, void *buf, u64 cnt)
{
struct dfi_cpu *cpu = dump_chunk->data;
char lc[0x2000];
dfi_mem_read(cpu->prefix + off, &lc[off], cnt);
if (dfi_arch() == DFI_ARCH_64)
cpu2lc_64(lc, cpu);
else
cpu2lc_32(lc, cpu);
memcpy(buf, &lc[off], cnt);
}
/*
* Copy register set to prefix page
*/
static void dfo_s390_dump_chunk_vx_fn(struct dfo_chunk *dump_chunk,
u64 off, void *buf, u64 cnt)
{
char *vx_regs = dump_chunk->data;
memcpy(buf, &vx_regs[off], cnt);
}
/*
* Add register set to dump layout. We copy the register sets to the
* lowcore pages.
*/
static void add_cpu_to_dfo(struct dfi_cpu *cpu)
{
struct dfi_lowcore_64 lc;
void *vx_regs;
if (dfi_cpu_content() != DFI_CPU_CONTENT_ALL)
return;
if (!dfi_mem_range_valid(cpu->prefix, dfi_lc_size(dfi_arch()))) {
STDERR("Info: Could not read CPU prefix page: %x\n",
cpu->prefix);
return;
}
/* Add lowcore to memory */
dfo_chunk_add(cpu->prefix + DF_S390_HDR_SIZE,
dfi_lc_size(dfi_arch()), cpu,
dfo_s390_dump_chunk_lc_fn);
/* Add VX save area to memory */
if (dfi_arch() != DFI_ARCH_64)
return;
if (!dfi_cpu_content_fac_check(DFI_CPU_CONTENT_FAC_VX))
return;
dfi_mem_read(cpu->prefix, &lc, sizeof(lc));
if (!dfi_cpu_lc_has_vx_sa(&lc))
return;
vx_regs = zg_alloc(DFI_VX_SA_SIZE);
dfi_cpu_vx_copy(vx_regs, cpu);
dfo_chunk_add(lc.vector_save_area_addr + DF_S390_HDR_SIZE,
DFI_VX_SA_SIZE, vx_regs, dfo_s390_dump_chunk_vx_fn);
}
/*
* Add memory chunk to dump layout
*/
static void add_mem_chunk_to_dfo(struct dfi_mem_chunk *mem_chunk)
{
struct dfi_mem_chunk *mem_chunk_prev = dfi_mem_chunk_prev(mem_chunk);
if (mem_chunk_prev && (mem_chunk_prev->end + 1 != mem_chunk->start))
dfo_chunk_add(mem_chunk_prev->end + 1 + DF_S390_HDR_SIZE,
mem_chunk->start - mem_chunk_prev->end - 1,
NULL, dfo_chunk_zero_fn);
dfo_chunk_add(mem_chunk->start + DF_S390_HDR_SIZE, mem_chunk->size,
mem_chunk, dfo_chunk_mem_fn);
}
/*
* Setup dump chunks
*/
static void dump_chunks_init(void)
{
struct dfi_mem_chunk *mem_chunk;
struct dfi_cpu *cpu;
dfo_chunk_add(0, DF_S390_HDR_SIZE, &l.hdr, dfo_chunk_buf_fn);
dfi_mem_chunk_iterate(mem_chunk)
add_mem_chunk_to_dfo(mem_chunk);
dfi_cpu_iterate(cpu)
add_cpu_to_dfo(cpu);
dfo_chunk_add(dfi_mem_range() + DF_S390_HDR_SIZE,
DF_S390_EM_SIZE,
&l.em, dfo_chunk_buf_fn);
}
/*
* Initialize s390 output dump format
*/
static void df_s390_dump_init(void)
{
struct df_s390_hdr *dh = &l.hdr;
struct df_s390_em *em = &l.em;
dh->magic = DF_S390_MAGIC;
dh->hdr_size = DF_S390_HDR_SIZE;
dh->page_size = PAGE_SIZE;
dh->dump_level = 4;
if (dfi_cpu_content() == DFI_CPU_CONTENT_NONE)
dh->version = 4;
else
dh->version = 5;
dh->mem_start = 0;
dh->mem_size = dh->mem_end = dfi_mem_range();
dh->num_pages = dh->mem_size / PAGE_SIZE;
dh->arch = df_s390_from_dfi_arch(dfi_arch());
if (dfi_attr_build_arch())
dh->build_arch = df_s390_from_dfi_arch(*dfi_attr_build_arch());
dh->cpu_cnt = dfi_cpu_cnt();
if (dfi_attr_real_cpu_cnt())
dh->real_cpu_cnt = *dfi_attr_real_cpu_cnt();
if (dfi_attr_cpu_id())
dh->cpu_id = *dfi_attr_cpu_id();
if (dfi_attr_mem_size_real())
dh->mem_size_real = *dfi_attr_mem_size_real();
if (dfi_attr_time()) {
timeval2tod(&dh->tod, dfi_attr_time());
timeval2tod(&em->tod, dfi_attr_time());
}
if (dfi_attr_time_end())
timeval2tod(&em->tod, dfi_attr_time_end());
lc_setup(dh);
memcpy(em->str, DF_S390_EM_STR, sizeof(em->str));
dump_chunks_init();
}
/*
* S390 DFO operations
*/
struct dfo dfo_s390 = {
.name = "s390",
.init = df_s390_dump_init,
};
+137
View File
@@ -0,0 +1,137 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* Dump tool info generic functions
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include "zgetdump.h"
/*
* Supported dump tools
*/
static struct dt *dt_vec[] = {
&dt_s390mv,
&dt_s390sv,
&dt_scsi,
NULL,
};
/*
* Dumper attribute information
*/
struct attr {
int *force;
u64 *mem_limit;
char *dasd_type;
};
/*
* File local static data
*/
static struct {
int version;
enum dfi_arch arch;
struct attr attr;
struct dt *dt;
} l;
/*
* Init dump tool backends
*/
void dt_init(void)
{
struct dt *dt;
int i = 0;
while ((dt = dt_vec[i])) {
g.fh = zg_open(g.opts.device, O_RDONLY, ZG_CHECK);
if (!S_ISBLK(g.fh->sb.st_mode))
ERR_EXIT("Please specify DASD or SCSI device node"
"(e.g. /dev/dasdd or /dev/sda )");
if (dt->init() == 0) {
l.dt = dt;
return;
}
zg_close(g.fh);
i++;
}
ERR_EXIT("No dump tool found on \"%s\"", g.opts.device);
}
/*
* Print info about dump tool
*/
void dt_info_print(void)
{
STDERR("Dump device info:\n");
STDERR(" Dump tool.........: %s\n", l.dt->desc);
STDERR(" Version...........: %d\n", l.version);
STDERR(" Architecture......: %s\n", dfi_arch_str(l.arch));
if (l.attr.dasd_type)
STDERR(" DASD type.........: %s\n", l.attr.dasd_type);
if (l.attr.mem_limit) {
if (*l.attr.mem_limit != U64_MAX)
STDERR(" Dump size limit...: %lld MB\n",
TO_MIB(*l.attr.mem_limit));
else
STDERR(" Dump size limit...: none\n");
}
if (l.attr.force) {
if (*l.attr.force == 0)
STDERR(" Force specified...: no\n");
else
STDERR(" Force specified...: yes\n");
}
if (l.dt->info) {
STDERR("\n");
l.dt->info();
}
}
/*
* Set DT architecture
*/
void dt_arch_set(enum dfi_arch arch)
{
l.arch = arch;
}
/*
* Set DT version
*/
void dt_version_set(int version)
{
l.version = version;
}
/*
* Set DT memory limit attribute
*/
void dt_attr_mem_limit_set(u64 mem_limit)
{
l.attr.mem_limit = zg_alloc(sizeof(*l.attr.mem_limit));
*l.attr.mem_limit = mem_limit;
}
/*
* Set DT force attribute
*/
void dt_attr_force_set(int force)
{
l.attr.force = zg_alloc(sizeof(*l.attr.force));
*l.attr.force = force;
}
/*
* Set DT DASD type attribute
*/
void dt_attr_dasd_type_set(const char *dasd_type)
{
l.attr.dasd_type = zg_strdup(dasd_type);
}
+31
View File
@@ -0,0 +1,31 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* Dump tool info generic functions
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef DT_H
#define DT_H
#include "dfi.h"
struct dt {
const char *desc;
int (*init)(void);
void (*info)(void);
};
extern void dt_init(void);
extern void dt_info_print(void);
extern void dt_arch_set(enum dfi_arch arch);
extern void dt_version_set(int version);
extern void dt_attr_mem_limit_set(u64 mem_limit);
extern void dt_attr_force_set(int value);
extern void dt_attr_dasd_type_set(const char *dasd_type);
#endif
+21
View File
@@ -0,0 +1,21 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* S390 multi-volume DASD dump tool
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include "zgetdump.h"
/*
* DT operations
*/
struct dt dt_s390mv = {
.desc = "Multi-volume DASD dump tool",
.init = dt_s390mv_init,
.info = dt_s390mv_info,
};
+135
View File
@@ -0,0 +1,135 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* S390 single-volume DASD dump tool
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <linux/fs.h>
#include "zgetdump.h"
#define HEXINSTR "\x0d\x10\x47\xf0" /* BASR + 1st halfword of BC */
/*
* File local static data
*/
static struct {
struct df_s390_dumper dumper;
enum dfi_arch dumper_arch;
} l;
/*
* Read dump tool from ECKD DASD device
*/
static int dumper_read_eckd(int blk_size)
{
df_s390_dumper_read(g.fh, blk_size, &l.dumper);
if (strncmp(l.dumper.magic, "ZECKD31", 7) == 0) {
l.dumper_arch = DFI_ARCH_32;
} else if (strncmp(l.dumper.magic, "ZECKD64", 7) == 0) {
l.dumper_arch = DFI_ARCH_64;
} else if ((memcmp(l.dumper.magic, HEXINSTR, 4) == 0) &&
(l.dumper.d.v1.code[0] == '\x0d') &&
(l.dumper.d.v1.code[1] == '\xd0')) {
/* We found basr r13,0 (old dumper) */
l.dumper.version = 0;
l.dumper_arch = DFI_ARCH_UNKNOWN;
} else {
return -ENODEV;
}
return 0;
}
/*
* Read dump tool from FBA DASD device
*/
static void dumper_read_fba_gen(int size, void *buffer)
{
zg_seek_end(g.fh, -size, ZG_CHECK);
zg_read(g.fh, buffer, size, ZG_CHECK);
}
/*
* Read dump tool on FBA disk and check its magic number
*/
static int dumper_check_fba(void)
{
if (strncmp(l.dumper.magic, "ZDFBA31", 7) == 0) {
l.dumper_arch = DFI_ARCH_32;
} else if (strncmp(l.dumper.magic, "ZDFBA64", 7) == 0) {
l.dumper_arch = DFI_ARCH_64;
} else if ((memcmp(l.dumper.magic, HEXINSTR, 4) == 0) &&
(l.dumper.d.v1.code[0] == '\x0d') &&
(l.dumper.d.v1.code[1] == '\xd0')) {
/* We found basr r13,0 (old dumper) */
l.dumper.version = 0;
l.dumper_arch = DFI_ARCH_UNKNOWN;
} else {
return -ENODEV;
}
return 0;
}
/*
* Read dump tool on FBA disk and check its magic number
*/
static int dumper_read_fba(void)
{
dumper_read_fba_gen(DF_S390_DUMPER_SIZE_V1, &l.dumper);
if (dumper_check_fba() == 0)
return 0;
dumper_read_fba_gen(DF_S390_DUMPER_SIZE_V2, &l.dumper);
if (dumper_check_fba() == 0)
return 0;
dumper_read_fba_gen(DF_S390_DUMPER_SIZE_V3, &l.dumper);
if (dumper_check_fba() == 0)
return 0;
return -ENODEV;
}
/*
* Read single volume dumper from disk
*/
static int sv_dumper_read(void)
{
int blk_size;
if (zg_type(g.fh) == ZG_TYPE_DASD_PART)
return -ENODEV;
zg_ioctl(g.fh, BLKSSZGET, &blk_size, "BLKSSZGET", ZG_CHECK);
if (dumper_read_eckd(blk_size) == 0) {
dt_attr_dasd_type_set("ECKD");
return 0;
}
if (dumper_read_fba() == 0) {
dt_attr_dasd_type_set("FBA");
return 0;
}
return -ENODEV;
}
/*
* Initialize s390 single-volume dump tool (for -d option)
*/
static int dt_s390sv_init(void)
{
if (sv_dumper_read() != 0)
return -ENODEV;
dt_arch_set(l.dumper_arch);
dt_version_set(df_s390_dumper_version(l.dumper));
dt_attr_mem_limit_set(df_s390_dumper_mem(&l.dumper));
return 0;
}
/*
* s390 single-volume DT operations
*/
struct dt dt_s390sv = {
.desc = "Single-volume DASD dump tool",
.init = dt_s390sv_init,
};
+233
View File
@@ -0,0 +1,233 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* Single-volume SCSI dump tool
*
* Copyright IBM Corp. 2013, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <linux/fs.h>
#include <stdio.h>
#include "lib/util_part.h"
#include "zgetdump.h"
/*
* Single volume SCSI dump superblock
*/
struct scsi_dump_sb {
uint64_t magic;
uint64_t version;
uint64_t part_start;
uint64_t part_size;
uint64_t dump_off;
uint64_t dump_size;
uint64_t csum_off;
uint64_t csum_size;
uint64_t csum;
} __attribute((packed));
/*
* File local static data
*/
static struct {
struct scsi_dump_sb sb;
int blk_size;
} l;
/*
* zipl on-disc / bootloader structs from zipl includes
*/
struct scsi_blockptr {
uint64_t blockno;
uint16_t size;
uint16_t blockct;
uint8_t reserved[4];
} __attribute__((__packed__));
enum component_entry_type {
component_execute = 0x01,
component_load = 0x02
};
struct component_entry {
struct scsi_blockptr data;
uint8_t pad[7];
uint8_t component_type;
union {
uint64_t load_address;
uint64_t load_psw;
} address;
} __attribute__((__packed__));
enum component_header_type {
component_header_ipl = 0x00,
component_header_dump = 0x01
};
struct component_header {
uint8_t magic[4];
uint8_t type;
uint8_t reserved[27];
} __attribute__((__packed__));
struct boot_info {
char magic[4];
uint8_t version;
uint8_t bp_type;
uint8_t dev_type;
uint8_t flags;
uint64_t sb_off;
} __attribute__ ((packed));
struct scsi_mbr {
char magic[4];
uint32_t version;
uint8_t reserved1[8];
struct scsi_blockptr blockptr;
uint8_t reserved2[0x50];
struct boot_info boot_info;
} __attribute__((__packed__));
#define BOOT_INFO_VERSION 1
#define BOOT_INFO_MAGIC "zIPL"
#define BOOT_INFO_DEV_TYPE_SCSI 0x02
#define BOOT_INFO_BP_TYPE_DUMP 0x01
/*
* Check the zIPL magic number
*/
static int check_zipl_magic(void *buf)
{
if (memcmp(buf, "zIPL", 4))
return -1;
return 0;
}
/*
* Final step looks into program to find dump flag
*/
static int check_dump_program(struct scsi_blockptr *blockptr)
{
uint64_t off = blockptr->blockno * l.blk_size;
struct component_header header;
zg_seek(g.fh, off, ZG_CHECK_ERR);
zg_read(g.fh, &header, sizeof(header), ZG_CHECK_ERR);
if (check_zipl_magic(&header.magic))
return -1;
return (header.type == component_header_dump) ? 0 : -1;
}
/*
* Parse program table, see zipl docu to understand table structures
*/
static int check_program_table(uint64_t blockno)
{
struct scsi_blockptr entries[l.blk_size / sizeof(struct scsi_blockptr)];
unsigned int i;
/* Entry 0, holds the magic, entry 1 the default */
zg_seek(g.fh, blockno * l.blk_size, ZG_CHECK);
zg_read(g.fh, &entries, l.blk_size, ZG_CHECK);
if (check_zipl_magic(&entries[0]))
return -1;
for (i = 1; i < l.blk_size / sizeof(struct scsi_blockptr); i++) {
if (entries[i].blockno == 0)
break;
if (check_dump_program(&entries[i]) == 0)
return 0;
}
return -1;
}
/*
* Check magic number and checksum of superblock at given offset
*/
static int check_sb(void)
{
char buf[l.sb.csum_size];
if (l.sb.magic != 0x5a46435044554d50ULL) /* ZFCPDUMP */
return -1;
/*
* Verify checksum
*/
zg_seek(g.fh, l.sb.part_start + l.sb.csum_off, ZG_CHECK);
zg_read(g.fh, &buf, sizeof(buf), ZG_CHECK);
if (zg_csum_partial(&buf, l.sb.csum_size, 0x12345678) != l.sb.csum)
return -1;
return 0;
}
/*
* Check the SCSI dump boot info
*/
static int check_boot_info(struct boot_info *info)
{
if (memcmp(&info->magic, BOOT_INFO_MAGIC, sizeof(info->magic)))
return -1;
if (info->dev_type != BOOT_INFO_DEV_TYPE_SCSI)
return -1;
if (info->bp_type != BOOT_INFO_BP_TYPE_DUMP)
return -1;
zg_seek(g.fh, info->sb_off, ZG_CHECK);
zg_read(g.fh, &l.sb, sizeof(l.sb), ZG_CHECK);
return check_sb();
}
/*
* Detect if the bootmap contains ZFCPDUMP.
* Walks through bootmap structs to find the dump flag
*/
static int dt_scsi_init(void)
{
struct scsi_mbr mbr;
zg_read(g.fh, &mbr, sizeof(mbr), ZG_CHECK);
if (zg_ioctl(g.fh, BLKSSZGET, &l.blk_size, "BLKSSZGET", ZG_CHECK_NONE))
return -1;
if (check_zipl_magic(mbr.magic))
return -1;
if (check_program_table(mbr.blockptr.blockno))
return -1;
if (check_boot_info(&mbr.boot_info))
return -1;
dt_arch_set(DFI_ARCH_64);
dt_version_set(l.sb.version);
return 0;
}
/*
* Print partition information for dump device
*/
static void dt_scsi_info(void)
{
int part_num, part_ext;
size_t start, cnt;
start = l.sb.part_start / l.blk_size;
cnt = l.sb.part_size / l.blk_size;
part_num = util_part_search_fh(g.fh->fh, start, cnt, l.blk_size,
&part_ext);
STDERR("Partition info:\n");
if (part_num > 0)
STDERR(" Partition number..: %d\n", part_num);
else
STDERR(" Partition number..: unknown\n");
STDERR(" Maximum dump size.: %llu MB\n",
(unsigned long long) TO_MIB(l.sb.dump_size));
}
/*
* Single-volume SCSI DT operations
*/
struct dt dt_scsi = {
.desc = "Single-volume SCSI dump tool",
.init = dt_scsi_init,
.info = dt_scsi_info,
};
+292
View File
@@ -0,0 +1,292 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* Option parsing
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib/zt_common.h"
#include "zgetdump.h"
/*
* Text for --help option
*/
static char help_text[] =
"Usage: zgetdump DUMP [-s SYS] [-f FMT] > DUMP_FILE\n"
" -m DUMP [-s SYS] [-f FMT] DIR\n"
" -i DUMP [-s SYS]\n"
" -d DUMPDEV\n"
" -u DIR\n"
"\n"
"The zgetdump tool can read different dump formats from a dump device or from\n"
"a dump file. You can use zgetdump to:\n"
"\n"
" - Write the dump content to standard output or to a file\n"
" - Mount the dump content to a Linux directory\n"
" - Convert a dump to a different dump format\n"
" - Check if a dump is valid\n"
" - Check if a DASD contains a valid dump tool.\n"
"\n"
"In the syntax description, DUMP specifies a dump device or dump file to be\n"
"read. The following options are available:\n"
"\n"
"-m, --mount Mount DUMP to mount point DIR\n"
"-u, --umount Unmount dump from mount point DIR\n"
"-i, --info Print DUMP information\n"
"-f, --fmt Specify target dump format FMT (\"elf\" or \"s390\")\n"
"-s, --select Select system data SYS (\"kdump\", \"prod\", or \"all\")\n"
"-d, --device Print DUMPDEV (dump device) information\n"
"-v, --version Print version information, then exit\n"
"-h, --help Print this help, then exit\n";
static const char copyright_str[] = "Copyright IBM Corp. 2001, 2017";
/*
* Select option strings
*/
const char *OPTS_SELECT_KDUMP = "kdump";
const char *OPTS_SELECT_PROD = "prod";
const char *OPTS_SELECT_ALL = "all";
/*
* Initialize default settings
*/
static void init_defaults(void)
{
g.prog_name = "zgetdump";
g.opts.action = ZG_ACTION_STDOUT;
#ifdef __s390x__
g.opts.fmt = "elf";
#else
g.opts.fmt = "s390";
#endif
dfo_set(g.opts.fmt);
}
/*
* Print "help" hint
*/
static void print_usage_exit(void)
{
STDERR("Try '%s --help' for more information.\n", g.prog_name);
zg_exit(1);
}
/*
* Print help text
*/
static void print_help_exit(void)
{
STDOUT("%s", help_text);
zg_exit(0);
}
/*
* Print version information
*/
static void print_version_exit(void)
{
STDOUT("%s: Tool for copying and converting dumps version %s\n",
g.prog_name, RELEASE_STRING);
STDOUT("%s\n", copyright_str);
zg_exit(0);
}
/*
* Set "--fmt" option
*/
static void fmt_set(const char *fmt)
{
if (dfo_set(fmt) != 0)
ERR_EXIT("Invalid target format \"%s\" specified", fmt);
g.opts.fmt_specified = 1;
g.opts.fmt = fmt;
}
/*
* Set "--select" option
*/
static void select_set(const char *select)
{
if (strcmp(select, OPTS_SELECT_KDUMP) == 0)
g.opts.select = OPTS_SELECT_KDUMP;
else if (strcmp(select, OPTS_SELECT_PROD) == 0)
g.opts.select = OPTS_SELECT_PROD;
else if (strcmp(select, OPTS_SELECT_ALL) == 0)
g.opts.select = OPTS_SELECT_ALL;
else
ERR_EXIT("Invalid select argument \"%s\" specified", select);
g.opts.select_specified = 1;
}
/*
* Set mount point
*/
static void mount_point_set(const char *mount_point)
{
g.opts.mount_point = zg_strdup(mount_point);
}
/*
* Set device
*/
static void device_set(const char *path)
{
g.opts.device = zg_strdup(path);
}
/*
* Set FUSE debug options
*/
static void argv_fuse_set(char **argv, int argc)
{
int i;
g.opts.argv_fuse = argv;
g.opts.argc_fuse = argc;
STDERR_PR("Fuse Options: ");
for (i = 0; i < argc; i++)
STDERR("%s ", g.opts.argv_fuse[i]);
STDERR("\n");
}
/*
* Set action
*/
static void action_set(enum zg_action action)
{
if (g.opts.action_specified)
ERR_EXIT("Please specifiy only one of the \"-i\", \"-d\", "
"\"-m\" or \"-u\" option");
g.opts.action = action;
g.opts.action_specified = 1;
}
/*
* Verify option combinations
*/
static void verify_opts(void)
{
if (g.opts.select_specified) {
if (g.opts.action != ZG_ACTION_MOUNT &&
g.opts.action != ZG_ACTION_STDOUT &&
g.opts.action != ZG_ACTION_DUMP_INFO)
ERR_EXIT("The \"--select\" option can only be "
"specifed for info, mount, or copy");
}
if (!g.opts.fmt_specified)
return;
if (g.opts.action == ZG_ACTION_DUMP_INFO)
ERR_EXIT("The \"--fmt\" option cannot be specified "
"together with \"--info\"");
if (g.opts.action == ZG_ACTION_DEVICE_INFO)
ERR_EXIT("The \"--fmt\" option cannot be specified "
"together with \"--device\"");
if (g.opts.action == ZG_ACTION_UMOUNT)
ERR_EXIT("The \"--fmt\" option cannot be specified "
"together with \"--umount\"");
}
/*
* Parse positional arguments
*/
static void parse_pos_args(char *argv[], int argc)
{
int pos_args = argc - optind;
switch (g.opts.action) {
case ZG_ACTION_STDOUT:
case ZG_ACTION_DUMP_INFO:
case ZG_ACTION_DEVICE_INFO:
if (pos_args == 0)
ERR_EXIT("No device or dump specified");
if (pos_args > 1 && !g.opts.debug_specified)
ERR_EXIT("Too many positional parameters specified");
device_set(argv[optind]);
break;
case ZG_ACTION_MOUNT:
if (pos_args == 0)
ERR_EXIT("No dump specified");
if (pos_args == 1)
ERR_EXIT("No mount point specified");
if (pos_args > 2 && !g.opts.debug_specified)
ERR_EXIT("Too many positional parameters specified");
device_set(argv[optind]);
mount_point_set(argv[optind + 1]);
if (g.opts.debug_specified && pos_args > 2)
argv_fuse_set(&argv[optind + 2], pos_args - 2);
break;
case ZG_ACTION_UMOUNT:
if (pos_args == 0)
ERR_EXIT("No mount point specified");
mount_point_set(argv[optind]);
break;
}
}
/*
* Main command line parsing function
*/
void opts_parse(int argc, char *argv[])
{
int opt, idx;
static struct option long_opts[] = {
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{"info", no_argument, NULL, 'i'},
{"device", no_argument, NULL, 'd'},
{"mount", no_argument, NULL, 'm'},
{"umount", no_argument, NULL, 'u'},
{"fmt", required_argument, NULL, 'f'},
{"select", required_argument, NULL, 's'},
{"debug", no_argument, NULL, 'X'},
{NULL, 0, NULL, 0 }
};
static const char optstr[] = "hvidmus:f:X";
init_defaults();
while ((opt = getopt_long(argc, argv, optstr, long_opts, &idx)) != -1) {
switch (opt) {
case 'h':
print_help_exit();
case 'v':
print_version_exit();
case 'i':
action_set(ZG_ACTION_DUMP_INFO);
break;
case 'd':
action_set(ZG_ACTION_DEVICE_INFO);
break;
case 'm':
action_set(ZG_ACTION_MOUNT);
break;
case 'u':
action_set(ZG_ACTION_UMOUNT);
break;
case 'f':
fmt_set(optarg);
break;
case 's':
select_set(optarg);
break;
case 'X':
g.opts.debug_specified = 1;
break;
default:
print_usage_exit();
}
}
parse_pos_args(argv, argc);
verify_opts();
}
+40
View File
@@ -0,0 +1,40 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* Write dump to standard output (stdout)
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include "zgetdump.h"
int stdout_write_dump(void)
{
u64 cnt, written = 0;
char buf[32768];
ssize_t rc;
if (!dfi_feat_copy())
ERR_EXIT("Copying not possible for %s dumps", dfi_name());
STDERR("Format Info:\n");
STDERR(" Source: %s\n", dfi_name());
STDERR(" Target: %s\n", dfo_name());
STDERR("\n");
zg_progress_init("Copying dump", dfo_size());
do {
cnt = dfo_read(buf, sizeof(buf));
rc = write(STDOUT_FILENO, buf, cnt);
if (rc == -1)
ERR_EXIT_ERRNO("Error: Write failed");
if (rc != (ssize_t) cnt)
ERR_EXIT("Error: Could not write full block");
written += cnt;
zg_progress(written);
} while (written != dfo_size());
STDERR("\n");
STDERR("Success: Dump has been copied\n");
return 0;
}
+241
View File
@@ -0,0 +1,241 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* FUSE functions
*
* Copyright IBM Corp. 2010, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#define FUSE_USE_VERSION 25
#include <errno.h>
#include <fcntl.h>
#include <fuse.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "zgetdump.h"
#define DUMP_PATH_MAX 100
/*
* File local static data
*/
static struct {
char path[DUMP_PATH_MAX];
struct stat stat_root;
struct stat stat_dump;
} l;
/*
* Initialize default values for stat buffer
*/
static void stat_default_init(struct stat *stat)
{
if (dfi_attr_time()) {
stat->st_mtime = dfi_attr_time()->tv_sec;
stat->st_ctime = dfi_attr_time()->tv_sec;
stat->st_atime = dfi_attr_time()->tv_sec;
} else {
stat->st_mtime = zg_stat(g.fh)->st_mtime;
stat->st_ctime = zg_stat(g.fh)->st_ctime;
stat->st_atime = zg_stat(g.fh)->st_atime;
}
stat->st_uid = geteuid();
stat->st_gid = getegid();
}
/*
* Initialize stat buffer for root directory
*/
static void stat_root_init(void)
{
stat_default_init(&l.stat_root);
l.stat_root.st_mode = S_IFDIR | 0500;
l.stat_root.st_nlink = 2;
}
/*
* Initialize stat buffer for dump
*/
static void stat_dump_init(void)
{
stat_default_init(&l.stat_dump);
l.stat_dump.st_mode = S_IFREG | 0400;
l.stat_dump.st_nlink = 1;
l.stat_dump.st_size = dfo_size();
l.stat_dump.st_blksize = 4096;
l.stat_dump.st_blocks = l.stat_dump.st_size / 4096;
}
/*
* FUSE callback: Getattr
*/
static int zfuse_getattr(const char *path, struct stat *stat)
{
if (strcmp(path, "/") == 0) {
*stat = l.stat_root;
return 0;
}
if (strcmp(path, l.path) == 0) {
*stat = l.stat_dump;
return 0;
}
return -ENOENT;
}
/*
* FUSE callback: Readdir - Return ".", ".." and dump file
*/
static int zfuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
{
(void) offset;
(void) fi;
if (strcmp(path, "/") != 0)
return -ENOENT;
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, &l.path[1], NULL, 0);
return 0;
}
/*
* FUSE callback: Open
*/
static int zfuse_open(const char *path, struct fuse_file_info *fi)
{
if (strcmp(path, l.path) != 0)
return -ENOENT;
if ((fi->flags & 3) != O_RDONLY)
return -EACCES;
l.stat_dump.st_atime = time(NULL);
return 0;
}
/*
* FUSE callback: Read
*/
static int zfuse_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
(void) fi;
if (strcmp(path, l.path) != 0)
return -ENOENT;
dfo_seek(offset);
dfo_read(buf, size);
return size;
}
/*
* FUSE callback: Statfs
*/
static int zfuse_statfs(const char *path, struct statvfs *buf)
{
(void) path;
buf->f_bsize = buf->f_frsize = 4096;
buf->f_blocks = dfo_size() / 4096;
buf->f_bfree = buf->f_bavail = 0;
buf->f_files = 1;
buf->f_ffree = 0;
buf->f_namemax = strlen(l.path) + 1;
return 0;
}
/*
* FUSE operations
*/
static struct fuse_operations zfuse_ops = {
.getattr = zfuse_getattr,
.readdir = zfuse_readdir,
.open = zfuse_open,
.read = zfuse_read,
.statfs = zfuse_statfs,
};
/*
* Add additional FUSE arguments
*/
static void add_argv_fuse(struct fuse_args *args)
{
int i;
if (g.opts.argc_fuse == 0)
return;
STDERR("Adding Fuse options: ");
for (i = 0; i < g.opts.argc_fuse; i++) {
STDERR("%s ", g.opts.argv_fuse[i]);
fuse_opt_add_arg(args, g.opts.argv_fuse[i]);
}
STDERR("\n");
}
/*
* Mount dump
*
* Add additional FUSE options:
* - s....................: Disable multi-threaded operation
* - o fsname.............: File system name (used for umount)
* - o ro.................: Read only
* - o default_permissions: Enable permission checking by kernel
*/
int zfuse_mount_dump(void)
{
struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
char tmp_str[PATH_MAX];
if (!dfi_feat_seek())
ERR_EXIT("Mounting not possible for %s dumps", dfi_name());
fuse_opt_add_arg(&args, "zgetdump");
fuse_opt_add_arg(&args, "-s");
snprintf(tmp_str, sizeof(tmp_str),
"-ofsname=%s,ro,default_permissions,nonempty",
g.opts.device);
fuse_opt_add_arg(&args, tmp_str);
fuse_opt_add_arg(&args, g.opts.mount_point);
add_argv_fuse(&args);
stat_root_init();
stat_dump_init();
snprintf(l.path, sizeof(l.path), "/dump.%s", dfo_name());
return fuse_main(args.argc, args.argv, &zfuse_ops);
}
/*
* Unmount dump
*/
void zfuse_umount(void)
{
char umount_cmd[PATH_MAX];
char *umount_tool;
struct stat sbuf;
int rc;
if (stat("/usr/bin/fusermount", &sbuf) == 0)
umount_tool = "/usr/bin/fusermount -u";
else if (stat("/bin/fusermount", &sbuf) == 0)
umount_tool = "/bin/fusermount -u";
else
umount_tool = "umount";
snprintf(umount_cmd, sizeof(umount_cmd), "%s %s", umount_tool,
g.opts.mount_point);
rc = system(umount_cmd);
if (rc == -1)
ERR_EXIT_ERRNO("\"%s\" failed", umount_cmd);
if (rc > 0)
ERR_EXIT("\"%s\" failed", umount_cmd);
exit(0);
}
+452
View File
@@ -0,0 +1,452 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* Helper functions
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <limits.h>
#include <stdlib.h>
#include <sys/sysmacros.h>
#include <sys/time.h>
#include "zgetdump.h"
#define MAX_EXIT_FN 10
#define MAX_DEV_RETRIES 1000
#define PROGRESS_INTERVAL_SECS 10
/*
* Progress information
*/
struct prog {
time_t time_next;
u64 mem_size;
};
/*
* At exit information
*/
struct atexit {
zg_atexit_fn_t fn_vec[MAX_EXIT_FN];
unsigned int cnt;
};
/*
* Temp devnode information
*/
struct devnode {
char **vec;
int cnt;
};
/*
* File local static data
*/
static struct {
struct atexit atexit;
struct prog prog;
struct devnode devnode;
} l;
/*
* Call all registered exit handlers
*/
static void exit_fn(void)
{
unsigned int i;
for (i = 0; i < l.atexit.cnt; i++)
l.atexit.fn_vec[i]();
}
/*
* Register exit handler
*/
void zg_atexit(zg_atexit_fn_t fn)
{
if (l.atexit.cnt >= MAX_EXIT_FN)
ABORT("Too many atexit handlers (%d)", l.atexit.cnt + 1);
l.atexit.fn_vec[l.atexit.cnt] = fn;
if (l.atexit.cnt == 0)
atexit(exit_fn);
l.atexit.cnt++;
}
/*
* Exit function (For having exit gdb break point)
*/
void __noreturn zg_exit(int rc)
{
exit(rc);
}
/*
* Alloc memory and check for errors
*/
void *zg_alloc(unsigned int size)
{
void *ptr = calloc(size, 1);
if (!ptr)
ERR_EXIT("Alloc: Out of memory (%i KiB)", TO_KIB(size));
return ptr;
}
/*
* Realloc memory and check for errors
*/
void *zg_realloc(void *ptr, unsigned int size)
{
void *new_ptr = realloc(ptr, size);
if (!new_ptr)
ERR_EXIT("Realloc: Out of memory (%i KiB)", TO_KIB(size));
return new_ptr;
}
/*
* Create duplicate for string
*/
char *zg_strdup(const char *str)
{
char *new_str = strdup(str);
if (!new_str)
ERR_EXIT("Strdup: Out of memory (%s)\n", str);
return new_str;
}
/*
* Free memory
*/
void zg_free(void *ptr)
{
free(ptr);
}
/*
* Return path name of open file
*/
const char *zg_path(struct zg_fh *zg_fh)
{
return zg_fh->path;
}
/*
* Return stat buffer of open file
*/
const struct stat *zg_stat(struct zg_fh *zg_fh)
{
return &zg_fh->sb;
}
/*
* Open file
*/
struct zg_fh *zg_open(const char *path, int flags, enum zg_check check)
{
struct zg_fh *zg_fh = zg_alloc(sizeof(*zg_fh));
zg_fh->fh = open(path, flags);
if (zg_fh->fh == -1) {
if (check == ZG_CHECK_NONE)
goto fail;
ERR_EXIT_ERRNO("Could not open \"%s\"", path);
}
if (stat(path, &zg_fh->sb) == -1) {
if (check == ZG_CHECK_NONE)
goto fail;
ERR_EXIT_ERRNO("Could not access file \"%s\"", path);
}
zg_fh->path = zg_strdup(path);
if (S_ISBLK(zg_fh->sb.st_mode)) {
/* We have a block device - set correct size */
zg_fh->sb.st_size = lseek(zg_fh->fh, 0, SEEK_END);
if (zg_fh->sb.st_size == (off_t)-1)
goto fail;
if (lseek(zg_fh->fh, 0, SEEK_SET) == (off_t)-1)
goto fail;
}
return zg_fh;
fail:
zg_free(zg_fh);
return NULL;
}
/*
* Close file
*/
void zg_close(struct zg_fh *zg_fh)
{
close(zg_fh->fh);
free(zg_fh);
}
/*
* Read file
*/
ssize_t zg_read(struct zg_fh *zg_fh, void *buf, size_t cnt, enum zg_check check)
{
size_t copied = 0;
ssize_t rc;
do {
rc = read(zg_fh->fh, buf + copied, cnt - copied);
if (rc == -1) {
if (check == ZG_CHECK_NONE)
return rc;
ERR_EXIT_ERRNO("Could not read \"%s\"", zg_fh->path);
}
if (rc == 0) {
if (check != ZG_CHECK)
return copied;
ERR_EXIT("Unexpected end of file for \"%s\"",
zg_fh->path);
}
copied += rc;
} while (copied != cnt);
return copied;
}
/*
* Read line
*/
ssize_t zg_gets(struct zg_fh *zg_fh, void *ptr, size_t cnt, enum zg_check check)
{
size_t copied = 0;
char *buf = ptr;
ssize_t rc;
if (cnt == 0)
return 0;
do {
rc = read(zg_fh->fh, &buf[copied], 1);
if (rc == -1) {
if (check == ZG_CHECK_NONE)
return rc;
ERR_EXIT_ERRNO("Could not read \"%s\"", zg_fh->path);
}
if (rc == 0 || buf[copied] == '\n' || copied == cnt - 1)
break;
copied++;
} while (1);
buf[copied] = '\0';
return copied;
}
/*
* Return file size
*/
u64 zg_size(struct zg_fh *zg_fh)
{
return zg_fh->sb.st_size;
}
/*
* Return file position
*/
off_t zg_tell(struct zg_fh *zg_fh, enum zg_check check)
{
off_t rc;
rc = lseek(zg_fh->fh, 0, SEEK_CUR);
if (rc == -1 && check != ZG_CHECK_NONE)
ERR_EXIT_ERRNO("Could not get file position for \"%s\"",
zg_fh->path);
return rc;
}
/*
* Seek to "off" relative to END
*/
off_t zg_seek_end(struct zg_fh *zg_fh, off_t off, enum zg_check check)
{
off_t rc;
rc = lseek(zg_fh->fh, off, SEEK_END);
if (rc == -1 && check != ZG_CHECK_NONE)
ERR_EXIT_ERRNO("Could not seek \"%s\"", zg_fh->path);
return rc;
}
/*
* Seek to "off" in file
*/
off_t zg_seek(struct zg_fh *zg_fh, off_t off, enum zg_check check)
{
off_t rc;
rc = lseek(zg_fh->fh, off, SEEK_SET);
if (rc == -1 && check != ZG_CHECK_NONE)
ERR_EXIT_ERRNO("Could not seek \"%s\"", zg_fh->path);
if (rc != off && check == ZG_CHECK)
ERR_EXIT("Could not seek \"%s\"", zg_fh->path);
return rc;
}
/*
* Seek from current position
*/
off_t zg_seek_cur(struct zg_fh *zg_fh, off_t off, enum zg_check check)
{
off_t rc;
rc = lseek(zg_fh->fh, off, SEEK_CUR);
if (rc == -1 && check != ZG_CHECK_NONE)
ERR_EXIT_ERRNO("Could not seek \"%s\"", zg_fh->path);
return rc;
}
/*
* Do ioctl and exit in case of an error
*/
int zg_ioctl(struct zg_fh *zg_fh, int rq, void *data, const char *op,
enum zg_check check)
{
int rc;
rc = ioctl(zg_fh->fh, rq, data);
if (rc == -1 && check != ZG_CHECK_NONE)
ERR_EXIT_ERRNO("Operation \"%s\" failed on \"%s\"", op,
zg_fh->path);
return rc;
}
/*
* Return file type
*/
enum zg_type zg_type(struct zg_fh *zg_fh)
{
struct mtop mtop;
struct stat *sb = &zg_fh->sb;
if (S_ISREG(sb->st_mode))
return ZG_TYPE_FILE;
if (S_ISBLK(sb->st_mode)) {
if (minor(sb->st_rdev) % 4 == 0)
return ZG_TYPE_DASD;
else
return ZG_TYPE_DASD_PART;
}
if (S_ISCHR(sb->st_mode)) {
mtop.mt_count = 1;
mtop.mt_op = MTTELL;
if (zg_ioctl(zg_fh, MTIOCTOP, &mtop, "MTIOCTOP",
ZG_CHECK_NONE) != -1)
return ZG_TYPE_TAPE;
}
return ZG_TYPE_UNKNOWN;
}
/*
* Initialize progress messages
*/
void zg_progress_init(const char *msg, u64 mem_size)
{
STDERR("%s:\n", msg);
l.prog.time_next = 0;
l.prog.mem_size = mem_size;
}
/*
* Print progress
*/
void zg_progress(u64 addr)
{
struct timeval tv;
gettimeofday(&tv, NULL);
if ((tv.tv_sec < l.prog.time_next) && (addr < l.prog.mem_size))
return;
STDERR(" %08Lu / %08Lu MB\n", TO_MIB(addr), TO_MIB(l.prog.mem_size));
l.prog.time_next = tv.tv_sec + PROGRESS_INTERVAL_SECS;
}
/*
* Try to create device node in "dir"
*/
static char *devnode_create_dir(const char *dir, dev_t dev)
{
char file_path[PATH_MAX];
int i, fh, rc;
for (i = 0; i < MAX_DEV_RETRIES; i++) {
snprintf(file_path, PATH_MAX, "%s/zgetdump.%04d", dir, i);
rc = mknod(file_path, S_IFBLK | S_IRWXU, dev);
if (rc == -1) {
if (errno == EEXIST)
continue;
else
break;
}
/* Need this test to cover 'nodev'-mounted filesystems */
fh = open(file_path, O_RDWR);
if (fh == -1) {
remove(file_path);
break;
}
close(fh);
return zg_strdup(file_path);
}
return NULL;
}
/*
* Delete temporary device node
*/
static void devnode_remove(char *dev_node)
{
if (remove(dev_node))
ERR("Warning: Could not remove temporary file %s: %s",
dev_node, strerror(errno));
zg_free(dev_node);
}
/*
* Remove all temporary device nodes
*/
static void devnode_remove_all(void)
{
int i;
for (i = 0; i < l.devnode.cnt; i++)
devnode_remove(l.devnode.vec[i]);
if (l.devnode.vec) {
zg_free(l.devnode.vec);
l.devnode.vec = NULL;
}
l.devnode.cnt = 0;
}
/*
* Make temporary device node for input dev identified by its dev_t
*/
char *zg_devnode_create(dev_t dev)
{
char *dir_vec[] = {getenv("TMPDIR"), "/tmp", getenv("HOME"), ".", "/"};
char *file_path;
unsigned int i;
for (i = 0; i < ARRAY_ELEMENT_CNT(dir_vec); i++) {
if (dir_vec[i] == NULL)
continue;
file_path = devnode_create_dir(dir_vec[i], dev);
if (file_path)
goto found;
}
ERR_EXIT_ERRNO("Unable to create temporary dev node");
return NULL;
found:
l.devnode.cnt++;
l.devnode.vec = zg_realloc(l.devnode.vec, l.devnode.cnt *
sizeof(void *));
l.devnode.vec[l.devnode.cnt - 1] = file_path;
if (l.devnode.cnt == 1)
zg_atexit(devnode_remove_all);
return file_path;
}
+201
View File
@@ -0,0 +1,201 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* Helper functions
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef ZG_H
#define ZG_H
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mtio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "lib/util_base.h"
#include "lib/zt_common.h"
#define U64_MAX ((u64) -1)
#define U32_MAX ((u32) -1)
#define U16_MAX ((u16) -1)
#define U8_MAX ((u8) -1)
/*
* IEC definitions
*/
#define KIB (1024)
#define MIB (1024 * 1024)
#define GIB (1024 * 1024 * 1024)
#define TO_MIB(x) ((x + (MIB / 2)) / MIB)
#define TO_KIB(x) ((x + (KIB / 2)) / KIB)
/*
* Memory functions
*/
extern void *zg_alloc(unsigned int size);
extern void *zg_realloc(void *ptr, unsigned int size);
extern void zg_free(void *ptr);
extern char *zg_strdup(const char *str);
/*
* At exit functions
*/
typedef void (*zg_atexit_fn_t)(void);
extern void zg_atexit(zg_atexit_fn_t fn);
extern void __noreturn zg_exit(int rc);
/*
* Temporary device node functions
*/
extern char *zg_devnode_create(dev_t dev);
/*
* Progress bar functions
*/
extern void zg_progress_init(const char *msg, u64 mem_size);
extern void zg_progress(u64 addr);
/*
* Error and print functions
*/
#define ERR(x...) \
do { \
fprintf(stderr, "%s: ", "zgetdump"); \
fprintf(stderr, x); \
fprintf(stderr, "\n"); \
} while (0)
#define ERR_EXIT(x...) \
do { \
ERR(x); \
zg_exit(1); \
} while (0)
#define ABORT(x...) \
do { \
ERR("Internal Error: " x); \
abort(); \
} while (0)
#define ERR_EXIT_ERRNO(x...) \
do { \
fflush(stdout); \
fprintf(stderr, "%s: ", "zgetdump"); \
fprintf(stderr, x); \
fprintf(stderr, " (%s)", strerror(errno)); \
fprintf(stderr, "\n"); \
zg_exit(1); \
} while (0)
#define STDERR(x...) \
do { \
fprintf(stderr, x); \
fflush(stderr); \
} while (0)
#define STDERR_PR(x...) \
do { \
fprintf(stderr, "\r%s: ", "zgetdump"); \
fprintf(stderr, x); \
} while (0)
#define STDOUT(x...) \
do { \
fprintf(stdout, x); \
fflush(stdout); \
} while (0)
/*
* Misc
*/
#define PAGE_SIZE 4096UL
#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
#define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE)
#define ARRAY_ELEMENT_CNT(x) (sizeof(x) / sizeof(x[0]))
#define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
static inline u32 zg_csum_partial(const void *buf, int len, u32 sum)
{
register unsigned long reg2 asm("2") = (unsigned long) buf;
register unsigned long reg3 asm("3") = (unsigned long) len;
asm volatile(
"0: cksm %0,%1\n" /* do checksum on longs */
" jo 0b\n"
: "+d" (sum), "+d" (reg2), "+d" (reg3) : : "cc", "memory");
return sum;
}
/*
* Pointer atrithmetic
*/
#define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
#define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y)))
#define PTR_DIFF(x, y) ((unsigned long)(((char *) (x)) - ((unsigned long) (y))))
/*
* File functions
*/
struct zg_fh {
const char *path;
int fh;
struct stat sb;
};
enum zg_type {
ZG_TYPE_DASD,
ZG_TYPE_DASD_PART,
ZG_TYPE_FILE,
ZG_TYPE_TAPE,
ZG_TYPE_UNKNOWN,
};
enum zg_check {
ZG_CHECK,
ZG_CHECK_ERR,
ZG_CHECK_NONE,
};
extern const char *zg_path(struct zg_fh *zg_fh);
extern const struct stat *zg_stat(struct zg_fh *zg_fh);
extern struct zg_fh *zg_open(const char *path, int flags, enum zg_check check);
extern void zg_close(struct zg_fh *zg_fh);
extern ssize_t zg_read(struct zg_fh *zg_fh, void *buf, size_t cnt,
enum zg_check check);
extern ssize_t zg_gets(struct zg_fh *zg_fh, void *buf, size_t cnt,
enum zg_check check);
extern u64 zg_size(struct zg_fh *zg_fh);
extern off_t zg_tell(struct zg_fh *zg_fh, enum zg_check check);
extern off_t zg_seek(struct zg_fh *zg_fh, off_t off, enum zg_check check);
extern off_t zg_seek_end(struct zg_fh *zg_fh, off_t off, enum zg_check check);
extern off_t zg_seek_cur(struct zg_fh *zg_fh, off_t off, enum zg_check check);
extern int zg_ioctl(struct zg_fh *zg_fh, int rq, void *data, const char *op,
enum zg_check check);
extern enum zg_type zg_type(struct zg_fh *zg_fh);
/*
* zgetdump actions
*/
enum zg_action {
ZG_ACTION_STDOUT,
ZG_ACTION_DUMP_INFO,
ZG_ACTION_DEVICE_INFO,
ZG_ACTION_MOUNT,
ZG_ACTION_UMOUNT,
};
#endif /* ZG_H */
+447
View File
@@ -0,0 +1,447 @@
.\" Copyright 2017 IBM Corp.
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH ZGETDUMP 8 "April 2012" "s390-tools"
.SH NAME
zgetdump \- Tool for copying and converting System z dumps
.SH SYNOPSIS
\fBzgetdump\fR DUMP [-s SYS] [-f FMT] > DUMP_FILE
.br
-m DUMP [-s SYS] [-f FMT] DIR
.br
-i DUMP [-s SYS]
.br
-d DUMPDEV
.br
-u DIR
.br
-h|-v
.SH DESCRIPTION
The \fBzgetdump\fR tool copies a source dump into a target dump with a
configurable dump format. The source dump can be located either on a dump
device or on a file system. By default the source dump content is
written to standard output, which you can redirect to a specific file. You
can also mount the dump content, print dump information, check
whether a dump device contains a valid dump tool, or create a
non-disruptive dump on a live system.
.SH OPTIONS
.TP
.BR "\-h" " or " "\-\-help"
Print usage information, then exit.
.TP
.BR "\-v" " or " "\-\-version"
Print version information, then exit.
.TP
.BR "\-m <DUMP> <DIR>" " or " "\-\-mount <DUMP> <DIR>"
Mount the source dump DUMP to mount point DIR and generate a virtual target
dump file instead of writing the content to standard output. The virtual dump
file gets the name "dump.FMT", where FMT is the name of the specified
dump format (see "--fmt" option).
.TP
.BR "\-u <DIR>" " or " "\-\-umount <DIR>"
Unmount the dump that is mounted at mount point DIR. This option is a wrapper
for "fusermount -u". Instead of DIR also the DUMP (for example /dev/dasdd1)
can be specified.
.TP
.BR "\-d <DUMPDEV>" " or " "\-\-device <DUMPDEV>"
Check the dump disk DUMPDEV for a valid dump tool and print information
about it. See chapters DUMPDEV and DUMPDEV INFORMATION below for
more information.
.TP
.BR "\-i <DUMP>" " or " "\-\-info <DUMP>"
Print the dump header information reading from the DUMP and check if
the dump is valid. See chapters DUMP and DUMP INFORMATION below for more
information.
.TP
.BR "\-f <FMT>" " or " "\-\-fmt <FMT>"
Use the specified target dump format FMT when writing or mounting the dump.
The following target dump formats are supported:
.BR "- elf:"
Executable and Linking Format core dump (default)
.BR "- s390:"
s390 dump
.TP
.BR "\-s <SYS>" " or " "\-\-select <SYS>"
If kdump fails and a stand-alone dump is created, the resulting dump captures
two systems: The crashed kdump system and the previously crashed Linux
instance. With the "--select" option you can choose which system data
to use:
.BR "- prod:"
Data for the initial crashed Linux instance
.BR "- kdump:"
Data for the crashed kdump system
.BR "- all:"
Data for the initial crashed Linux and kdump system
The "-s" option returns an error for dumps that capture only a single crashed system.
.TP
\fBDUMP\fR
This parameter specifies the file, partition or tape device node where the
source dump is located:
.IP " -" 12
Regular dump file (e.g. /dumps/dump.0)
.IP " -" 12
DASD partition device node (e.g. /dev/dasdc1)
.IP " -" 12
DASD device node for multi-volume dump (e.g. /dev/dasdc)
.IP " -" 12
Device mapper multipath partition device node of a FCP attached SCSI disk (e.g.
/dev/mapper/3600..20c0-part1)
.IP " -" 12
Tape device node (e.g. /dev/ntibm0)
.IP " -" 12
Device node for live system (/dev/mem or /dev/crash)
.PP
.IP " " 8
Note: For DASD multi-volume dump it is sufficient to specify only one of the
multi-volume DASD partitions as DUMP.
.TP
\fBDUMPDEV\fR
When using the "--device" option, DUMPDEV must be the device node of
the dump disk that should be verified. This can be either a DASD device
node or a device mapper multipath device node of a FCP attached SCSI disk.
.SH COPY DUMP
The default action of zgetdump is to copy the source dump to standard output in
the target format specified by the \-\-fmt option. Read
the examples section below for more information.
.SH MOUNT DUMP
Use the "--mount" option to make a source dump accessible to tools that cannot
directly read the original dump format. Rather than creating a converted
copy of the dump, zgetdump creates a virtual dump file with the requested
target format. This is fast and does not consume any additional disk space.
Also multi-volume dumps can be assimilated into a single virtual dump file,
which can then be accessed directly with dump-processing tools like
makedumpfile or crash.
Specify a command of this form to mount and convert a dump:
.br
# zgetdump --mount <DUMP> <DIR> --fmt <FMT>
.br
Where:
.TP
.BR DUMP
is the source dump or dump device
.TP
.BR DIR
is the mount point where the virtual dump file is created
.TP
.BR FMT
is the target dump format to which the virtual dump file is converted.
The resulting virtual dump file is <DIR>/dump.<FMT>
.P
The virtual dump file exists until the directory is unmounted.
Use zgetdump -u <DIR> to unmount a dump.
The zgetdump tool uses the file system in user space (fuse) to mount the source
dump. Therefore, the fuse kernel module must to be loaded before using
the "--mount" option.
Read the examples section below for more information.
.SH DUMP FORMATS
The default target format of zgetdump is "elf". Use the "--fmt" option to
change the target format. The following dump formats are supported for
target and source dump:
.TP
.BR "elf"
Executable and Linking Format core dump. This dump format is also used for
Linux user space core dumps.
.TP
.BR "s390"
This dump format is System z specific and is used for DASD and tape dumps.
.TP
The following dump formats are supported for the source dump only:
.TP
.BR "lkcd"
This dump format is used by the Linux Kernel Crash Dumps (LKCD) project
and also on System z for the "vmconvert" dump tool.
.TP
.BR "devmem"
On live systems the /dev/mem or /dev/crash device nodes can be used as source
dumps for creating live dumps.
.TP
.BR "kdump" / "kdump_flat"
Dump formats created by the "makedumpfile" tool. For these formats only the
"--info" option can be used.
.SH DUMP INFORMATION
Depending on the dump format, the following dump attributes are available
when calling zgetdump with the "--info" option:
.TP
.BR "Dump format"
Name of the dump format.
.TP
.BR Version
Version number of the dump format.
.TP
.BR "Dump method"
Dump method that has been used to create the dump. Currently the only
supported value for this attribute is "live" which indicates that the
dump has been created from a live system and therefore is not consistent.
.TP
.BR "Dump created/ended"
Time when the dump process was started or ended. The dump time information is
printed in your local time zone. E.g. "Wed, 03 Feb 2010 10:47:37 +0100" shows
the time at your location. The meaning of "+0100" is that your time zone is one
hour behind GMT. You can use the "TZ" environment
variable or use the "tzselect" tool to change the time zone. For example, if you
know that the dump has been created in Hawaii, you can get the correct
time information with:
.br
# TZ='Pacific/Honolulu' zgetdump -i DUMP
.TP
.BR "Dump CPU ID"
Identifier of the CPU that ran the dump tool.
.TP
.BR "UTS node name"
The network node hostname of the Linux system.
.TP
.BR "UTS kernel release"
The kernel release of the Linux system.
.TP
.BR "UTS kernel version"
The kernel version of the Linux system.
.TP
.BR "Build arch"
Architecture (s390 or s390x) on which the dump tool was built.
.TP
.BR "System arch"
Architecture (s390 or s390x) of the Linux system.
.TP
.BR "CPU count (online)"
Number of online CPUs.
.TP
.BR "CPU count (real)"
Number of total CPUs (online and offline).
.TP
.BR "Dump memory range"
Memory range that was dumped. This value is the difference between the last
dumped and the first dumped memory address.
.TP
.BR "Real memory range"
Memory range that was available on the system. This value is the difference
between the last and the first memory address of the system on which the
dump was created.
The "real memory range" can differ from the "dump memory range" when
the SIZE parameter was used when preparing the dump device with the zipl
tool (see man zipl).
.TP
.BR "Memory map"
Available memory chunks in the dump. Some dump tools create multiple memory
chunks when creating a dump on a system with memory gaps
.SH DUMPDEV INFORMATION
Depending on the dump tool, the following attributes are available
when calling zgetdump with the "--device" option:
.TP
.BR "Dump tool"
Name of the dump tool.
.TP
.BR "Version"
Version of the dump tool.
.TP
.BR "Architecture"
Architecture (s390 or s390x) of the dump tool.
.TP
.BR "DASD type"
Type of the DASD where the dump tool is installed (ECKD or FBA).
.TP
.BR "Dump size limit"
If this attribute is set, the dump tool will dump memory only up to that
limit even if there is more memory available.
.TP
.BR "Force specified"
If this attribute is set to "yes", the multi-volume DASD dump tool will not
verify the dump signature on dump partitions. This can be useful, if the dump
partition is also used for swap.
.TP
.BR "Partition info"
For SCSI partition dump, the partition number and the maximum dump size is
printed. The partition number corresponds to the output of
"parted /dev/sdx print" or "fdisk -l /dev/sdx".
.SH EXAMPLES
.TP
.B Copy single-volume DASD dump
The DASD partition /dev/dasdx1 was prepared for dump with:
.br
# zipl -d /dev/dasdx1
.br
An IPL was performed on the corresponding single-volume dump tool and a dump
has been created. To copy the dump from the DASD partition to file dump.elf
issue:
.br
# zgetdump /dev/dasdx1 > dump.elf
.TP
.B Copy multi-volume DASD dump
DASD partitions /dev/dasdx1 and /dev/dasdy1 contained in file dev_list.conf
were prepared for multi-volume dump with:
.br
# zipl -M dev_list.conf
.br
An IPL was performed on the corresponding multi-volume dump tool and a dump
has been created. To copy the dump from the DASD partitions to file dump.elf
issue:
.br
# zgetdump /dev/dasdx > dump.elf
.br
.TP
.B Copy SCSI dump
The device mapper multipath partition on a SCSI disk
/dev/mapper/3600..20c0-part1 was prepared for dump with:
.br
# zipl -d /dev/mapper/3600..20c0-part1
.br
An IPL was performed on the corresponding dump tool and a dump
has been created. To copy the dump from the device mapper partition to file
dump.elf issue:
.br
# zgetdump /dev/mapper/3600..20c0-part1 > dump.elf
.TP
.B Copy tape dump
Tape device /dev/ntibm0 was prepared with:
.br
# zipl -d /dev/ntibm0
.br
An IPL was performed on the corresponding tape dump tool and a dump
has been created. To copy the dump from the tape to file dump.elf
issue:
.br
# zgetdump /dev/ntibm0 > dump.elf
.br
.TP
.B Create live dump
To store an ELF-format dump from a live system in a file called dump.elf
issue:
.br
# nice -n -20 zgetdump /dev/mem > dump.elf
.br
.TP
.B Using pipes for network transfer
You can redirect standard output to tools like ftp or ssh in order to
transfer the dump over the network without copying it into the file system
first.
Copy DASD dump using ssh:
.br
# zgetdump /dev/dasdd1 | ssh user@host "cat > dump.elf"
.br
Copy and compress DASD dump using ftp and gzip (note that not all ftp clients
can do this):
.br
# ftp host
ftp> put |"zgetdump /dev/dasdd1 | gzip" dump.elf.gz
.br
The same effect can also be achieved by using the "--mount" option and run
scp or ftp directly on the mounted virtual dump file.
.TP
.B Using the "--mount" option
Mount a single-volume DASD dump as virtual ELF dump file, compress
it with the makedumpfile tool, and unmount it with zgetdump:
.br
# zgetdump -m /dev/dasdc1 /dumps
# makedumpfile -c -d 31 -x vmlinux.debug \\
/dumps/dump.elf dump.kdump
# zgetdump -u /dumps
.br
Mount a multi-volume DASD dump, process it with the "crash" tool, and
unmount it with fusermount:
.br
# zgetdump -m /dev/dasdx /dumps
# crash vmlinux /dumps/dump.elf
# fusermount -u /dumps
.br
.TP
.B Print dump information (--info)
Print information about a DASD dump on /dev/dasdd1:
.br
# zgetdump -i /dev/dasdd1
.br
Print information about a dump on a device mapper multipath partition device
node of a SCSI disk:
.br
# zgetdump -i /dev/mapper/3600..20c0-part1
.br
.TP
.B Print dump tool information (--device)
Print information about a DASD dump tool on /dev/dasdd:
.br
# zgetdump -d /dev/dasdd
.br
Print information about a dump tool on a SCSI multipath device:
.br
# zgetdump -d /dev/mapper/3600..02c0
.br
.SH NOTES
The ELF dump format is not supported by the zgetdump tool under 31 bit.
While it is not recommended for reasons of recovery and redundancy, FCP
attached SCSI disks can also be accessed directly without multipathing,
for example via the "/dev/disk/by-path/" device nodes.
.SH SEE ALSO
.BR zipl (8), crash (8), makedumpfile (8), dumpconf (8), vmconvert (1), vmur (8)
.BR fdisk (8), parted (8)
+191
View File
@@ -0,0 +1,191 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* Main functions
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <linux/fs.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mtio.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "zgetdump.h"
/*
* Globals
*/
struct zgetdump_globals g;
/*
* Signal handler for exiting zgetdump (the atexit handler will do the work)
*/
static void sig_exit(int sig)
{
(void) sig;
STDERR("\n"); /* E.g. to get newline after '^C' */
ERR_EXIT("Got signal %i, exiting...", sig);
}
/*
* Install signal handler
*/
static void sig_handler_init(void)
{
struct sigaction sigact;
/* Ignore signals SIGUSR1 and SIGUSR2 */
if (sigemptyset(&sigact.sa_mask) < 0)
goto fail;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGUSR1, &sigact, NULL) < 0)
goto fail;
if (sigaction(SIGUSR2, &sigact, NULL) < 0)
goto fail;
/* Exit on SIGINT, SIGTERM, SIGHUP, ... */
if (sigemptyset(&sigact.sa_mask) < 0)
goto fail;
sigact.sa_handler = sig_exit;
if (sigaction(SIGINT, &sigact, NULL) < 0)
goto fail;
if (sigaction(SIGTERM, &sigact, NULL) < 0)
goto fail;
if (sigaction(SIGHUP, &sigact, NULL) < 0)
goto fail;
if (sigaction(SIGQUIT, &sigact, NULL) < 0)
goto fail;
if (sigaction(SIGALRM, &sigact, NULL) < 0)
goto fail;
if (sigaction(SIGPIPE, &sigact, NULL) < 0)
goto fail;
return;
fail:
ERR_EXIT_ERRNO("Could not initialize signal handler");
}
/*
* Check if dump contains kdump dump and production system dump
*/
static void kdump_select_check(void)
{
static char *msg =
"The dump contains \"kdump\" and \"production system\"\n"
" Access \"production system\" with \"-s prod\"\n"
" Access \"kdump\" with \"-s kdump\"\n"
" Access the complete dump with \"-s all\"\n"
" Send both dumps to your service organization";
if (g.opts.select_specified)
return;
if (!dfi_kdump_base())
return;
ERR_EXIT("%s", msg);
}
/*
* Run "--umount" action
*/
static int do_umount(void)
{
zfuse_umount();
return 0;
}
/*
* Run "--device" action
*/
static int do_device_info(void)
{
dt_init();
dt_info_print();
return 0;
}
/*
* Run "--info" action
*/
static int do_dump_info(void)
{
if (dfi_init() != 0) {
dfi_info_print();
STDERR("\nERROR: Dump is not complete\n");
zg_exit(1);
}
kdump_select_check();
dfi_info_print();
dfi_exit();
return 0;
}
/*
* Run "--mount" action
*/
static int do_mount(void)
{
int rc;
if (dfi_init() != 0)
ERR_EXIT("Dump cannot be processed (is not complete)");
dfo_init();
kdump_select_check();
rc = zfuse_mount_dump();
dfi_exit();
return rc;
}
/*
* Run "copy to stdout" action
*/
static int do_stdout(void)
{
int rc;
if (dfi_init() != 0)
ERR_EXIT("Dump cannot be processed (is not complete)");
dfo_init();
kdump_select_check();
rc = stdout_write_dump();
dfi_exit();
return rc;
}
/*
* The zgetdump main function
*/
int main(int argc, char *argv[])
{
sig_handler_init();
opts_parse(argc, argv);
switch (g.opts.action) {
case ZG_ACTION_STDOUT:
return do_stdout();
case ZG_ACTION_DUMP_INFO:
return do_dump_info();
case ZG_ACTION_DEVICE_INFO:
return do_device_info();
case ZG_ACTION_MOUNT:
return do_mount();
case ZG_ACTION_UMOUNT:
return do_umount();
}
ABORT("Invalid action: %i", g.opts.action);
}
+98
View File
@@ -0,0 +1,98 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* Main include file - Should be included by all source files
*
* Copyright IBM Corp. 2001, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef ZGETDUMP_H
#define ZGETDUMP_H
#include "df_elf.h"
#include "df_lkcd.h"
#include "df_s390.h"
#include "dfi.h"
#include "dfo.h"
#include "dt.h"
#include "zg.h"
/*
* zgetdump options
*/
struct options {
int action_specified;
enum zg_action action;
char *device;
char *mount_point;
int fmt_specified;
const char *fmt;
int debug_specified;
char **argv_fuse;
int argc_fuse;
const char *select;
int select_specified;
};
extern const char *OPTS_SELECT_KDUMP;
extern const char *OPTS_SELECT_PROD;
extern const char *OPTS_SELECT_ALL;
/*
* zgetdump globals
*/
extern struct zgetdump_globals {
struct zg_fh *fh;
const char *prog_name;
struct options opts;
} g;
/*
* Misc fuctions
*/
extern void opts_parse(int argc, char *argv[]);
extern int stdout_write_dump(void);
#if HAVE_FUSE == 0
static inline int zfuse_mount_dump(void)
{
ERR_EXIT("Program compiled without fuse support");
}
static inline void zfuse_umount(void)
{
ERR_EXIT("Program compiled without fuse support");
}
#else
int zfuse_mount_dump(void);
void zfuse_umount(void);
#endif
/*
* Supported DFI dump formats
*/
extern struct dfi dfi_s390tape;
extern struct dfi dfi_s390mv;
extern struct dfi dfi_s390;
extern struct dfi dfi_lkcd;
extern struct dfi dfi_elf;
extern struct dfi dfi_kdump;
extern struct dfi dfi_kdump_flat;
extern struct dfi dfi_devmem;
/*
* Supported DFO dump formats
*/
extern struct dfo dfo_s390;
extern struct dfo dfo_elf;
/*
* Supported s390 dumpers
*/
extern struct dt dt_s390mv;
extern struct dt dt_s390sv;
extern struct dt dt_scsi;
#endif /* ZGETDUMP_H */