kexec-tools/kexec-tools-1.101-reloc-update.patch

1041 lines
32 KiB
Diff
Raw Normal View History

2007-01-05 17:47:37 +00:00
--- kexec-tools-1.101/purgatory/arch/x86_64/include/arch/debug.h.orig 2004-12-20 18:05:40.000000000 -0500
2007-01-05 18:35:38 +00:00
+++ kexec-tools-1.101/purgatory/arch/x86_64/include/arch/debug.h 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -311,7 +311,7 @@
TTYS0_TX_AL
-#define DEBUG(x) TTYS0_TX_CHAR($x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
+#define DEBUG_CHAR(x) TTYS0_TX_CHAR($x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
#define DEBUG_TX_HEX32(x) TTYS0_TX_HEX32(x); TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
#define DEBUG_TX_HEX64(x) TTYS0_TX_HEX64(x); TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
2006-12-15 21:05:01 +00:00
--- kexec-tools-1.101/purgatory/arch/i386/linux-entry16.S.orig 2004-12-20 05:48:45.000000000 -0500
2007-01-05 18:35:38 +00:00
+++ kexec-tools-1.101/purgatory/arch/i386/linux-entry16.S 2007-01-05 13:32:24.000000000 -0500
2006-12-15 21:05:01 +00:00
@@ -127,10 +127,10 @@
TTYS0_TX_AL
-#define DEBUG(x) TTYS0_TX_CHAR($x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
+#define DEBUG_CHAR(x) TTYS0_TX_CHAR($x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
#define DEBUG_TX_HEX32(x) TTYS0_TX_HEX32(x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
#else
-#define DEBUG(x)
+#define DEBUG_CHAR(x)
#define DEBUG_TX_HEX32(x)
#endif
@@ -142,15 +142,15 @@
entry16:
.code32
-DEBUG('a')
+DEBUG_CHAR('a')
/* Setup the classic BIOS interrupt table at 0x0 */
lidt idtptr
-DEBUG('b')
+DEBUG_CHAR('b')
/* Provide us with 16bit segments that we can use */
lgdt gdt
-DEBUG('c')
+DEBUG_CHAR('c')
/* Note we don't disable the a20 line, (this shouldn't be required)
* The code to do it is in kexec_test and it is a real pain.
* I will worry about that when I need it.
2007-01-05 17:47:37 +00:00
@@ -164,26 +164,26 @@ DEBUG('c')
2006-12-15 21:05:01 +00:00
movl %eax, %fs
movl %eax, %gs
-DEBUG('d')
+DEBUG_CHAR('d')
/* switch to 16bit mode */
ljmp $0x08, $1f - entry16
1:
.code16
-DEBUG('e')
+DEBUG_CHAR('e')
/* Disable Paging and protected mode */
/* clear the PG & PE bits of CR0 */
movl %cr0,%eax
andl $~((1 << 31)|(1<<0)),%eax
movl %eax,%cr0
-DEBUG('f')
+DEBUG_CHAR('f')
/* make intersegment jmp to flush the processor pipeline
* and reload %cs:%eip (to clear upper 16 bits of %eip).
*/
ljmp *(realptr - entry16)
3:
-DEBUG('g')
+DEBUG_CHAR('g')
/* we are in real mode now
* set up the real mode segment registers : %ds, $ss, %es
*/
2007-01-05 17:47:37 +00:00
@@ -191,7 +191,7 @@ DEBUG('g')
2006-12-15 21:05:01 +00:00
movw %cs, %ax
movw %ax, %ds
-DEBUG('h')
+DEBUG_CHAR('h')
/* Load the registers */
movl eax - entry16, %eax
movl ebx - entry16, %ebx
2007-01-05 17:47:37 +00:00
@@ -386,10 +386,10 @@ gdt_end:
2006-12-15 21:05:01 +00:00
TTYS0_TX_AL
-#define DEBUG(x) TTYS0_TX_CHAR($x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
+#define DEBUG_CHAR(x) TTYS0_TX_CHAR($x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
#define DEBUG_TX_HEX32(x) TTYS0_TX_HEX32(x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
#else
-#define DEBUG(x)
+#define DEBUG_CHAR(x)
#define DEBUG_TX_HEX32(x)
#endif
2007-01-05 17:47:37 +00:00
@@ -403,7 +403,7 @@ setup16_debug_start:
2006-12-15 21:05:01 +00:00
_reloc = .
.balign 16
.code32
-DEBUG('a')
+DEBUG_CHAR('a')
/* Compute where I am running at */
call 1f
1: popl %ebx
2007-01-05 17:47:37 +00:00
@@ -412,13 +412,13 @@ DEBUG('a')
2006-12-15 21:05:01 +00:00
/* Remember where I am running at */
movl %ebx, location - _reloc(%ebx)
-DEBUG('b')
+DEBUG_CHAR('b')
/* Fixup my real mode segment */
movl %ebx, %eax
shrl $4, %eax
movw %ax, 2 + realptr - _reloc(%ebx)
-DEBUG('c')
+DEBUG_CHAR('c')
/* Fixup the gdt */
movl %ebx, %eax
shll $16, %eax
2007-01-05 17:47:37 +00:00
@@ -440,7 +440,7 @@ DEBUG('c')
2006-12-15 21:05:01 +00:00
-DEBUG('d')
+DEBUG_CHAR('d')
/* Setup the classic BIOS interrupt table at 0x0 */
lidt idtptr - _reloc(%ebx)
2007-01-05 17:47:37 +00:00
@@ -465,20 +465,20 @@ DEBUG('d')
2006-12-15 21:05:01 +00:00
ljmp $0x08, $2f - _reloc
2:
.code16
-DEBUG('e')
+DEBUG_CHAR('e')
/* Disable Paging and protected mode */
/* clear the PG & PE bits of CR0 */
movl %cr0,%eax
andl $~((1 << 31)|(1<<0)),%eax
movl %eax,%cr0
-DEBUG('f')
+DEBUG_CHAR('f')
/* make intersegment jmp to flush the processor pipeline
* and reload %cs:%eip (to clear upper 16 bits of %eip).
*/
ljmp *(realptr - _reloc)
3:
-DEBUG('g')
+DEBUG_CHAR('g')
/* we are in real mode now
* set up the real mode segment registers : %ds, $ss, %es
*/
2007-01-05 17:47:37 +00:00
@@ -486,7 +486,7 @@ DEBUG('g')
2006-12-15 21:05:01 +00:00
movw %cs, %ax
movw %ax, %ds
-DEBUG('h')
+DEBUG_CHAR('h')
/* Load the registers */
movl eax - _reloc, %eax
movl ebx - _reloc, %ebx
2007-01-05 17:47:37 +00:00
@@ -600,7 +600,7 @@ debug_gdt_end:
2006-12-15 21:05:01 +00:00
setup16_debug_kernel_pre_protected:
.code16
- DEBUG('i')
+ DEBUG_CHAR('i')
cli # no interrupts allowed !
movb $0x80, %al # disable NMI for bootup
# sequence
2007-01-05 17:47:37 +00:00
@@ -611,7 +611,7 @@ setup16_debug_first_code32:
2006-12-15 21:05:01 +00:00
.byte 0xbf /* movl $0x12345678, %edi */
location:
.long 0x12345678
- DEBUG('j')
+ DEBUG_CHAR('j')
.byte 0xb8 /* movl $0x10000, %eax */
setup16_debug_old_code32:
.long 0x10000
--- kexec-tools-1.101/purgatory/arch/i386/entry32-16-debug.S.orig 2004-12-20 18:11:43.000000000 -0500
2007-01-05 18:35:38 +00:00
+++ kexec-tools-1.101/purgatory/arch/i386/entry32-16-debug.S 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -55,15 +55,15 @@ entry16_debug:
2006-12-15 21:05:01 +00:00
orl %ecx, 0x14 + gdt
-DEBUG('a')
+DEBUG_CHAR('a')
/* Setup the classic BIOS interrupt table at 0x0 */
lidt idtptr
-DEBUG('b')
+DEBUG_CHAR('b')
/* Provide us with 16bit segments that we can use */
lgdt gdt
-DEBUG('c')
+DEBUG_CHAR('c')
/* Note we don't disable the a20 line, (this shouldn't be required)
* The code to do it is in kexec_test and it is a real pain.
* I will worry about that when I need it.
2007-01-05 17:47:37 +00:00
@@ -77,26 +77,26 @@ DEBUG('c')
2006-12-15 21:05:01 +00:00
movl %eax, %fs
movl %eax, %gs
-DEBUG('d')
+DEBUG_CHAR('d')
/* switch to 16bit mode */
ljmp $0x08, $1f - entry16_debug
1:
.code16
-DEBUG('e')
+DEBUG_CHAR('e')
/* Disable Paging and protected mode */
/* clear the PG & PE bits of CR0 */
movl %cr0,%eax
andl $~((1 << 31)|(1<<0)),%eax
movl %eax,%cr0
-DEBUG('f')
+DEBUG_CHAR('f')
/* make intersegment jmp to flush the processor pipeline
* and reload %cs:%eip (to clear upper 16 bits of %eip).
*/
ljmp *(realptr - entry16_debug)
3:
-DEBUG('g')
+DEBUG_CHAR('g')
/* we are in real mode now
* set up the real mode segment registers : %ds, $ss, %es
*/
2007-01-05 17:47:37 +00:00
@@ -104,7 +104,7 @@ DEBUG('g')
2006-12-15 21:05:01 +00:00
movw %cs, %ax
movw %ax, %ds
-DEBUG('h')
+DEBUG_CHAR('h')
/* Load the registers */
movl eax - entry16_debug, %eax
movl ebx - entry16_debug, %ebx
2007-01-05 17:47:37 +00:00
@@ -176,7 +176,7 @@ gdt_end:
2006-12-15 21:05:01 +00:00
.text
entry16_debug_pre32:
.code16
-DEBUG('i')
+DEBUG_CHAR('i')
cli # no interrupts allowed !
movb $0x80, %al # disable NMI for bootup
# sequence
2007-01-05 17:47:37 +00:00
@@ -186,7 +186,7 @@ DEBUG('i')
2006-12-15 21:05:01 +00:00
entry16_debug_first32:
.code32
-DEBUG('j')
+DEBUG_CHAR('j')
.byte 0xb8 /* movl $0x10000, %eax */
entry16_debug_old_first32:
.long 0x100000
2007-01-05 17:47:37 +00:00
--- kexec-tools-1.101/purgatory/arch/i386/include/arch/debug.h.orig 2004-12-20 18:03:17.000000000 -0500
2007-01-05 18:35:38 +00:00
+++ kexec-tools-1.101/purgatory/arch/i386/include/arch/debug.h 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -311,6 +311,6 @@
2006-12-15 21:05:01 +00:00
TTYS0_TX_AL
-#define DEBUG(x) TTYS0_TX_CHAR($x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
+#define DEBUG_CHAR(x) TTYS0_TX_CHAR($x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
#define DEBUG_TX_HEX32(x) TTYS0_TX_HEX32(x); TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
#define DEBUG_TX_HEX64(x) TTYS0_TX_HEX64(x); TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
2007-01-05 18:35:38 +00:00
--- kexec-tools-1.101/kexec/Makefile.orig 2007-01-05 13:32:05.000000000 -0500
+++ kexec-tools-1.101/kexec/Makefile 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -13,6 +13,7 @@ KEXEC_C_SRCS:= kexec/kexec.c
2006-12-15 21:05:01 +00:00
KEXEC_C_SRCS+= kexec/ifdown.c
KEXEC_C_SRCS+= kexec/kexec-elf.c
KEXEC_C_SRCS+= kexec/kexec-elf-exec.c
+KEXEC_C_SRCS+= kexec/kexec-elf-core.c
KEXEC_C_SRCS+= kexec/kexec-elf-rel.c
KEXEC_C_SRCS+= kexec/kexec-elf-boot.c
KEXEC_C_SRCS+= kexec/crashdump.c
2007-01-05 18:35:38 +00:00
--- kexec-tools-1.101/kexec/kexec-elf-rel.c.orig 2007-01-05 13:32:05.000000000 -0500
+++ kexec-tools-1.101/kexec/kexec-elf-rel.c 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -135,10 +135,11 @@ static struct mem_rela elf_rela(struct m
return rela;
}
2006-12-15 21:05:01 +00:00
2007-01-05 17:47:37 +00:00
-int build_elf_rel_info(const char *buf, off_t len, struct mem_ehdr *ehdr)
+int build_elf_rel_info(const char *buf, off_t len, struct mem_ehdr *ehdr,
2006-12-15 21:05:01 +00:00
+ uint32_t flags)
{
int result;
- result = build_elf_info(buf, len, ehdr);
+ result = build_elf_info(buf, len, ehdr, flags);
if (result < 0) {
return result;
}
2007-01-05 17:47:37 +00:00
@@ -412,12 +413,12 @@ int elf_rel_load(struct mem_ehdr *ehdr,
2006-12-15 21:05:01 +00:00
2007-01-05 17:47:37 +00:00
void elf_rel_build_load(struct kexec_info *info, struct mem_ehdr *ehdr,
const char *buf, off_t len, unsigned long min, unsigned long max,
- int end)
+ int end, uint32_t flags)
2006-12-15 21:05:01 +00:00
{
int result;
2007-01-05 17:47:37 +00:00
2006-12-15 21:05:01 +00:00
/* Parse the Elf file */
2007-01-05 17:47:37 +00:00
- result = build_elf_rel_info((char *)purgatory, purgatory_size, ehdr);
+ result = build_elf_rel_info(buf, len, ehdr, flags);
2006-12-15 21:05:01 +00:00
if (result < 0) {
2007-01-05 17:47:37 +00:00
die("ELF rel parse failed\n");
2006-12-15 21:05:01 +00:00
}
2007-01-05 18:35:38 +00:00
--- kexec-tools-1.101/kexec/kexec-elf.c.orig 2007-01-05 13:32:05.000000000 -0500
+++ kexec-tools-1.101/kexec/kexec-elf.c 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -368,7 +368,8 @@ static int build_mem_elf64_phdr(const ch
return 0;
2006-12-15 21:05:01 +00:00
}
2007-01-05 17:47:37 +00:00
-static int build_mem_phdrs(const char *buf, off_t len, struct mem_ehdr *ehdr)
+static int build_mem_phdrs(const char *buf, off_t len, struct mem_ehdr *ehdr,
+ uint32_t flags)
2006-12-15 21:05:01 +00:00
{
2007-01-05 17:47:37 +00:00
size_t phdr_size, mem_phdr_size;
int i;
@@ -418,9 +419,11 @@ static int build_mem_phdrs(const char *b
2006-12-15 21:05:01 +00:00
2007-01-05 17:47:37 +00:00
/* Check the program headers to be certain
* they are safe to use.
+ * Skip the check if ELF_SKIP_FILESZ_CHECK is set.
*/
phdr = &ehdr->e_phdr[i];
- if ((phdr->p_offset + phdr->p_filesz) > len) {
+ if (!(flags & ELF_SKIP_FILESZ_CHECK)
+ && (phdr->p_offset + phdr->p_filesz) > len) {
/* The segment does not fit in the buffer */
if (probe_debug) {
fprintf(stderr, "ELF segment not in file\n");
@@ -580,7 +583,8 @@ static int build_mem_elf64_shdr(const ch
return 0;
}
2006-12-15 21:05:01 +00:00
2007-01-05 17:47:37 +00:00
-static int build_mem_shdrs(const char *buf, off_t len, struct mem_ehdr *ehdr)
+static int build_mem_shdrs(const char *buf, off_t len, struct mem_ehdr *ehdr,
+ uint32_t flags)
{
size_t shdr_size, mem_shdr_size;
int i;
@@ -628,11 +632,12 @@ static int build_mem_shdrs(const char *b
}
/* Check the section headers to be certain
* they are safe to use.
+ * Skip the check if ELF_SKIP_FILESZ_CHECK is set.
*/
shdr = &ehdr->e_shdr[i];
- if ((shdr->sh_type != SHT_NOBITS) &&
- ((shdr->sh_offset + shdr->sh_size) > len))
- {
+ if (!(flags & ELF_SKIP_FILESZ_CHECK)
+ && (shdr->sh_type != SHT_NOBITS)
+ && (shdr->sh_offset + shdr->sh_size) > len) {
/* The section does not fit in the buffer */
if (probe_debug) {
fprintf(stderr, "ELF section %d not in file\n",
@@ -710,7 +715,8 @@ static int build_mem_notes(const char *b
note_size += (hdr.n_descsz + 3) & ~3;
2006-12-15 21:05:01 +00:00
2007-01-05 17:47:37 +00:00
if ((hdr.n_namesz != 0) && (name[hdr.n_namesz -1] != '\0')) {
- die("Note name is not null termiated");
+ fprintf(stderr, "Note name is not null termiated\n");
+ return -1;
}
ehdr->e_note[i].n_type = hdr.n_type;
ehdr->e_note[i].n_name = (char *)name;
@@ -729,7 +735,8 @@ void free_elf_info(struct mem_ehdr *ehdr
memset(ehdr, 0, sizeof(*ehdr));
}
-int build_elf_info(const char *buf, off_t len, struct mem_ehdr *ehdr)
+int build_elf_info(const char *buf, off_t len, struct mem_ehdr *ehdr,
+ uint32_t flags)
{
2006-12-15 21:05:01 +00:00
int result;
2007-01-05 17:47:37 +00:00
result = build_mem_ehdr(buf, len, ehdr);
@@ -737,14 +744,14 @@ int build_elf_info(const char *buf, off_
return result;
2006-12-15 21:05:01 +00:00
}
2007-01-05 17:47:37 +00:00
if ((ehdr->e_phoff > 0) && (ehdr->e_phnum > 0)) {
- result = build_mem_phdrs(buf, len, ehdr);
+ result = build_mem_phdrs(buf, len, ehdr, flags);
if (result < 0) {
free_elf_info(ehdr);
return result;
}
2006-12-15 21:05:01 +00:00
}
2007-01-05 17:47:37 +00:00
if ((ehdr->e_shoff > 0) && (ehdr->e_shnum > 0)) {
- result = build_mem_shdrs(buf, len, ehdr);
+ result = build_mem_shdrs(buf, len, ehdr, flags);
if (result < 0) {
free_elf_info(ehdr);
return result;
2007-01-05 18:35:38 +00:00
--- kexec-tools-1.101/kexec/arch/ia64/kexec-elf-ia64.c.orig 2007-01-05 13:32:05.000000000 -0500
+++ kexec-tools-1.101/kexec/arch/ia64/kexec-elf-ia64.c 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -56,7 +56,7 @@ int elf_ia64_probe(const char *buf, off_
{
2006-12-15 21:05:01 +00:00
struct mem_ehdr ehdr;
int result;
- result = build_elf_exec_info(buf, len, &ehdr);
+ result = build_elf_exec_info(buf, len, &ehdr, 0);
if (result < 0) {
2007-01-05 17:47:37 +00:00
if (probe_debug) {
fprintf(stderr, "Not an ELF executable\n");
@@ -163,7 +163,7 @@ int elf_ia64_load(int argc, char **argv,
2006-12-15 21:05:01 +00:00
}
/* Parse the Elf file */
- result = build_elf_exec_info(buf, len, &ehdr);
+ result = build_elf_exec_info(buf, len, &ehdr, 0);
if (result < 0) {
2007-01-05 17:47:37 +00:00
fprintf(stderr, "ELF parse failed\n");
2006-12-15 21:05:01 +00:00
free_elf_info(&ehdr);
2007-01-05 17:47:37 +00:00
@@ -198,7 +198,7 @@ int elf_ia64_load(int argc, char **argv,
2006-12-15 21:05:01 +00:00
2007-01-05 17:47:37 +00:00
/* Load the setup code */
elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size,
- 0x0, ULONG_MAX, -1);
+ 0x0, ULONG_MAX, -1, 0);
2006-12-15 21:05:01 +00:00
2007-01-05 17:47:37 +00:00
if (load_crashdump_segments(info, &ehdr, max_addr, 0,
2007-01-05 18:35:38 +00:00
--- kexec-tools-1.101/kexec/arch/x86_64/crashdump-x86_64.c.orig 2007-01-05 13:32:05.000000000 -0500
+++ kexec-tools-1.101/kexec/arch/x86_64/crashdump-x86_64.c 2007-01-05 13:32:24.000000000 -0500
2006-12-15 21:05:01 +00:00
@@ -24,8 +24,10 @@
#include <errno.h>
#include <limits.h>
#include <elf.h>
+#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/mman.h>
#include <unistd.h>
#include "../../kexec.h"
#include "../../kexec-elf.h"
2007-01-05 17:47:37 +00:00
@@ -40,6 +42,137 @@ extern struct arch_options_t arch_option
2006-12-15 21:05:01 +00:00
/* Forward Declaration. */
static int exclude_crash_reserve_region(int *nr_ranges);
+#define KERN_VADDR_ALIGN 0x200000 /* 2MB */
+
+/* Read kernel physical load addr from /proc/iomem (Kernel Code) and
+ * store in kexec_info */
+static int get_kernel_paddr(struct kexec_info *info)
+{
+ const char iomem[]= "/proc/iomem";
+ char line[MAX_LINE];
+ FILE *fp;
+ unsigned long long start, end;
+
+ fp = fopen(iomem, "r");
+ if (!fp) {
+ fprintf(stderr, "Cannot open %s: %s\n", iomem, strerror(errno));
+ return -1;
+ }
+ while(fgets(line, sizeof(line), fp) != 0) {
+ char *str;
+ int consumed, count;
+ count = sscanf(line, "%Lx-%Lx : %n",
+ &start, &end, &consumed);
+ if (count != 2)
+ continue;
+ str = line + consumed;
+#ifdef DEBUG
+ printf("%016Lx-%016Lx : %s",
+ start, end, str);
+#endif
+ if (memcmp(str, "Kernel code\n", 12) == 0) {
+ info->kern_paddr_start = start;
+
+#ifdef DEBUG
+ printf("kernel load physical addr start = 0x%016Lx\n",
+ start);
+#endif
+ fclose(fp);
+ return 0;
+ }
+ }
+ fprintf(stderr, "Cannot determine kernel physical load addr\n");
+ fclose(fp);
+ return -1;
+}
+
+/* Hardcoding kernel virtual address and size. While writting
+ * this patch vanilla kernel is compiled for addr 2MB. Anybody
+ * using kernel older than that which was compiled for 1MB
+ * physical addr, use older version of kexec-tools. This function
+ * is there just for backward compatibility reasons and we should
+ * get rid of it at some point of time.
+ */
+
+static int hardcode_kernel_vaddr_size(struct kexec_info *info)
+{
+ fprintf(stderr, "Warning: Hardcoding kernel virtual addr and size\n");
+ info->kern_vaddr_start = __START_KERNEL_map + 0x200000;
+ info->kern_size = KERNEL_TEXT_SIZE - 0x200000;
+ fprintf(stderr, "Warning: virtual addr = 0x%lx size = 0x%lx\n",
+ info->kern_vaddr_start, info->kern_size);
+ return 0;
+}
+
+/* Retrieve info regarding virtual address kernel has been compiled for and
+ * size of the kernel from /proc/kcore. Current /proc/kcore parsing from
+ * from kexec-tools fails because of malformed elf notes. A kernel patch has
+ * been submitted. For the folks using older kernels, this function
+ * hard codes the values to remain backward compatible. Once things stablize
+ * we should get rid of backward compatible code. */
+
+static int get_kernel_vaddr_and_size(struct kexec_info *info)
+{
+ int result;
+ const char kcore[] = "/proc/kcore";
+ char *buf;
+ struct mem_ehdr ehdr;
+ struct mem_phdr *phdr, *end_phdr;
+ int align;
+ unsigned long size;
+ uint32_t elf_flags = 0;
+
+ align = getpagesize();
+ size = KCORE_ELF_HEADERS_SIZE;
+ buf = slurp_file_len(kcore, size);
+ if (!buf) {
+ fprintf(stderr, "Cannot read %s: %s\n", kcore, strerror(errno));
+ return -1;
+ }
+
+ /* Don't perform checks to make sure stated phdrs and shdrs are
+ * actually present in the core file. It is not practical
+ * to read the GB size file into a user space buffer, Given the
+ * fact that we don't use any info from that.
+ */
+ elf_flags |= ELF_SKIP_FILESZ_CHECK;
+ result = build_elf_core_info(buf, size, &ehdr, elf_flags);
+ if (result < 0) {
+ fprintf(stderr, "ELF core (kcore) parse failed\n");
+ hardcode_kernel_vaddr_size(info);
+ return 0;
+ }
+
+ /* Traverse through the Elf headers and find the region where
+ * kernel is mapped. */
+ end_phdr = &ehdr.e_phdr[ehdr.e_phnum];
+ for(phdr = ehdr.e_phdr; phdr != end_phdr; phdr++) {
+ if (phdr->p_type == PT_LOAD) {
+ unsigned long saddr = phdr->p_vaddr;
+ unsigned long eaddr = phdr->p_vaddr + phdr->p_memsz;
+ unsigned long size;
+
+ /* Look for kernel text mapping header. */
+ if ((saddr >= __START_KERNEL_map) &&
+ (eaddr <= __START_KERNEL_map + KERNEL_TEXT_SIZE)) {
+ saddr = (saddr) & (~(KERN_VADDR_ALIGN - 1));
+ info->kern_vaddr_start = saddr;
+ size = eaddr - saddr;
+ /* Align size to page size boundary. */
+ size = (size + align - 1) & (~(align - 1));
+ info->kern_size = size;
+#ifdef DEBUG
+ printf("kernel vaddr = 0x%lx size = 0x%lx\n",
+ saddr, size);
+#endif
+ return 0;
+ }
+ }
+ }
+ fprintf(stderr, "Can't find kernel text map area from kcore\n");
+ return -1;
+}
+
/* Stores a sorted list of RAM memory ranges for which to create elf headers.
* A separate program header is created for backup region */
static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
2007-01-05 17:47:37 +00:00
@@ -245,7 +378,7 @@ static int add_memmap(struct memory_rang
2006-12-15 21:05:01 +00:00
memmap_p[j+1] = memmap_p[j];
memmap_p[tidx].start = addr;
memmap_p[tidx].end = addr + size - 1;
-#if 0
+#ifdef DEBUG
printf("Memmap after adding segment\n");
for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) {
mstart = memmap_p[i].start;
2007-01-05 17:47:37 +00:00
@@ -330,7 +463,7 @@ static int delete_memmap(struct memory_r
2006-12-15 21:05:01 +00:00
memmap_p[j-1] = memmap_p[j];
memmap_p[j-1].start = memmap_p[j-1].end = 0;
}
-#if 0
+#ifdef DEBUG
printf("Memmap after deleting segment\n");
for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) {
mstart = memmap_p[i].start;
2007-01-05 17:47:37 +00:00
@@ -404,7 +537,7 @@ static int cmdline_add_memmap(char *cmdl
2006-12-15 21:05:01 +00:00
die("Command line overflow\n");
strcat(cmdline, str_mmap);
}
-#if 0
+#ifdef DEBUG
printf("Command line after adding memmap\n");
printf("%s\n", cmdline);
#endif
2007-01-05 17:47:37 +00:00
@@ -432,7 +565,7 @@ static int cmdline_add_elfcorehdr(char *
2006-12-15 21:05:01 +00:00
if (cmdlen > (COMMAND_LINE_SIZE - 1))
die("Command line overflow\n");
strcat(cmdline, str);
-#if 0
+#ifdef DEBUG
printf("Command line after adding elfcorehdr\n");
printf("%s\n", cmdline);
#endif
2007-01-05 17:47:37 +00:00
@@ -465,7 +598,7 @@ static int cmdline_add_memmap_acpi(char
2006-12-15 21:05:01 +00:00
die("Command line overflow\n");
strcat(cmdline, str_mmap);
-#if 0
+#ifdef DEBUG
printf("Command line after adding acpi memmap\n");
printf("%s\n", cmdline);
#endif
2007-01-05 17:47:37 +00:00
@@ -536,6 +669,27 @@ static int prepare_crash_memory_elf64_he
2006-12-15 21:05:01 +00:00
(elf->e_phnum)++;
}
+ /* Setup an PT_LOAD type program header for the region where
+ * Kernel is mapped.
+ */
+ phdr = (Elf64_Phdr *) bufp;
+ bufp += sizeof(Elf64_Phdr);
+ phdr->p_type = PT_LOAD;
+ phdr->p_flags = PF_R|PF_W|PF_X;
+ phdr->p_offset = phdr->p_paddr = info->kern_paddr_start;
+ phdr->p_vaddr = info->kern_vaddr_start;
+ phdr->p_filesz = phdr->p_memsz = info->kern_size;
+ phdr->p_align = 0;
+ (elf->e_phnum)++;
+#ifdef DEBUG
+ printf("Kernel text Elf header: p_type = %d, p_offset = 0x%lx "
+ "p_paddr = 0x%lx p_vaddr = 0x%lx "
+ "p_filesz = 0x%lx p_memsz = 0x%lx\n",
+ phdr->p_type, phdr->p_offset, phdr->p_paddr,
+ phdr->p_vaddr, phdr->p_filesz, phdr->p_memsz);
+#endif
+
+
/* Setup PT_LOAD type program header for every system RAM chunk.
* A seprate program header for Backup Region*/
for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) {
2007-01-05 17:47:37 +00:00
@@ -555,21 +709,13 @@ static int prepare_crash_memory_elf64_he
2006-12-15 21:05:01 +00:00
else
phdr->p_offset = mstart;
- /* Handle linearly mapped region.*/
+ /* We already prepared the header for kernel text. Map
+ * rest of the memory segments to kernel linearly mapped
+ * memory region.
+ */
- /* Filling the vaddr conditionally as we have two linearly
- * mapped regions here. One is __START_KERNEL_map 0 to 40 MB
- * other one is PAGE_OFFSET */
-
- if ((mend <= (MAXMEM - 1)) && mstart < KERNEL_TEXT_SIZE)
- phdr->p_vaddr = mstart + __START_KERNEL_map;
- else {
- if (mend <= (MAXMEM - 1))
- phdr->p_vaddr = mstart + PAGE_OFFSET;
- else
- phdr->p_vaddr = -1ULL;
- }
phdr->p_paddr = mstart;
+ phdr->p_vaddr = mstart + PAGE_OFFSET;
phdr->p_filesz = phdr->p_memsz = mend - mstart + 1;
/* Do we need any alignment of segments? */
phdr->p_align = 0;
2007-01-05 17:47:37 +00:00
@@ -593,6 +739,12 @@ int load_crashdump_segments(struct kexec
2006-12-15 21:05:01 +00:00
long int nr_cpus = 0;
struct memory_range *mem_range, *memmap_p;
+ if (get_kernel_paddr(info))
+ return -1;
+
+ if (get_kernel_vaddr_and_size(info))
+ return -1;
+
if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0)
return -1;
2007-01-05 17:47:37 +00:00
@@ -638,7 +790,7 @@ int load_crashdump_segments(struct kexec
2006-12-15 21:05:01 +00:00
* This is a makeshift solution until it is fixed in kernel.
*/
elfcorehdr = add_buffer(info, tmp, sz, 16*1024, align, min_base,
- max_addr, 1);
+ max_addr, -1);
if (delete_memmap(memmap_p, elfcorehdr, sz) < 0)
return -1;
cmdline_add_memmap(mod_cmdline, memmap_p);
2007-01-05 17:47:37 +00:00
--- kexec-tools-1.101/kexec/arch/x86_64/kexec-elf-rel-x86_64.c.orig 2004-12-21 12:51:24.000000000 -0500
2007-01-05 18:35:38 +00:00
+++ kexec-tools-1.101/kexec/arch/x86_64/kexec-elf-rel-x86_64.c 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -60,7 +60,7 @@ static const char *reloc_name(unsigned l
void machine_apply_elf_rel(struct mem_ehdr *ehdr, unsigned long r_type,
void *location, unsigned long address, unsigned long value)
2006-12-15 21:05:01 +00:00
{
2007-01-05 17:47:37 +00:00
-#if 0
+#ifdef DEBUG
fprintf(stderr, "%s\n", reloc_name(r_type));
#endif
switch(r_type) {
2007-01-05 18:35:38 +00:00
--- kexec-tools-1.101/kexec/arch/x86_64/kexec-elf-x86_64.c.orig 2007-01-05 13:32:05.000000000 -0500
+++ kexec-tools-1.101/kexec/arch/x86_64/kexec-elf-x86_64.c 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -47,7 +47,7 @@ int elf_x86_64_probe(const char *buf, of
2006-12-15 21:05:01 +00:00
struct mem_ehdr ehdr;
int result;
- result = build_elf_exec_info(buf, len, &ehdr);
+ result = build_elf_exec_info(buf, len, &ehdr, 0);
if (result < 0) {
if (probe_debug) {
fprintf(stderr, "Not an ELF executable\n");
2007-01-05 17:47:37 +00:00
@@ -177,7 +177,7 @@ int elf_x86_64_load(int argc, char **arg
2006-12-15 21:05:01 +00:00
}
2007-01-05 17:47:37 +00:00
/* Load the ELF executable */
- elf_exec_build_load(info, &ehdr, buf, len);
+ elf_exec_build_load(info, &ehdr, buf, len, 0);
entry = ehdr.e_entry;
max_addr = elf_max_addr(&ehdr);
@@ -186,7 +186,7 @@ int elf_x86_64_load(int argc, char **arg
if (arg_style != ARG_STYLE_NONE) {
/* Load the setup code */
elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size,
- 0, ULONG_MAX, 1);
+ 0, ULONG_MAX, 1, 0);
}
if (arg_style == ARG_STYLE_NONE) {
info->entry = (void *)entry;
2007-01-05 18:35:38 +00:00
--- kexec-tools-1.101/kexec/arch/x86_64/kexec-x86_64.c.orig 2007-01-05 13:32:05.000000000 -0500
+++ kexec-tools-1.101/kexec/arch/x86_64/kexec-x86_64.c 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -64,7 +64,7 @@ int get_memory_ranges(struct memory_rang
continue;
str = line + consumed;
end = end + 1;
-#if 0
+#ifdef DEBUG
printf("%016Lx-%016Lx : %s",
start, end, str);
#endif
@@ -104,7 +104,7 @@ int get_memory_ranges(struct memory_rang
memory_range[memory_ranges].start = start;
memory_range[memory_ranges].end = end;
memory_range[memory_ranges].type = type;
-#if 0
+#ifdef DEBUG
printf("%016Lx-%016Lx : %x\n",
start, end, type);
#endif
2007-01-05 18:35:38 +00:00
--- kexec-tools-1.101/kexec/arch/i386/kexec-elf-x86.c.orig 2007-01-05 13:32:05.000000000 -0500
+++ kexec-tools-1.101/kexec/arch/i386/kexec-elf-x86.c 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -47,7 +47,7 @@ int elf_x86_probe(const char *buf, off_t
struct mem_ehdr ehdr;
int result;
2006-12-15 21:05:01 +00:00
- result = build_elf_exec_info(buf, len, &ehdr);
+ result = build_elf_exec_info(buf, len, &ehdr, 0);
if (result < 0) {
2007-01-05 17:47:37 +00:00
if (probe_debug) {
fprintf(stderr, "Not an ELF executable\n");
@@ -177,7 +177,7 @@ int elf_x86_load(int argc, char **argv,
}
/* Load the ELF executable */
- elf_exec_build_load(info, &ehdr, buf, len);
+ elf_exec_build_load(info, &ehdr, buf, len, 0);
entry = ehdr.e_entry;
max_addr = elf_max_addr(&ehdr);
@@ -186,7 +186,7 @@ int elf_x86_load(int argc, char **argv,
if (arg_style != ARG_STYLE_NONE) {
/* Load the setup code */
elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size,
- 0, ULONG_MAX, 1);
+ 0, ULONG_MAX, 1, 0);
}
if (arg_style == ARG_STYLE_NONE) {
info->entry = (void *)entry;
2007-01-05 18:35:38 +00:00
--- kexec-tools-1.101/kexec/arch/i386/kexec-multiboot-x86.c.orig 2007-01-05 13:32:05.000000000 -0500
+++ kexec-tools-1.101/kexec/arch/i386/kexec-multiboot-x86.c 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -209,10 +209,11 @@ int multiboot_x86_load(int argc, char **
/* Load the ELF executable */
- elf_exec_build_load(info, &ehdr, buf, len);
+ elf_exec_build_load(info, &ehdr, buf, len, 0);
2006-12-15 21:05:01 +00:00
/* Load the setup code */
2007-01-05 17:47:37 +00:00
- elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size, 0, ULONG_MAX, 1);
+ elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size, 0,
+ ULONG_MAX, 1, 0);
/* The first segment will contain the multiboot headers:
* =============
--- kexec-tools-1.101/kexec/arch/ppc/kexec-elf-ppc.c.orig 2005-01-20 14:10:56.000000000 -0500
2007-01-05 18:35:38 +00:00
+++ kexec-tools-1.101/kexec/arch/ppc/kexec-elf-ppc.c 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -72,7 +72,7 @@ int elf_ppc_probe(const char *buf, off_t
2006-12-15 21:05:01 +00:00
2007-01-05 17:47:37 +00:00
struct mem_ehdr ehdr;
int result;
- result = build_elf_exec_info(buf, len, &ehdr);
+ result = build_elf_exec_info(buf, len, &ehdr, 0);
if (result < 0) {
goto out;
}
@@ -180,7 +180,7 @@ int elf_ppc_load(int argc, char **argv,
}
/* Parse the Elf file */
- result = build_elf_exec_info(buf, len, &ehdr);
+ result = build_elf_exec_info(buf, len, &ehdr, 0);
if (result < 0) {
free_elf_info(&ehdr);
return result;
2007-01-05 18:35:38 +00:00
--- kexec-tools-1.101/kexec/arch/ppc64/kexec-elf-ppc64.c.orig 2007-01-05 13:32:05.000000000 -0500
+++ kexec-tools-1.101/kexec/arch/ppc64/kexec-elf-ppc64.c 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -52,7 +52,7 @@ int elf_ppc64_probe(const char *buf, off
2006-12-15 21:05:01 +00:00
{
struct mem_ehdr ehdr;
int result;
- result = build_elf_exec_info(buf, len, &ehdr);
+ result = build_elf_exec_info(buf, len, &ehdr, 0);
if (result < 0) {
goto out;
}
2007-01-05 17:47:37 +00:00
@@ -163,7 +163,7 @@ int elf_ppc64_load(int argc, char **argv
2006-12-15 21:05:01 +00:00
}
/* Parse the Elf file */
- result = build_elf_exec_info(buf, len, &ehdr);
+ result = build_elf_exec_info(buf, len, &ehdr, 0);
if (result < 0) {
free_elf_info(&ehdr);
return result;
2007-01-05 17:47:37 +00:00
@@ -213,7 +213,7 @@ int elf_ppc64_load(int argc, char **argv
2006-12-15 21:05:01 +00:00
memcpy(seg_buf, purgatory, purgatory_size);
seg_size = purgatory_size;
elf_rel_build_load(info, &info->rhdr, (const char *)purgatory,
- purgatory_size, 0, max_addr, 1);
+ purgatory_size, 0, max_addr, 1, 0);
/* Add a ram-disk to the current image
* Note: Add the ramdisk after elf_rel_build_load
2007-01-05 17:47:37 +00:00
--- /dev/null 2006-12-27 08:05:56.458406418 -0500
2007-01-05 18:35:38 +00:00
+++ kexec-tools-1.101/kexec/kexec-elf-core.c 2007-01-05 13:32:24.000000000 -0500
2006-12-15 21:05:01 +00:00
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "elf.h"
+#include "kexec-elf.h"
+
+
+int build_elf_core_info(const char *buf, off_t len, struct mem_ehdr *ehdr,
+ uint32_t flags)
+{
+ int result;
+ result = build_elf_info(buf, len, ehdr, flags);
+ if (result < 0) {
+ return result;
+ }
+ if ((ehdr->e_type != ET_CORE)) {
+ /* not an ELF Core */
+ fprintf(stderr, "Not ELF type ET_CORE\n");
+ return -1;
+ }
+ if (!ehdr->e_phdr) {
+ /* No program header */
+ fprintf(stderr, "No ELF program header\n");
+ return -1;
+ }
+
+ return 0;
+}
2007-01-05 18:35:38 +00:00
--- kexec-tools-1.101/kexec/kexec-elf.h.orig 2007-01-05 13:32:05.000000000 -0500
+++ kexec-tools-1.101/kexec/kexec-elf.h 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -82,22 +82,29 @@ typedef struct
2006-12-15 21:05:01 +00:00
uint32_t n_type; /* Type of the note. */
} ElfNN_Nhdr;
+/* Misc flags */
+#define ELF_SKIP_FILESZ_CHECK 0x00000001
extern void free_elf_info(struct mem_ehdr *ehdr);
-extern int build_elf_info(const char *buf, off_t len, struct mem_ehdr *ehdr);
-extern int build_elf_exec_info(const char *buf, off_t len, struct mem_ehdr *ehdr);
-extern int build_elf_rel_info(const char *buf, off_t len, struct mem_ehdr *ehdr);
+extern int build_elf_info(const char *buf, off_t len, struct mem_ehdr *ehdr,
+ uint32_t flags);
+extern int build_elf_exec_info(const char *buf, off_t len,
+ struct mem_ehdr *ehdr, uint32_t flags);
+extern int build_elf_rel_info(const char *buf, off_t len, struct mem_ehdr *ehdr,
+ uint32_t flags);
+extern int build_elf_core_info(const char *buf, off_t len,
+ struct mem_ehdr *ehdr, uint32_t flags);
extern int elf_exec_load(struct mem_ehdr *ehdr, struct kexec_info *info);
extern int elf_rel_load(struct mem_ehdr *ehdr, struct kexec_info *info,
unsigned long min, unsigned long max, int end);
extern void elf_exec_build_load(struct kexec_info *info, struct mem_ehdr *ehdr,
- const char *buf, off_t len);
+ const char *buf, off_t len, uint32_t flags);
extern void elf_rel_build_load(struct kexec_info *info, struct mem_ehdr *ehdr,
const char *buf, off_t len, unsigned long min, unsigned long max,
- int end);
+ int end, uint32_t flags);
extern int elf_rel_find_symbol(struct mem_ehdr *ehdr,
const char *name, struct mem_sym *ret_sym);
2007-01-05 18:35:38 +00:00
--- kexec-tools-1.101/kexec/kexec-elf-exec.c.orig 2007-01-05 13:32:05.000000000 -0500
+++ kexec-tools-1.101/kexec/kexec-elf-exec.c 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -11,11 +11,12 @@
static const int probe_debug = 0;
-int build_elf_exec_info(const char *buf, off_t len, struct mem_ehdr *ehdr)
+int build_elf_exec_info(const char *buf, off_t len, struct mem_ehdr *ehdr,
+ uint32_t flags)
{
struct mem_phdr *phdr, *end_phdr;
int result;
- result = build_elf_info(buf, len, ehdr);
+ result = build_elf_info(buf, len, ehdr, flags);
if (result < 0) {
return result;
}
@@ -136,11 +137,11 @@ int elf_exec_load(struct mem_ehdr *ehdr,
}
void elf_exec_build_load(struct kexec_info *info, struct mem_ehdr *ehdr,
- const char *buf, off_t len)
+ const char *buf, off_t len, uint32_t flags)
{
int result;
/* Parse the Elf file */
- result = build_elf_exec_info(buf, len, ehdr);
+ result = build_elf_exec_info(buf, len, ehdr, flags);
if (result < 0) {
die("ELF exec parse failed\n");
}
2007-01-05 18:35:38 +00:00
--- kexec-tools-1.101/kexec/crashdump.h.orig 2007-01-05 13:32:05.000000000 -0500
+++ kexec-tools-1.101/kexec/crashdump.h 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -5,5 +5,7 @@ extern int get_crash_notes_per_cpu(int c
/* Need to find a better way to determine per cpu notes section size. */
#define MAX_NOTE_BYTES 1024
+/* Expecting ELF headers to fit in 4K. Increase it if you need more. */
+#define KCORE_ELF_HEADERS_SIZE 4096
#endif /* CRASHDUMP_H */
2007-01-05 18:35:38 +00:00
--- kexec-tools-1.101/kexec/kexec.h.orig 2007-01-05 13:32:05.000000000 -0500
+++ kexec-tools-1.101/kexec/kexec.h 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -116,6 +116,9 @@ struct kexec_info {
struct mem_ehdr rhdr;
unsigned long backup_start;
unsigned long kexec_flags;
+ unsigned long kern_vaddr_start;
+ unsigned long kern_paddr_start;
+ unsigned long kern_size;
};
void usage(void);
@@ -177,6 +180,7 @@ extern void die(char *fmt, ...);
extern void *xmalloc(size_t size);
extern void *xrealloc(void *ptr, size_t size);
extern char *slurp_file(const char *filename, off_t *r_size);
+extern char *slurp_file_len(const char *filename, off_t size);
extern char *slurp_decompress_file(const char *filename, off_t *r_size);
extern void add_segment(struct kexec_info *info,
const void *buf, size_t bufsz, unsigned long base, size_t memsz);
2007-01-05 18:35:38 +00:00
--- kexec-tools-1.101/kexec/kexec.c.orig 2007-01-05 13:32:05.000000000 -0500
+++ kexec-tools-1.101/kexec/kexec.c 2007-01-05 13:32:24.000000000 -0500
2007-01-05 17:47:37 +00:00
@@ -391,6 +391,50 @@ char *slurp_file(const char *filename, o
return buf;
}
+/* This functions reads either specified number of bytes from the file or
+ lesser if EOF is met. */
+
+char *slurp_file_len(const char *filename, off_t size)
+{
+ int fd;
+ char *buf;
+ off_t progress;
+ ssize_t result;
+
+ if (!filename)
+ return 0;
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot open %s: %s\n", filename,
+ strerror(errno));
+ return 0;
+ }
+ buf = xmalloc(size);
+ progress = 0;
+ while(progress < size) {
+ result = read(fd, buf + progress, size - progress);
+ if (result < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+ fprintf(stderr, "read on %s of %ld bytes failed: %s\n",
+ filename, (size - progress)+ 0UL,
+ strerror(errno));
+ free(buf);
+ return 0;
+ }
+ if (result == 0)
+ /* EOF */
+ break;
+ progress += result;
+ }
+ result = close(fd);
+ if (result < 0) {
+ die("Close of %s failed: %s\n",
+ filename, strerror(errno));
+ }
+ return buf;
+}
+
#if HAVE_ZLIB_H
char *slurp_decompress_file(const char *filename, off_t *r_size)
{