Skip to contentSkip to conversation

ramoops: scripts/ramoops.c for extracting oopses

PATCH In review Thomas Tuttle 4 participants 4 messages Oct 5, 2011 – Oct 6, 2011

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 ramoops: scripts/ramoops.c for extracting oopses

Add a C program to extract oopses stored by ramoops. Running with no arguments will list all of the records; running with an argument number will retrieve the oops from that record, if it is valid.

(In the long term, it'd be ideal to have some kernel interface to ramoops records, but this script may be useful in the short term.)

BUG=chromium-os:21113
TEST=Adhoc, seems to work :)

Change-Id I24edf4d09c96a5d89bb75859a83d5427502d4eb6
---
 scripts/ramoops.c |  175 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 175 insertions(+), 0 deletions(-)
 create mode 100644 scripts/ramoops.c
scripts/ramoops.c new file +175 -0
new file mode 100644
index 0000000..25cc7c5
@@ -0,0 +1,175 @@
+/*
+ * ramoops: Extract ramoops images from /dev/mem.
+ *
+ * Copyright (C) 2011 Thomas Tuttle <[email protected]>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of the Linux
+ * distribution for more details.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static char *progn;
+
+static void read_long(char *name, unsigned long *out)
+{
+	FILE *f = fopen(name, "r");
+	if (!f) {
+		fprintf(stderr, "%s: %s: %s\n",
+			progn, name, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (fscanf(f, "%lu", out) < 1) {
+		fprintf(stderr, "%s: %s: couldn't read a number\n",
+			progn, name);
+		exit(EXIT_FAILURE);
+	}
+
+	fclose(f);
+}
+
+static const char *MEM_NAME = "/dev/mem";
+
+static FILE *open_mem(void)
+{
+	FILE *mem = fopen(MEM_NAME, "r");
+	if (!mem) {
+		fprintf(stderr, "%s: open %s: %s\n",
+			progn, MEM_NAME, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+	return mem;
+}
+
+static void seek_mem(FILE *mem, unsigned long off)
+{
+	if (fseek(mem, off, SEEK_SET) < 0) {
+		fprintf(stderr, "%s: seek %s: %s\n",
+			progn, MEM_NAME, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void read_mem(FILE *mem, char *buf, unsigned long len)
+{
+	size_t res;
+
+	res = fread(buf, 1, len, mem);
+	if (res == 0 && ferror(mem)) {
+		fprintf(stderr, "%s: read %s: %s\n",
+			progn, MEM_NAME, strerror(errno));
+		exit(EXIT_FAILURE);
+	} else if (res < len) {
+		fprintf(stderr, "%s: read %s: short read\n",
+			progn, MEM_NAME);
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void putsn(const char *s, size_t n)
+{
+	while (*s && n-- > 0)
+		putchar(*s++);
+}
+
+static int check_record(char *buf, char *time_out, size_t time_len)
+{
+	static const char *MAGIC = "====";
+	static const size_t MAGIC_LEN = 4;
+
+	char *s;
+
+	if (memcmp(buf, MAGIC, MAGIC_LEN))
+		return 0;
+
+	s = buf + MAGIC_LEN;
+	while (*s != '\n' && --time_len > 0)
+		*time_out++ = *s++;
+	*time_out = '\0';
+
+	return 1;
+}
+
+static const int REC_LIST = -1;
+
+#define RAMOOPS_PARAM "/sys/module/ramoops/parameters/"
+
+static int print_record(int record, int contents, FILE *mem,
+			unsigned long record_size, char *buf)
+{
+	static const size_t TIME_LEN = 64;
+
+	char time[TIME_LEN];
+
+	read_mem(mem, buf, record_size);
+	fprintf(stderr, "ramoops record %d: ", record);
+	if (check_record(buf, time, TIME_LEN)) {
+		fprintf(stderr, "valid, timestamp %s\n", time);
+		if (contents)
+			putsn(buf, record_size);
+		return 0;
+	} else {
+		fprintf(stderr, "invalid\n");
+		return 1;
+	}
+}
+
+static int print_records(int record)
+{
+	unsigned long mem_address, mem_size, record_size, num_records;
+	FILE *mem;
+	int i;
+	int ret = 0;
+
+	read_long(RAMOOPS_PARAM "mem_address", &mem_address);
+	read_long(RAMOOPS_PARAM "mem_size",    &mem_size);
+	read_long(RAMOOPS_PARAM "record_size", &record_size);
+	num_records = mem_size / record_size;
+
+	if (record != REC_LIST &&
+	    (record < 0 || (unsigned long)record >= num_records)) {
+		fprintf(stderr, "%s: record number %d out of range [0, %ld)\n",
+			progn, record, num_records);
+		return 1;
+	}
+
+	buf = malloc(record_size);
+	if (!buf) {
+		fprintf(stderr, "%s: failed to allocate record buffer\n",
+			progn);
+		return 1;
+	}
+
+	mem = open_mem();
+	if (record == REC_LIST) {
+		seek_mem(mem, mem_address);
+		for (i = 0; i < (int)num_records; i++)
+			print_record(i, 0, mem, record_size, buf);
+	} else {
+		seek_mem(mem, mem_address + record * record_size);
+		ret = print_record(record, 1, mem, record_size, buf);
+	}
+	fclose(mem);
+
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	progn = argv[0];
+
+	switch (argc) {
+	case 1:
+		return print_records(REC_LIST);
+	case 2:
+		return print_records(atoi(argv[1]));
+	default:
+		fprintf(stderr, "Usage: %s [record]\n", progn);
+		return 1;
+	}
+}
Signature · 1 line
1.7.3.1
#1 lore raw
Quoted 5 lines · Thomas Tuttle

Add a C program to extract oopses stored by ramoops. Running with no arguments will list all of the records; running with an argument number will retrieve the oops from that record, if it is valid.

+ * ramoops: Extract ramoops images from /dev/mem.

How does this play with CONFIG_STRICT_DEVMEM?

#3 lore raw
In reply to Thomas Tuttle

Hi,

Quoted 10 lines · Thomas Tuttle
scripts/ramoops.c new file +10 -0
+static int print_records(int record)
+{
+	unsigned long mem_address, mem_size, record_size, num_records;
+	FILE *mem;
+	int i;
+	int ret = 0;
+
+	read_long(RAMOOPS_PARAM "mem_address", &mem_address);
+	read_long(RAMOOPS_PARAM "mem_size",    &mem_size);
+	read_long(RAMOOPS_PARAM "record_size", &record_size);

scripts/ramoops.c line 141

Quoted 10 lines
scripts/ramoops.c new file +10 -0
+	num_records = mem_size / record_size;
+
+	if (record != REC_LIST &&
+	    (record < 0 || (unsigned long)record >= num_records)) {
+		fprintf(stderr, "%s: record number %d out of range [0, %ld)\n",
+			progn, record, num_records);
+		return 1;
+	}
+
+	buf = malloc(record_size);

Since buf is not declared, this fails program compilation.

Quoted 6 lines
scripts/ramoops.c new file +6 -0
+	if (!buf) {
+		fprintf(stderr, "%s: failed to allocate record buffer\n",
+			progn);
+		return 1;
+	}
+
Signature · 4 lines
Regards,
Srivatsa S. Bhat  <[email protected]>
Linux Technology Center,
IBM India Systems and Technology Lab
#2 lore raw
In reply to [email protected]

Hi,

2011/10/5 <[email protected]>:

Quoted 9 lines · Thomas Tuttle
Quoted 5 lines

Add a C program to extract oopses stored by ramoops.  Running with no arguments will list all of the records; running with an argument number will retrieve the oops from that record, if it is valid.

+ * ramoops: Extract ramoops images from /dev/mem.

How does this play with CONFIG_STRICT_DEVMEM?

It's be a problem only if the driver uses ioremap exclusive, but it doesn't.

Marco