summaryrefslogtreecommitdiffstats
path: root/util_lib
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 02:56:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 02:56:35 +0000
commiteba0cfa6b0bef4f2e73c8630a7efa3944df8b0f8 (patch)
tree74c37eede1f0634cc5de1c63c934edaa1630c6bc /util_lib
parentInitial commit. (diff)
downloadkexec-tools-7bbe6b040c9123991377749057cfc0356c289ceb.tar.xz
kexec-tools-7bbe6b040c9123991377749057cfc0356c289ceb.zip
Adding upstream version 1:2.0.27.upstream/1%2.0.27upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'util_lib')
-rw-r--r--util_lib/Makefile24
-rw-r--r--util_lib/compute_ip_checksum.c102
-rw-r--r--util_lib/elf_info.c1284
-rw-r--r--util_lib/include/elf_info.h36
-rw-r--r--util_lib/include/ip_checksum.h8
-rw-r--r--util_lib/include/sha256.h22
-rw-r--r--util_lib/sha256.c368
7 files changed, 1844 insertions, 0 deletions
diff --git a/util_lib/Makefile b/util_lib/Makefile
new file mode 100644
index 0000000..4a6213a
--- /dev/null
+++ b/util_lib/Makefile
@@ -0,0 +1,24 @@
+#
+# Utility function library
+#
+UTIL_LIB_SRCS +=
+UTIL_LIB_SRCS += util_lib/compute_ip_checksum.c
+UTIL_LIB_SRCS += util_lib/elf_info.c
+UTIL_LIB_SRCS += util_lib/sha256.c
+UTIL_LIB_OBJS =$(call objify, $(UTIL_LIB_SRCS))
+UTIL_LIB_DEPS =$(call depify, $(UTIL_LIB_OBJS))
+UTIL_LIB = libutil.a
+
+-include $(UTIL_LIB_DEPS)
+
+dist += util_lib/Makefile $(UTIL_LIB_SRCS) \
+ util_lib/include/elf_info.h util_lib/include/sha256.h \
+ util_lib/include/ip_checksum.h
+clean += $(UTIL_LIB_OBJS) $(UTIL_LIB_DEPS) $(UTIL_LIB)
+
+$(UTIL_LIB): CPPFLAGS += -I$(srcdir)/util_lib/include
+
+$(UTIL_LIB): $(UTIL_LIB_OBJS)
+ @$(MKDIR) -p $(@D)
+ $(AR) rs $(UTIL_LIB) $(UTIL_LIB_OBJS)
+
diff --git a/util_lib/compute_ip_checksum.c b/util_lib/compute_ip_checksum.c
new file mode 100644
index 0000000..39a371b
--- /dev/null
+++ b/util_lib/compute_ip_checksum.c
@@ -0,0 +1,102 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <ip_checksum.h>
+#include <string.h>
+
+unsigned long compute_ip_checksum(void *addr, unsigned long length)
+{
+ uint16_t *ptr;
+ unsigned long sum;
+ unsigned long len;
+ unsigned long laddr;
+ /* compute an ip style checksum */
+ laddr = (unsigned long )addr;
+ sum = 0;
+ if (laddr & 1) {
+ uint16_t buffer;
+ unsigned char *ptr;
+ /* copy the first byte into a 2 byte buffer.
+ * This way automatically handles the endian question
+ * of which byte (low or high) the last byte goes in.
+ */
+ buffer = 0;
+ ptr = addr;
+ memcpy(&buffer, ptr, 1);
+ sum += buffer;
+ if (sum > 0xFFFF)
+ sum -= 0xFFFF;
+ length -= 1;
+ addr = ptr +1;
+
+ }
+ len = length >> 1;
+ ptr = addr;
+ while (len--) {
+ sum += *(ptr++);
+ if (sum > 0xFFFF)
+ sum -= 0xFFFF;
+ }
+ addr = ptr;
+ if (length & 1) {
+ uint16_t buffer;
+ unsigned char *ptr;
+ /* copy the last byte into a 2 byte buffer.
+ * This way automatically handles the endian question
+ * of which byte (low or high) the last byte goes in.
+ */
+ buffer = 0;
+ ptr = addr;
+ memcpy(&buffer, ptr, 1);
+ sum += buffer;
+ if (sum > 0xFFFF)
+ sum -= 0xFFFF;
+ }
+ return (~sum) & 0xFFFF;
+
+}
+
+unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new)
+{
+ unsigned long checksum;
+ sum = ~sum & 0xFFFF;
+ new = ~new & 0xFFFF;
+ if (offset & 1) {
+ /* byte swap the sum if it came from an odd offset
+ * since the computation is endian independant this
+ * works.
+ */
+ new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
+ }
+ checksum = sum + new;
+ if (checksum > 0xFFFF) {
+ checksum -= 0xFFFF;
+ }
+ return (~checksum) & 0xFFFF;
+}
+
+unsigned long negate_ip_checksum(unsigned long sum)
+{
+ sum = ~sum & 0xFFFF;
+
+ sum = 0xFFFF - sum;
+
+ return ~sum & 0xFFFF;
+}
diff --git a/util_lib/elf_info.c b/util_lib/elf_info.c
new file mode 100644
index 0000000..ce71c60
--- /dev/null
+++ b/util_lib/elf_info.c
@@ -0,0 +1,1284 @@
+/*
+ * elf_info.c: Architecture independent code for parsing elf files.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <elf_info.h>
+
+/* The 32bit and 64bit note headers make it clear we don't care */
+typedef Elf32_Nhdr Elf_Nhdr;
+
+const char *fname;
+static Elf64_Ehdr ehdr;
+static Elf64_Phdr *phdr;
+static int num_pt_loads;
+
+static char osrelease[4096];
+
+/* VMCOREINFO symbols for lockless printk ringbuffer */
+static loff_t prb_vaddr;
+static size_t printk_ringbuffer_sz;
+static size_t prb_desc_sz;
+static size_t printk_info_sz;
+static uint64_t printk_ringbuffer_desc_ring_offset;
+static uint64_t printk_ringbuffer_text_data_ring_offset;
+static uint64_t prb_desc_ring_count_bits_offset;
+static uint64_t prb_desc_ring_descs_offset;
+static uint64_t prb_desc_ring_infos_offset;
+static uint64_t prb_data_ring_size_bits_offset;
+static uint64_t prb_data_ring_data_offset;
+static uint64_t prb_desc_ring_head_id_offset;
+static uint64_t prb_desc_ring_tail_id_offset;
+static uint64_t atomic_long_t_counter_offset;
+static uint64_t prb_desc_state_var_offset;
+static uint64_t prb_desc_info_offset;
+static uint64_t prb_desc_text_blk_lpos_offset;
+static uint64_t prb_data_blk_lpos_begin_offset;
+static uint64_t prb_data_blk_lpos_next_offset;
+static uint64_t printk_info_seq_offset;
+static uint64_t printk_info_caller_id_offset;
+static uint64_t printk_info_ts_nsec_offset;
+static uint64_t printk_info_level_offset;
+static uint64_t printk_info_text_len_offset;
+
+static loff_t log_buf_vaddr;
+static loff_t log_end_vaddr;
+static loff_t log_buf_len_vaddr;
+static loff_t logged_chars_vaddr;
+
+/* record format logs */
+static loff_t log_first_idx_vaddr;
+static loff_t log_next_idx_vaddr;
+
+/* struct printk_log (or older log) size */
+static uint64_t log_sz;
+
+/* struct printk_log (or older log) field offsets */
+static uint64_t log_offset_ts_nsec = UINT64_MAX;
+static uint16_t log_offset_len = UINT16_MAX;
+static uint16_t log_offset_text_len = UINT16_MAX;
+
+static uint64_t phys_offset = UINT64_MAX;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define ELFDATANATIVE ELFDATA2LSB
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define ELFDATANATIVE ELFDATA2MSB
+#else
+#error "Unknown machine endian"
+#endif
+
+static uint16_t file16_to_cpu(uint16_t val)
+{
+ if (ehdr.e_ident[EI_DATA] != ELFDATANATIVE)
+ val = bswap_16(val);
+ return val;
+}
+
+static uint32_t file32_to_cpu(uint32_t val)
+{
+ if (ehdr.e_ident[EI_DATA] != ELFDATANATIVE)
+ val = bswap_32(val);
+ return val;
+}
+
+static uint64_t file64_to_cpu(uint64_t val)
+{
+ if (ehdr.e_ident[EI_DATA] != ELFDATANATIVE)
+ val = bswap_64(val);
+ return val;
+}
+
+static uint64_t vaddr_to_offset(uint64_t vaddr)
+{
+ /* Just hand the simple case where kexec gets
+ * the virtual address on the program headers right.
+ */
+ ssize_t i;
+ for (i = 0; i < ehdr.e_phnum; i++) {
+ if (phdr[i].p_vaddr > vaddr)
+ continue;
+ if ((phdr[i].p_vaddr + phdr[i].p_memsz) <= vaddr)
+ continue;
+ return (vaddr - phdr[i].p_vaddr) + phdr[i].p_offset;
+ }
+ fprintf(stderr, "No program header covering vaddr 0x%llxfound kexec bug?\n",
+ (unsigned long long)vaddr);
+ exit(30);
+}
+
+static unsigned machine_pointer_bits(void)
+{
+ uint8_t bits = 0;
+
+ /* Default to the size of the elf class */
+ switch(ehdr.e_ident[EI_CLASS]) {
+ case ELFCLASS32: bits = 32; break;
+ case ELFCLASS64: bits = 64; break;
+ }
+
+ /* Report the architectures pointer size */
+ switch(ehdr.e_machine) {
+ case EM_386: bits = 32; break;
+ }
+
+ return bits;
+}
+
+void read_elf32(int fd)
+{
+ Elf32_Ehdr ehdr32;
+ Elf32_Phdr *phdr32;
+ size_t phdrs32_size;
+ ssize_t ret, i;
+
+ ret = pread(fd, &ehdr32, sizeof(ehdr32), 0);
+ if (ret != sizeof(ehdr32)) {
+ fprintf(stderr, "Read of Elf header from %s failed: %s\n",
+ fname, strerror(errno));
+ exit(10);
+ }
+
+ ehdr.e_type = file16_to_cpu(ehdr32.e_type);
+ ehdr.e_machine = file16_to_cpu(ehdr32.e_machine);
+ ehdr.e_version = file32_to_cpu(ehdr32.e_version);
+ ehdr.e_entry = file32_to_cpu(ehdr32.e_entry);
+ ehdr.e_phoff = file32_to_cpu(ehdr32.e_phoff);
+ ehdr.e_shoff = file32_to_cpu(ehdr32.e_shoff);
+ ehdr.e_flags = file32_to_cpu(ehdr32.e_flags);
+ ehdr.e_ehsize = file16_to_cpu(ehdr32.e_ehsize);
+ ehdr.e_phentsize = file16_to_cpu(ehdr32.e_phentsize);
+ ehdr.e_phnum = file16_to_cpu(ehdr32.e_phnum);
+ ehdr.e_shentsize = file16_to_cpu(ehdr32.e_shentsize);
+ ehdr.e_shnum = file16_to_cpu(ehdr32.e_shnum);
+ ehdr.e_shstrndx = file16_to_cpu(ehdr32.e_shstrndx);
+
+ if (ehdr.e_version != EV_CURRENT) {
+ fprintf(stderr, "Bad Elf header version %u\n",
+ ehdr.e_version);
+ exit(11);
+ }
+ if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) {
+ fprintf(stderr, "Bad Elf progra header size %u expected %zu\n",
+ ehdr.e_phentsize, sizeof(Elf32_Phdr));
+ exit(12);
+ }
+ phdrs32_size = ehdr.e_phnum * sizeof(Elf32_Phdr);
+ phdr32 = calloc(ehdr.e_phnum, sizeof(Elf32_Phdr));
+ if (!phdr32) {
+ fprintf(stderr, "Calloc of %u phdrs32 failed: %s\n",
+ ehdr.e_phnum, strerror(errno));
+ exit(14);
+ }
+ phdr = calloc(ehdr.e_phnum, sizeof(Elf64_Phdr));
+ if (!phdr) {
+ fprintf(stderr, "Calloc of %u phdrs failed: %s\n",
+ ehdr.e_phnum, strerror(errno));
+ exit(15);
+ }
+ ret = pread(fd, phdr32, phdrs32_size, ehdr.e_phoff);
+ if (ret < 0 || (size_t)ret != phdrs32_size) {
+ fprintf(stderr, "Read of program header @ 0x%llu for %zu bytes failed: %s\n",
+ (unsigned long long)ehdr.e_phoff, phdrs32_size, strerror(errno));
+ exit(16);
+ }
+ for (i = 0; i < ehdr.e_phnum; i++) {
+ phdr[i].p_type = file32_to_cpu(phdr32[i].p_type);
+ phdr[i].p_offset = file32_to_cpu(phdr32[i].p_offset);
+ phdr[i].p_vaddr = file32_to_cpu(phdr32[i].p_vaddr);
+ phdr[i].p_paddr = file32_to_cpu(phdr32[i].p_paddr);
+ phdr[i].p_filesz = file32_to_cpu(phdr32[i].p_filesz);
+ phdr[i].p_memsz = file32_to_cpu(phdr32[i].p_memsz);
+ phdr[i].p_flags = file32_to_cpu(phdr32[i].p_flags);
+ phdr[i].p_align = file32_to_cpu(phdr32[i].p_align);
+
+ if (phdr[i].p_type == PT_LOAD)
+ num_pt_loads++;
+ }
+ free(phdr32);
+}
+
+void read_elf64(int fd)
+{
+ Elf64_Ehdr ehdr64;
+ Elf64_Phdr *phdr64;
+ size_t phdrs_size;
+ ssize_t ret, i;
+
+ ret = pread(fd, &ehdr64, sizeof(ehdr64), 0);
+ if (ret < 0 || (size_t)ret != sizeof(ehdr)) {
+ fprintf(stderr, "Read of Elf header from %s failed: %s\n",
+ fname, strerror(errno));
+ exit(10);
+ }
+
+ ehdr.e_type = file16_to_cpu(ehdr64.e_type);
+ ehdr.e_machine = file16_to_cpu(ehdr64.e_machine);
+ ehdr.e_version = file32_to_cpu(ehdr64.e_version);
+ ehdr.e_entry = file64_to_cpu(ehdr64.e_entry);
+ ehdr.e_phoff = file64_to_cpu(ehdr64.e_phoff);
+ ehdr.e_shoff = file64_to_cpu(ehdr64.e_shoff);
+ ehdr.e_flags = file32_to_cpu(ehdr64.e_flags);
+ ehdr.e_ehsize = file16_to_cpu(ehdr64.e_ehsize);
+ ehdr.e_phentsize = file16_to_cpu(ehdr64.e_phentsize);
+ ehdr.e_phnum = file16_to_cpu(ehdr64.e_phnum);
+ ehdr.e_shentsize = file16_to_cpu(ehdr64.e_shentsize);
+ ehdr.e_shnum = file16_to_cpu(ehdr64.e_shnum);
+ ehdr.e_shstrndx = file16_to_cpu(ehdr64.e_shstrndx);
+
+ if (ehdr.e_version != EV_CURRENT) {
+ fprintf(stderr, "Bad Elf header version %u\n",
+ ehdr.e_version);
+ exit(11);
+ }
+ if (ehdr.e_phentsize != sizeof(Elf64_Phdr)) {
+ fprintf(stderr, "Bad Elf progra header size %u expected %zu\n",
+ ehdr.e_phentsize, sizeof(Elf64_Phdr));
+ exit(12);
+ }
+ phdrs_size = ehdr.e_phnum * sizeof(Elf64_Phdr);
+ phdr64 = calloc(ehdr.e_phnum, sizeof(Elf64_Phdr));
+ if (!phdr64) {
+ fprintf(stderr, "Calloc of %u phdrs64 failed: %s\n",
+ ehdr.e_phnum, strerror(errno));
+ exit(14);
+ }
+ phdr = calloc(ehdr.e_phnum, sizeof(Elf64_Phdr));
+ if (!phdr) {
+ fprintf(stderr, "Calloc of %u phdrs failed: %s\n",
+ ehdr.e_phnum, strerror(errno));
+ exit(15);
+ }
+ ret = pread(fd, phdr64, phdrs_size, ehdr.e_phoff);
+ if (ret < 0 || (size_t)ret != phdrs_size) {
+ fprintf(stderr, "Read of program header @ %llu for %zu bytes failed: %s\n",
+ (unsigned long long)(ehdr.e_phoff), phdrs_size, strerror(errno));
+ exit(16);
+ }
+ for (i = 0; i < ehdr.e_phnum; i++) {
+ phdr[i].p_type = file32_to_cpu(phdr64[i].p_type);
+ phdr[i].p_flags = file32_to_cpu(phdr64[i].p_flags);
+ phdr[i].p_offset = file64_to_cpu(phdr64[i].p_offset);
+ phdr[i].p_vaddr = file64_to_cpu(phdr64[i].p_vaddr);
+ phdr[i].p_paddr = file64_to_cpu(phdr64[i].p_paddr);
+ phdr[i].p_filesz = file64_to_cpu(phdr64[i].p_filesz);
+ phdr[i].p_memsz = file64_to_cpu(phdr64[i].p_memsz);
+ phdr[i].p_align = file64_to_cpu(phdr64[i].p_align);
+
+ if (phdr[i].p_type == PT_LOAD)
+ num_pt_loads++;
+ }
+ free(phdr64);
+}
+
+int get_pt_load(int idx,
+ unsigned long long *phys_start,
+ unsigned long long *phys_end,
+ unsigned long long *virt_start,
+ unsigned long long *virt_end)
+{
+ Elf64_Phdr *pls;
+
+ if (num_pt_loads <= idx)
+ return 0;
+
+ pls = &phdr[idx];
+
+ if (phys_start)
+ *phys_start = pls->p_paddr;
+ if (phys_end)
+ *phys_end = pls->p_paddr + pls->p_memsz;
+ if (virt_start)
+ *virt_start = pls->p_vaddr;
+ if (virt_end)
+ *virt_end = pls->p_vaddr + pls->p_memsz;
+
+ return 1;
+}
+
+#define NOT_FOUND_LONG_VALUE (-1)
+
+void (*arch_scan_vmcoreinfo)(char *pos);
+
+void scan_vmcoreinfo(char *start, size_t size)
+{
+ char *last = start + size - 1;
+ char *pos, *eol;
+ char temp_buf[1024];
+ bool last_line = false;
+ char *str, *endp;
+
+#define SYMBOL(sym) { \
+ .str = "SYMBOL(" #sym ")=", \
+ .name = #sym, \
+ .len = sizeof("SYMBOL(" #sym ")=") - 1, \
+ .vaddr = & sym ## _vaddr, \
+ }
+ static struct symbol {
+ const char *str;
+ const char *name;
+ size_t len;
+ loff_t *vaddr;
+ } symbol[] = {
+ SYMBOL(prb),
+ SYMBOL(log_buf),
+ SYMBOL(log_end),
+ SYMBOL(log_buf_len),
+ SYMBOL(logged_chars),
+ SYMBOL(log_first_idx),
+ SYMBOL(log_next_idx),
+ };
+
+ for (pos = start; pos <= last; pos = eol + 1) {
+ size_t len, i;
+ /* Find the end of the current line */
+ for (eol = pos; (eol <= last) && (*eol != '\n') ; eol++)
+ ;
+ if (eol > last) {
+ /*
+ * We did not find \n and note ended. Currently kernel
+ * is appending last field CRASH_TIME without \n. It
+ * is ugly but handle it.
+ */
+ eol = last;
+ len = eol - pos + 1;
+ if (len >= sizeof(temp_buf))
+ len = sizeof(temp_buf) - 1;
+ strncpy(temp_buf, pos, len);
+ temp_buf[len + 1] = '\0';
+
+ pos = temp_buf;
+ len = len + 1;
+ eol = pos + len -1;
+ last_line = true;
+ } else {
+ len = eol - pos + 1;
+ }
+
+ /* Stomp the last character so I am guaranteed a terminating null */
+ *eol = '\0';
+ /* Copy OSRELEASE if I see it */
+ if ((len >= 10) && (memcmp("OSRELEASE=", pos, 10) == 0)) {
+ size_t to_copy = len - 10;
+ if (to_copy >= sizeof(osrelease))
+ to_copy = sizeof(osrelease) - 1;
+ memcpy(osrelease, pos + 10, to_copy);
+ osrelease[to_copy] = '\0';
+ }
+ /* See if the line is mentions a symbol I am looking for */
+ for (i = 0; i < sizeof(symbol)/sizeof(symbol[0]); i++ ) {
+ unsigned long long vaddr;
+ if (symbol[i].len >= len)
+ continue;
+ if (memcmp(symbol[i].str, pos, symbol[i].len) != 0)
+ continue;
+ /* Found a symbol now decode it */
+ vaddr = strtoull(pos + symbol[i].len, NULL, 16);
+ /* Remember the virtual address */
+ *symbol[i].vaddr = vaddr;
+ }
+
+ str = "SIZE(printk_ringbuffer)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ printk_ringbuffer_sz = strtoull(pos + strlen(str),
+ NULL, 10);
+
+ str = "SIZE(prb_desc)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ prb_desc_sz = strtoull(pos + strlen(str), NULL, 10);
+
+ str = "SIZE(printk_info)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ printk_info_sz = strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(printk_ringbuffer.desc_ring)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ printk_ringbuffer_desc_ring_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(printk_ringbuffer.text_data_ring)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ printk_ringbuffer_text_data_ring_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(prb_desc_ring.count_bits)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ prb_desc_ring_count_bits_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(prb_desc_ring.descs)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ prb_desc_ring_descs_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(prb_desc_ring.infos)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ prb_desc_ring_infos_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(prb_data_ring.size_bits)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ prb_data_ring_size_bits_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(prb_data_ring.data)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ prb_data_ring_data_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(prb_desc_ring.head_id)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ prb_desc_ring_head_id_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(prb_desc_ring.tail_id)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ prb_desc_ring_tail_id_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(atomic_long_t.counter)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ atomic_long_t_counter_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(prb_desc.state_var)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ prb_desc_state_var_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(prb_desc.info)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ prb_desc_info_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(prb_desc.text_blk_lpos)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ prb_desc_text_blk_lpos_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(prb_data_blk_lpos.begin)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ prb_data_blk_lpos_begin_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(prb_data_blk_lpos.next)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ prb_data_blk_lpos_next_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(printk_info.seq)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ printk_info_seq_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(printk_info.caller_id)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ printk_info_caller_id_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(printk_info.ts_nsec)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ printk_info_ts_nsec_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(printk_info.level)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ printk_info_level_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(printk_info.text_len)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ printk_info_text_len_offset =
+ strtoull(pos + strlen(str), NULL, 10);
+
+ /* Check for "SIZE(printk_log)" or older "SIZE(log)=" */
+ str = "SIZE(log)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ log_sz = strtoull(pos + strlen(str), NULL, 10);
+
+ str = "SIZE(printk_log)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ log_sz = strtoull(pos + strlen(str), NULL, 10);
+
+ /* Check for struct printk_log (or older log) field offsets */
+ str = "OFFSET(log.ts_nsec)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ log_offset_ts_nsec = strtoull(pos + strlen(str), NULL,
+ 10);
+ str = "OFFSET(printk_log.ts_nsec)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ log_offset_ts_nsec = strtoull(pos + strlen(str), NULL,
+ 10);
+
+ str = "OFFSET(log.len)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ log_offset_len = strtoul(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(printk_log.len)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ log_offset_len = strtoul(pos + strlen(str), NULL, 10);
+
+ str = "OFFSET(log.text_len)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ log_offset_text_len = strtoul(pos + strlen(str), NULL,
+ 10);
+ str = "OFFSET(printk_log.text_len)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ log_offset_text_len = strtoul(pos + strlen(str), NULL,
+ 10);
+
+ /* Check for PHYS_OFFSET number */
+ str = "NUMBER(PHYS_OFFSET)=";
+ if (memcmp(str, pos, strlen(str)) == 0) {
+ phys_offset = strtoul(pos + strlen(str), &endp,
+ 10);
+ if (strlen(endp) != 0)
+ phys_offset = strtoul(pos + strlen(str), &endp, 16);
+ if ((phys_offset == LONG_MAX) || strlen(endp) != 0) {
+ fprintf(stderr, "Invalid data %s\n",
+ pos);
+ break;
+ }
+ }
+
+ if (arch_scan_vmcoreinfo != NULL)
+ (*arch_scan_vmcoreinfo)(pos);
+
+ if (last_line)
+ break;
+ }
+}
+
+static int scan_notes(int fd, loff_t start, loff_t lsize)
+{
+ char *buf, *last, *note, *next;
+ size_t size;
+ ssize_t ret;
+
+ if (lsize > SSIZE_MAX) {
+ fprintf(stderr, "Unable to handle note section of %llu bytes\n",
+ (unsigned long long)lsize);
+ exit(20);
+ }
+
+ size = lsize;
+ buf = malloc(size);
+ if (!buf) {
+ fprintf(stderr, "Cannot malloc %zu bytes\n", size);
+ exit(21);
+ }
+ last = buf + size - 1;
+ ret = pread(fd, buf, size, start);
+ if (ret != (ssize_t)size) {
+ fprintf(stderr, "Cannot read note section @ 0x%llx of %zu bytes: %s\n",
+ (unsigned long long)start, size, strerror(errno));
+ exit(22);
+ }
+
+ for (note = buf; (note + sizeof(Elf_Nhdr)) < last; note = next)
+ {
+ Elf_Nhdr *hdr;
+ char *n_name, *n_desc;
+ size_t n_namesz, n_descsz, n_type;
+
+ hdr = (Elf_Nhdr *)note;
+ n_namesz = file32_to_cpu(hdr->n_namesz);
+ n_descsz = file32_to_cpu(hdr->n_descsz);
+ n_type = file32_to_cpu(hdr->n_type);
+
+ n_name = note + sizeof(*hdr);
+ n_desc = n_name + ((n_namesz + 3) & ~3);
+ next = n_desc + ((n_descsz + 3) & ~3);
+
+ if (next > (last + 1))
+ break;
+
+ if ((memcmp(n_name, "VMCOREINFO", 11) != 0) || (n_type != 0))
+ continue;
+ scan_vmcoreinfo(n_desc, n_descsz);
+ }
+
+ if ((note + sizeof(Elf_Nhdr)) == last) {
+ free(buf);
+ return -1;
+ }
+
+ free(buf);
+
+ return 0;
+}
+
+static int scan_note_headers(int fd)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < ehdr.e_phnum; i++) {
+ if (phdr[i].p_type != PT_NOTE)
+ continue;
+ ret = scan_notes(fd, phdr[i].p_offset, phdr[i].p_filesz);
+ }
+
+ return ret;
+}
+
+static uint64_t read_file_pointer(int fd, uint64_t addr)
+{
+ uint64_t result;
+ ssize_t ret;
+
+ if (machine_pointer_bits() == 64) {
+ uint64_t scratch;
+ ret = pread(fd, &scratch, sizeof(scratch), addr);
+ if (ret != sizeof(scratch)) {
+ fprintf(stderr, "Failed to read pointer @ 0x%llx: %s\n",
+ (unsigned long long)addr, strerror(errno));
+ exit(40);
+ }
+ result = file64_to_cpu(scratch);
+ } else {
+ uint32_t scratch;
+ ret = pread(fd, &scratch, sizeof(scratch), addr);
+ if (ret != sizeof(scratch)) {
+ fprintf(stderr, "Failed to read pointer @ 0x%llx: %s\n",
+ (unsigned long long)addr, strerror(errno));
+ exit(40);
+ }
+ result = file32_to_cpu(scratch);
+ }
+ return result;
+}
+
+static uint32_t read_file_u32(int fd, uint64_t addr)
+{
+ uint32_t scratch;
+ ssize_t ret;
+ ret = pread(fd, &scratch, sizeof(scratch), addr);
+ if (ret != sizeof(scratch)) {
+ fprintf(stderr, "Failed to read value @ 0x%llx: %s\n",
+ (unsigned long long)addr, strerror(errno));
+ exit(41);
+ }
+ return file32_to_cpu(scratch);
+}
+
+static int32_t read_file_s32(int fd, uint64_t addr)
+{
+ return read_file_u32(fd, addr);
+}
+
+static void dump_dmesg_legacy(int fd, void (*handler)(char*, unsigned int))
+{
+ uint64_t log_buf, log_buf_offset;
+ unsigned log_end, logged_chars, log_end_wrapped;
+ int log_buf_len, to_wrap;
+ char *buf;
+ ssize_t ret;
+
+ if (!log_buf_vaddr) {
+ fprintf(stderr, "Missing the log_buf symbol\n");
+ exit(50);
+ }
+ if (!log_end_vaddr) {
+ fprintf(stderr, "Missing the log_end symbol\n");
+ exit(51);
+ }
+ if (!log_buf_len_vaddr) {
+ fprintf(stderr, "Missing the log_bug_len symbol\n");
+ exit(52);
+ }
+ if (!logged_chars_vaddr) {
+ fprintf(stderr, "Missing the logged_chars symbol\n");
+ exit(53);
+ }
+
+ log_buf = read_file_pointer(fd, vaddr_to_offset(log_buf_vaddr));
+ log_end = read_file_u32(fd, vaddr_to_offset(log_end_vaddr));
+ log_buf_len = read_file_s32(fd, vaddr_to_offset(log_buf_len_vaddr));
+ logged_chars = read_file_u32(fd, vaddr_to_offset(logged_chars_vaddr));
+
+ log_buf_offset = vaddr_to_offset(log_buf);
+
+ buf = calloc(1, log_buf_len);
+ if (!buf) {
+ fprintf(stderr, "Failed to malloc %d bytes for the logbuf: %s\n",
+ log_buf_len, strerror(errno));
+ exit(51);
+ }
+
+ log_end_wrapped = log_end % log_buf_len;
+ to_wrap = log_buf_len - log_end_wrapped;
+
+ ret = pread(fd, buf, to_wrap, log_buf_offset + log_end_wrapped);
+ if (ret != to_wrap) {
+ fprintf(stderr, "Failed to read the first half of the log buffer: %s\n",
+ strerror(errno));
+ exit(52);
+ }
+ ret = pread(fd, buf + to_wrap, log_end_wrapped, log_buf_offset);
+ if (ret != log_end_wrapped) {
+ fprintf(stderr, "Faield to read the second half of the log buffer: %s\n",
+ strerror(errno));
+ exit(53);
+ }
+
+ /*
+ * To collect full dmesg including the part before `dmesg -c` is useful
+ * for later debugging. Use same logic as what crash utility is using.
+ */
+ logged_chars = log_end < log_buf_len ? log_end : log_buf_len;
+
+ if (handler)
+ handler(buf + (log_buf_len - logged_chars), logged_chars);
+}
+
+static inline uint16_t struct_val_u16(char *ptr, unsigned int offset)
+{
+ return(file16_to_cpu(*(uint16_t *)(ptr + offset)));
+}
+
+static inline uint32_t struct_val_u32(char *ptr, unsigned int offset)
+{
+ return(file32_to_cpu(*(uint32_t *)(ptr + offset)));
+}
+
+static inline uint64_t struct_val_u64(char *ptr, unsigned int offset)
+{
+ return(file64_to_cpu(*(uint64_t *)(ptr + offset)));
+}
+
+/* Read headers of log records and dump accordingly */
+static void dump_dmesg_structured(int fd, void (*handler)(char*, unsigned int))
+{
+#define OUT_BUF_SIZE 4096
+ uint64_t log_buf, log_buf_offset, ts_nsec;
+ uint32_t log_buf_len, log_first_idx, log_next_idx, current_idx, len = 0, i;
+ char *buf, out_buf[OUT_BUF_SIZE];
+ bool has_wrapped_around = false;
+ ssize_t ret;
+ char *msg;
+ uint16_t text_len;
+ imaxdiv_t imaxdiv_sec, imaxdiv_usec;
+
+ if (!log_buf_vaddr) {
+ fprintf(stderr, "Missing the log_buf symbol\n");
+ exit(60);
+ }
+
+ if (!log_buf_len_vaddr) {
+ fprintf(stderr, "Missing the log_bug_len symbol\n");
+ exit(61);
+ }
+
+ if (!log_first_idx_vaddr) {
+ fprintf(stderr, "Missing the log_first_idx symbol\n");
+ exit(62);
+ }
+
+ if (!log_next_idx_vaddr) {
+ fprintf(stderr, "Missing the log_next_idx symbol\n");
+ exit(63);
+ }
+
+ if (!log_sz) {
+ fprintf(stderr, "Missing the struct log size export\n");
+ exit(64);
+ }
+
+ if (log_offset_ts_nsec == UINT64_MAX) {
+ fprintf(stderr, "Missing the log.ts_nsec offset export\n");
+ exit(65);
+ }
+
+ if (log_offset_len == UINT16_MAX) {
+ fprintf(stderr, "Missing the log.len offset export\n");
+ exit(66);
+ }
+
+ if (log_offset_text_len == UINT16_MAX) {
+ fprintf(stderr, "Missing the log.text_len offset export\n");
+ exit(67);
+ }
+
+ log_buf = read_file_pointer(fd, vaddr_to_offset(log_buf_vaddr));
+ log_buf_len = read_file_s32(fd, vaddr_to_offset(log_buf_len_vaddr));
+
+ log_first_idx = read_file_u32(fd, vaddr_to_offset(log_first_idx_vaddr));
+ log_next_idx = read_file_u32(fd, vaddr_to_offset(log_next_idx_vaddr));
+
+ log_buf_offset = vaddr_to_offset(log_buf);
+
+ buf = calloc(1, log_sz);
+ if (!buf) {
+ fprintf(stderr, "Failed to malloc %" PRId64 " bytes for the log:"
+ " %s\n", log_sz, strerror(errno));
+ exit(64);
+ }
+
+ /* Parse records and write out data at standard output */
+
+ current_idx = log_first_idx;
+ len = 0;
+ while (current_idx != log_next_idx) {
+ uint16_t loglen;
+
+ ret = pread(fd, buf, log_sz, log_buf_offset + current_idx);
+ if (ret != log_sz) {
+ fprintf(stderr, "Failed to read log of size %" PRId64 " bytes:"
+ " %s\n", log_sz, strerror(errno));
+ exit(65);
+ }
+ ts_nsec = struct_val_u64(buf, log_offset_ts_nsec);
+ imaxdiv_sec = imaxdiv(ts_nsec, 1000000000);
+ imaxdiv_usec = imaxdiv(imaxdiv_sec.rem, 1000);
+
+ len += sprintf(out_buf + len, "[%5llu.%06llu] ",
+ (long long unsigned int)imaxdiv_sec.quot,
+ (long long unsigned int)imaxdiv_usec.quot);
+
+ /* escape non-printable characters */
+ text_len = struct_val_u16(buf, log_offset_text_len);
+ msg = calloc(1, text_len);
+ if (!msg) {
+ fprintf(stderr, "Failed to malloc %u bytes for log text:"
+ " %s\n", text_len, strerror(errno));
+ exit(64);
+ }
+
+ ret = pread(fd, msg, text_len, log_buf_offset + current_idx + log_sz);
+ if (ret != text_len) {
+ fprintf(stderr, "Failed to read log text of size %u bytes:"
+ " %s\n", text_len, strerror(errno));
+ exit(65);
+ }
+ for (i = 0; i < text_len; i++) {
+ unsigned char c = msg[i];
+
+ if (!isprint(c) && !isspace(c))
+ len += sprintf(out_buf + len, "\\x%02x", c);
+ else
+ out_buf[len++] = c;
+
+ if (len >= OUT_BUF_SIZE - 64) {
+ if (handler)
+ handler(out_buf, len);
+ len = 0;
+ }
+ }
+
+ out_buf[len++] = '\n';
+ free(msg);
+ /*
+ * A length == 0 record is the end of buffer marker. Wrap around
+ * and read the message at the start of the buffer.
+ */
+ loglen = struct_val_u16(buf, log_offset_len);
+ if (!loglen) {
+ if (has_wrapped_around) {
+ if (len && handler)
+ handler(out_buf, len);
+ fprintf(stderr, "Cycle when parsing dmesg detected.\n");
+ fprintf(stderr, "The prink log_buf is most likely corrupted.\n");
+ fprintf(stderr, "log_buf = 0x%lx, idx = 0x%x\n",
+ log_buf, current_idx);
+ exit(68);
+ }
+ current_idx = 0;
+ has_wrapped_around = true;
+ } else {
+ /* Move to next record */
+ current_idx += loglen;
+ if(current_idx > log_buf_len - log_sz) {
+ if (len && handler)
+ handler(out_buf, len);
+ fprintf(stderr, "Index outside log_buf detected.\n");
+ fprintf(stderr, "The prink log_buf is most likely corrupted.\n");
+ fprintf(stderr, "log_buf = 0x%lx, idx = 0x%x\n",
+ log_buf, current_idx);
+ exit(69);
+ }
+ }
+ }
+ free(buf);
+ if (len && handler)
+ handler(out_buf, len);
+}
+
+/* convenience struct for passing many values to helper functions */
+struct prb_map {
+ char *prb;
+
+ char *desc_ring;
+ unsigned long desc_ring_count;
+ char *descs;
+
+ char *infos;
+
+ char *text_data_ring;
+ unsigned long text_data_ring_size;
+ char *text_data;
+};
+
+/*
+ * desc_state and DESC_* definitions taken from kernel source:
+ *
+ * kernel/printk/printk_ringbuffer.h
+ *
+ * DESC_* definitions modified to provide 32-bit and 64-bit variants.
+ */
+
+/* The possible responses of a descriptor state-query. */
+enum desc_state {
+ desc_miss = -1, /* ID mismatch (pseudo state) */
+ desc_reserved = 0x0, /* reserved, in use by writer */
+ desc_committed = 0x1, /* committed by writer, could get reopened */
+ desc_finalized = 0x2, /* committed, no further modification allowed */
+ desc_reusable = 0x3, /* free, not yet used by any writer */
+};
+
+#define DESC_SV_BITS (sizeof(uint64_t) * 8)
+#define DESC_FLAGS_SHIFT (DESC_SV_BITS - 2)
+#define DESC_FLAGS_MASK (3ULL << DESC_FLAGS_SHIFT)
+#define DESC_STATE(sv) (3ULL & (sv >> DESC_FLAGS_SHIFT))
+#define DESC_ID_MASK (~DESC_FLAGS_MASK)
+#define DESC_ID(sv) ((sv) & DESC_ID_MASK)
+
+#define DESC32_SV_BITS (sizeof(uint32_t) * 8)
+#define DESC32_FLAGS_SHIFT (DESC32_SV_BITS - 2)
+#define DESC32_FLAGS_MASK (3UL << DESC32_FLAGS_SHIFT)
+#define DESC32_STATE(sv) (3UL & (sv >> DESC32_FLAGS_SHIFT))
+#define DESC32_ID_MASK (~DESC32_FLAGS_MASK)
+#define DESC32_ID(sv) ((sv) & DESC32_ID_MASK)
+
+/*
+ * get_desc_state() taken from kernel source:
+ *
+ * kernel/printk/printk_ringbuffer.c
+ *
+ * get_desc32_state() added as 32-bit variant.
+ */
+
+/* Query the state of a descriptor. */
+static enum desc_state get_desc_state(unsigned long id,
+ uint64_t state_val)
+{
+ if (id != DESC_ID(state_val))
+ return desc_miss;
+
+ return DESC_STATE(state_val);
+}
+
+static enum desc_state get_desc32_state(unsigned long id,
+ uint64_t state_val)
+{
+ if (id != DESC32_ID(state_val))
+ return desc_miss;
+
+ return DESC32_STATE(state_val);
+}
+
+static bool record_committed(unsigned long id, uint64_t state_var)
+{
+ enum desc_state state;
+
+ if (machine_pointer_bits() == 32)
+ state = get_desc32_state(id, state_var);
+ else
+ state = get_desc_state(id, state_var);
+
+ return (state == desc_committed || state == desc_finalized);
+}
+
+static uint64_t id_inc(uint64_t id)
+{
+ id++;
+
+ if (machine_pointer_bits() == 32)
+ return (id & DESC32_ID_MASK);
+
+ return (id & DESC_ID_MASK);
+}
+
+static uint64_t get_ulong(char *addr)
+{
+ if (machine_pointer_bits() == 32)
+ return struct_val_u32(addr, 0);
+ return struct_val_u64(addr, 0);
+}
+
+static uint64_t sizeof_ulong(void)
+{
+ return (machine_pointer_bits() >> 3);
+}
+
+static void dump_record(struct prb_map *m, unsigned long id,
+ void (*handler)(char*, unsigned int))
+{
+#define OUT_BUF_SIZE 4096
+ char out_buf[OUT_BUF_SIZE];
+ imaxdiv_t imaxdiv_usec;
+ imaxdiv_t imaxdiv_sec;
+ uint32_t offset = 0;
+ unsigned short len;
+ uint64_t state_var;
+ uint64_t ts_nsec;
+ uint64_t begin;
+ uint64_t next;
+ char *info;
+ char *text;
+ char *desc;
+ int i;
+
+ desc = m->descs + ((id % m->desc_ring_count) * prb_desc_sz);
+ info = m->infos + ((id % m->desc_ring_count) * printk_info_sz);
+
+ /* skip non-committed record */
+ state_var = get_ulong(desc + prb_desc_state_var_offset +
+ atomic_long_t_counter_offset);
+ if (!record_committed(id, state_var))
+ return;
+
+ begin = get_ulong(desc + prb_desc_text_blk_lpos_offset +
+ prb_data_blk_lpos_begin_offset) %
+ m->text_data_ring_size;
+ next = get_ulong(desc + prb_desc_text_blk_lpos_offset +
+ prb_data_blk_lpos_next_offset) %
+ m->text_data_ring_size;
+
+ ts_nsec = struct_val_u64(info, printk_info_ts_nsec_offset);
+ imaxdiv_sec = imaxdiv(ts_nsec, 1000000000);
+ imaxdiv_usec = imaxdiv(imaxdiv_sec.rem, 1000);
+
+ offset += sprintf(out_buf + offset, "[%5llu.%06llu] ",
+ (long long unsigned int)imaxdiv_sec.quot,
+ (long long unsigned int)imaxdiv_usec.quot);
+
+ /* skip data-less text blocks */
+ if (begin == next)
+ goto out;
+
+ len = struct_val_u16(info, printk_info_text_len_offset);
+
+ /* handle wrapping data block */
+ if (begin > next)
+ begin = 0;
+
+ /* skip over descriptor ID */
+ begin += sizeof_ulong();
+
+ /* handle truncated messages */
+ if (next - begin < len)
+ len = next - begin;
+
+ text = m->text_data + begin;
+
+ /* escape non-printable characters */
+ for (i = 0; i < len; i++) {
+ unsigned char c = text[i];
+
+ if (!isprint(c) && !isspace(c))
+ offset += sprintf(out_buf + offset, "\\x%02x", c);
+ else
+ out_buf[offset++] = c;
+
+ if (offset >= OUT_BUF_SIZE - 64) {
+ if (handler)
+ handler(out_buf, offset);
+ offset = 0;
+ }
+ }
+out:
+ out_buf[offset++] = '\n';
+
+ if (offset && handler)
+ handler(out_buf, offset);
+}
+
+/*
+ * Handle the lockless printk_ringbuffer.
+ */
+static void dump_dmesg_lockless(int fd, void (*handler)(char*, unsigned int))
+{
+ struct prb_map m;
+ uint64_t head_id;
+ uint64_t tail_id;
+ uint64_t kaddr;
+ uint64_t id;
+ int ret;
+
+ /* setup printk_ringbuffer */
+ kaddr = read_file_pointer(fd, vaddr_to_offset(prb_vaddr));
+ m.prb = calloc(1, printk_ringbuffer_sz);
+ if (!m.prb) {
+ fprintf(stderr, "Failed to malloc %zu bytes for prb: %s\n",
+ printk_ringbuffer_sz, strerror(errno));
+ exit(64);
+ }
+ ret = pread(fd, m.prb, printk_ringbuffer_sz, vaddr_to_offset(kaddr));
+ if (ret != printk_ringbuffer_sz) {
+ fprintf(stderr, "Failed to read prb of size %zu bytes: %s\n",
+ printk_ringbuffer_sz, strerror(errno));
+ exit(65);
+ }
+
+ /* setup descriptor ring */
+ m.desc_ring = m.prb + printk_ringbuffer_desc_ring_offset;
+ m.desc_ring_count = 1 << struct_val_u32(m.desc_ring,
+ prb_desc_ring_count_bits_offset);
+ kaddr = get_ulong(m.desc_ring + prb_desc_ring_descs_offset);
+ m.descs = calloc(1, prb_desc_sz * m.desc_ring_count);
+ if (!m.descs) {
+ fprintf(stderr, "Failed to malloc %lu bytes for descs: %s\n",
+ prb_desc_sz * m.desc_ring_count, strerror(errno));
+ exit(64);
+ }
+ ret = pread(fd, m.descs, prb_desc_sz * m.desc_ring_count,
+ vaddr_to_offset(kaddr));
+ if (ret != prb_desc_sz * m.desc_ring_count) {
+ fprintf(stderr,
+ "Failed to read descs of size %lu bytes: %s\n",
+ prb_desc_sz * m.desc_ring_count, strerror(errno));
+ exit(65);
+ }
+
+ /* setup info ring */
+ kaddr = get_ulong(m.prb + prb_desc_ring_infos_offset);
+ m.infos = calloc(1, printk_info_sz * m.desc_ring_count);
+ if (!m.infos) {
+ fprintf(stderr, "Failed to malloc %lu bytes for infos: %s\n",
+ printk_info_sz * m.desc_ring_count, strerror(errno));
+ exit(64);
+ }
+ ret = pread(fd, m.infos, printk_info_sz * m.desc_ring_count,
+ vaddr_to_offset(kaddr));
+ if (ret != printk_info_sz * m.desc_ring_count) {
+ fprintf(stderr,
+ "Failed to read infos of size %lu bytes: %s\n",
+ printk_info_sz * m.desc_ring_count, strerror(errno));
+ exit(65);
+ }
+
+ /* setup text data ring */
+ m.text_data_ring = m.prb + printk_ringbuffer_text_data_ring_offset;
+ m.text_data_ring_size = 1 << struct_val_u32(m.text_data_ring,
+ prb_data_ring_size_bits_offset);
+ kaddr = get_ulong(m.text_data_ring + prb_data_ring_data_offset);
+ m.text_data = calloc(1, m.text_data_ring_size);
+ if (!m.text_data) {
+ fprintf(stderr,
+ "Failed to malloc %lu bytes for text_data: %s\n",
+ m.text_data_ring_size, strerror(errno));
+ exit(64);
+ }
+ ret = pread(fd, m.text_data, m.text_data_ring_size,
+ vaddr_to_offset(kaddr));
+ if (ret != m.text_data_ring_size) {
+ fprintf(stderr,
+ "Failed to read text_data of size %lu bytes: %s\n",
+ m.text_data_ring_size, strerror(errno));
+ exit(65);
+ }
+
+ /* ready to go */
+
+ tail_id = get_ulong(m.desc_ring + prb_desc_ring_tail_id_offset +
+ atomic_long_t_counter_offset);
+ head_id = get_ulong(m.desc_ring + prb_desc_ring_head_id_offset +
+ atomic_long_t_counter_offset);
+
+ for (id = tail_id; id != head_id; id = id_inc(id))
+ dump_record(&m, id, handler);
+
+ /* dump head record */
+ dump_record(&m, id, handler);
+
+ free(m.text_data);
+ free(m.infos);
+ free(m.descs);
+ free(m.prb);
+}
+
+void dump_dmesg(int fd, void (*handler)(char*, unsigned int))
+{
+ if (prb_vaddr)
+ dump_dmesg_lockless(fd, handler);
+ else if (log_first_idx_vaddr)
+ dump_dmesg_structured(fd, handler);
+ else
+ dump_dmesg_legacy(fd, handler);
+}
+
+int read_elf(int fd)
+{
+ int ret;
+
+ ret = pread(fd, ehdr.e_ident, EI_NIDENT, 0);
+ if (ret != EI_NIDENT) {
+ fprintf(stderr, "Read of e_ident from %s failed: %s\n",
+ fname, strerror(errno));
+ return 3;
+ }
+ if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
+ fprintf(stderr, "Missing elf signature\n");
+ return 4;
+ }
+ if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
+ fprintf(stderr, "Bad elf version\n");
+ return 5;
+ }
+ if ((ehdr.e_ident[EI_CLASS] != ELFCLASS32) &&
+ (ehdr.e_ident[EI_CLASS] != ELFCLASS64))
+ {
+ fprintf(stderr, "Unknown elf class %u\n",
+ ehdr.e_ident[EI_CLASS]);
+ return 6;
+ }
+ if ((ehdr.e_ident[EI_DATA] != ELFDATA2LSB) &&
+ (ehdr.e_ident[EI_DATA] != ELFDATA2MSB))
+ {
+ fprintf(stderr, "Unkown elf data order %u\n",
+ ehdr.e_ident[EI_DATA]);
+ return 7;
+ }
+ if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
+ read_elf32(fd);
+ else
+ read_elf64(fd);
+
+ ret = scan_note_headers(fd);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int read_phys_offset_elf_kcore(int fd, long *phys_off)
+{
+ int ret;
+
+ *phys_off = ULONG_MAX;
+
+ ret = read_elf(fd);
+ if (!ret) {
+ /* If we have a valid 'PHYS_OFFSET' by now,
+ * return it to the caller now.
+ */
+ if (phys_offset != UINT64_MAX) {
+ *phys_off = phys_offset;
+ return ret;
+ }
+ }
+
+ return 2;
+}
diff --git a/util_lib/include/elf_info.h b/util_lib/include/elf_info.h
new file mode 100644
index 0000000..fdf4c3d
--- /dev/null
+++ b/util_lib/include/elf_info.h
@@ -0,0 +1,36 @@
+#ifndef ELF_INFO_H
+#define ELF_INFO_H
+
+#define _XOPEN_SOURCE 700
+#define _GNU_SOURCE
+#define _LARGEFILE_SOURCE 1
+#define _FILE_OFFSET_BITS 64
+
+#include <endian.h>
+#include <byteswap.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <elf.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <ctype.h>
+
+int get_pt_load(int idx,
+ unsigned long long *phys_start,
+ unsigned long long *phys_end,
+ unsigned long long *virt_start,
+ unsigned long long *virt_end);
+int read_phys_offset_elf_kcore(int fd, long *phys_off);
+int read_elf(int fd);
+void dump_dmesg(int fd, void (*handler)(char*, unsigned int));
+extern void (*arch_scan_vmcoreinfo)(char *pos);
+
+#endif /* ELF_INFO_H */
diff --git a/util_lib/include/ip_checksum.h b/util_lib/include/ip_checksum.h
new file mode 100644
index 0000000..5559fa4
--- /dev/null
+++ b/util_lib/include/ip_checksum.h
@@ -0,0 +1,8 @@
+#ifndef IP_CHECKSUM_H
+#define IP_CHECKSUM_H
+
+unsigned long compute_ip_checksum(void *addr, unsigned long length);
+unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new);
+unsigned long negate_ip_checksum(unsigned long sum);
+
+#endif /* IP_CHECKSUM_H */
diff --git a/util_lib/include/sha256.h b/util_lib/include/sha256.h
new file mode 100644
index 0000000..467fb22
--- /dev/null
+++ b/util_lib/include/sha256.h
@@ -0,0 +1,22 @@
+#ifndef SHA256_H
+#define SHA256_H
+
+#include <sys/types.h>
+#include <stdint.h>
+
+typedef struct
+{
+ size_t total[2];
+ uint32_t state[8];
+ uint8_t buffer[64];
+}
+sha256_context;
+
+typedef uint8_t sha256_digest_t[32];
+
+void sha256_starts( sha256_context *ctx );
+void sha256_update( sha256_context *ctx, const uint8_t *input, size_t length );
+void sha256_finish( sha256_context *ctx, sha256_digest_t digest );
+
+
+#endif /* SHA256_H */
diff --git a/util_lib/sha256.c b/util_lib/sha256.c
new file mode 100644
index 0000000..2e61a31
--- /dev/null
+++ b/util_lib/sha256.c
@@ -0,0 +1,368 @@
+/*
+ * FIPS-180-2 compliant SHA-256 implementation
+ *
+ * Copyright (C) 2001-2003 Christophe Devine
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+
+#include "sha256.h"
+
+#define GET_UINT32(n,b,i) \
+{ \
+ (n) = ( (uint32_t) (b)[(i) ] << 24 ) | \
+ ( (uint32_t) (b)[(i) + 1] << 16 ) | \
+ ( (uint32_t) (b)[(i) + 2] << 8 ) | \
+ ( (uint32_t) (b)[(i) + 3] ); \
+}
+
+#define PUT_UINT32(n,b,i) \
+{ \
+ (b)[(i) ] = (uint8_t) ( (n) >> 24 ); \
+ (b)[(i) + 1] = (uint8_t) ( (n) >> 16 ); \
+ (b)[(i) + 2] = (uint8_t) ( (n) >> 8 ); \
+ (b)[(i) + 3] = (uint8_t) ( (n) ); \
+}
+
+void sha256_starts( sha256_context *ctx )
+{
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ ctx->state[0] = 0x6A09E667;
+ ctx->state[1] = 0xBB67AE85;
+ ctx->state[2] = 0x3C6EF372;
+ ctx->state[3] = 0xA54FF53A;
+ ctx->state[4] = 0x510E527F;
+ ctx->state[5] = 0x9B05688C;
+ ctx->state[6] = 0x1F83D9AB;
+ ctx->state[7] = 0x5BE0CD19;
+}
+
+void sha256_process( sha256_context *ctx, const uint8_t data[64] )
+{
+ uint32_t temp1, temp2, W[64];
+ uint32_t A, B, C, D, E, F, G, H;
+
+ GET_UINT32( W[0], data, 0 );
+ GET_UINT32( W[1], data, 4 );
+ GET_UINT32( W[2], data, 8 );
+ GET_UINT32( W[3], data, 12 );
+ GET_UINT32( W[4], data, 16 );
+ GET_UINT32( W[5], data, 20 );
+ GET_UINT32( W[6], data, 24 );
+ GET_UINT32( W[7], data, 28 );
+ GET_UINT32( W[8], data, 32 );
+ GET_UINT32( W[9], data, 36 );
+ GET_UINT32( W[10], data, 40 );
+ GET_UINT32( W[11], data, 44 );
+ GET_UINT32( W[12], data, 48 );
+ GET_UINT32( W[13], data, 52 );
+ GET_UINT32( W[14], data, 56 );
+ GET_UINT32( W[15], data, 60 );
+
+#define SHR(x,n) ((x & 0xFFFFFFFF) >> n)
+#define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
+
+#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3))
+#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10))
+
+#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
+#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
+
+#define F0(x,y,z) ((x & y) | (z & (x | y)))
+#define F1(x,y,z) (z ^ (x & (y ^ z)))
+
+#define R(t) \
+( \
+ W[t] = S1(W[t - 2]) + W[t - 7] + \
+ S0(W[t - 15]) + W[t - 16] \
+)
+
+#define P(a,b,c,d,e,f,g,h,x,K) \
+{ \
+ temp1 = h + S3(e) + F1(e,f,g) + K + x; \
+ temp2 = S2(a) + F0(a,b,c); \
+ d += temp1; h = temp1 + temp2; \
+}
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+ E = ctx->state[4];
+ F = ctx->state[5];
+ G = ctx->state[6];
+ H = ctx->state[7];
+
+ P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98 );
+ P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491 );
+ P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF );
+ P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5 );
+ P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B );
+ P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1 );
+ P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4 );
+ P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5 );
+ P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98 );
+ P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01 );
+ P( G, H, A, B, C, D, E, F, W[10], 0x243185BE );
+ P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3 );
+ P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74 );
+ P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE );
+ P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7 );
+ P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174 );
+ P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1 );
+ P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786 );
+ P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6 );
+ P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC );
+ P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F );
+ P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA );
+ P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC );
+ P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA );
+ P( A, B, C, D, E, F, G, H, R(24), 0x983E5152 );
+ P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D );
+ P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8 );
+ P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7 );
+ P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3 );
+ P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147 );
+ P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351 );
+ P( B, C, D, E, F, G, H, A, R(31), 0x14292967 );
+ P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85 );
+ P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138 );
+ P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC );
+ P( F, G, H, A, B, C, D, E, R(35), 0x53380D13 );
+ P( E, F, G, H, A, B, C, D, R(36), 0x650A7354 );
+ P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB );
+ P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E );
+ P( B, C, D, E, F, G, H, A, R(39), 0x92722C85 );
+ P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1 );
+ P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B );
+ P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70 );
+ P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3 );
+ P( E, F, G, H, A, B, C, D, R(44), 0xD192E819 );
+ P( D, E, F, G, H, A, B, C, R(45), 0xD6990624 );
+ P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585 );
+ P( B, C, D, E, F, G, H, A, R(47), 0x106AA070 );
+ P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116 );
+ P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08 );
+ P( G, H, A, B, C, D, E, F, R(50), 0x2748774C );
+ P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5 );
+ P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3 );
+ P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A );
+ P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F );
+ P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3 );
+ P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE );
+ P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F );
+ P( G, H, A, B, C, D, E, F, R(58), 0x84C87814 );
+ P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208 );
+ P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA );
+ P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB );
+ P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7 );
+ P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2 );
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+ ctx->state[4] += E;
+ ctx->state[5] += F;
+ ctx->state[6] += G;
+ ctx->state[7] += H;
+}
+
+void sha256_update( sha256_context *ctx, const uint8_t *input, size_t length )
+{
+ size_t left, fill;
+
+ if( ! length ) return;
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += length;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if( ctx->total[0] < length )
+ ctx->total[1]++;
+
+ if( left && length >= fill )
+ {
+ memcpy( ctx->buffer + left, input, fill );
+ sha256_process( ctx, ctx->buffer );
+ length -= fill;
+ input += fill;
+ left = 0;
+ }
+
+ while( length >= 64 )
+ {
+ sha256_process( ctx, input );
+ length -= 64;
+ input += 64;
+ }
+
+ if( length )
+ {
+ memcpy(ctx->buffer + left, input, length);
+ }
+}
+
+static uint8_t sha256_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+void sha256_finish( sha256_context *ctx, sha256_digest_t digest )
+{
+ uint32_t last, padn;
+ uint32_t high, low;
+ uint8_t msglen[8];
+
+ high = ( ctx->total[0] >> 29 )
+ | ( ctx->total[1] << 3 );
+ low = ( ctx->total[0] << 3 );
+
+ PUT_UINT32( high, msglen, 0 );
+ PUT_UINT32( low, msglen, 4 );
+
+ last = ctx->total[0] & 0x3F;
+ padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+ sha256_update( ctx, sha256_padding, padn );
+ sha256_update( ctx, msglen, 8 );
+
+ PUT_UINT32( ctx->state[0], digest, 0 );
+ PUT_UINT32( ctx->state[1], digest, 4 );
+ PUT_UINT32( ctx->state[2], digest, 8 );
+ PUT_UINT32( ctx->state[3], digest, 12 );
+ PUT_UINT32( ctx->state[4], digest, 16 );
+ PUT_UINT32( ctx->state[5], digest, 20 );
+ PUT_UINT32( ctx->state[6], digest, 24 );
+ PUT_UINT32( ctx->state[7], digest, 28 );
+}
+
+#ifdef TEST
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ * those are the standard FIPS-180-2 test vectors
+ */
+
+static char *msg[] =
+{
+ "abc",
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ NULL
+};
+
+static char *val[] =
+{
+ "ba7816bf8f01cfea414140de5dae2223" \
+ "b00361a396177a9cb410ff61f20015ad",
+ "248d6a61d20638b8e5c026930c3e6039" \
+ "a33ce45964ff2167f6ecedd419db06c1",
+ "cdc76e5c9914fb9281a1c7e284d73e67" \
+ "f1809a48a497200e046d39ccc7112cd0"
+};
+
+int main( int argc, char *argv[] )
+{
+ FILE *f;
+ int i, j;
+ char output[65];
+ sha256_context ctx;
+ unsigned char buf[1000];
+ unsigned char sha256sum[32];
+
+ if( argc < 2 )
+ {
+ printf( "\n SHA-256 Validation Tests:\n\n" );
+
+ for( i = 0; i < 3; i++ )
+ {
+ printf( " Test %d ", i + 1 );
+
+ sha256_starts( &ctx );
+
+ if( i < 2 )
+ {
+ sha256_update( &ctx, (uint8_t *) msg[i],
+ strlen( msg[i] ) );
+ }
+ else
+ {
+ memset( buf, 'a', 1000 );
+
+ for( j = 0; j < 1000; j++ )
+ {
+ sha256_update( &ctx, (uint8_t *) buf, 1000 );
+ }
+ }
+
+ sha256_finish( &ctx, sha256sum );
+
+ for( j = 0; j < 32; j++ )
+ {
+ sprintf( output + j * 2, "%02x", sha256sum[j] );
+ }
+
+ if( memcmp( output, val[i], 64 ) )
+ {
+ printf( "failed!\n" );
+ return( 1 );
+ }
+
+ printf( "passed.\n" );
+ }
+
+ printf( "\n" );
+ }
+ else
+ {
+ if( ! ( f = fopen( argv[1], "rb" ) ) )
+ {
+ perror( "fopen" );
+ return( 1 );
+ }
+
+ sha256_starts( &ctx );
+
+ while( ( i = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
+ {
+ sha256_update( &ctx, buf, i );
+ }
+
+ sha256_finish( &ctx, sha256sum );
+
+ for( j = 0; j < 32; j++ )
+ {
+ printf( "%02x", sha256sum[j] );
+ }
+
+ printf( " %s\n", argv[1] );
+ }
+
+ return( 0 );
+}
+
+#endif
+