blob: b7c978081d3acb912c925a2bb7faecde30c1775a [file] [log] [blame]
/*
* Copyright 2010 Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
*
* 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, 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; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <inttypes.h>
#include <sys/stat.h>
#include <sys/mman.h>
#if !defined(le32toh) || !defined(le16toh)
#if BYTE_ORDER == LITTLE_ENDIAN
#define le32toh(x) (x)
#define le16toh(x) (x)
#else
#include <byteswap.h>
#define le32toh(x) bswap_32(x)
#define le16toh(x) bswap_16(x)
#endif
#endif
struct slabentry {
uint32_t destaddr;
uint32_t length_flag;
};
struct slabheader {
uint16_t entries;
uint16_t headersize;
struct slabentry blocks[0];
};
struct nameentry {
uint8_t segtype;
uint16_t dtor_offset;
char name[0];
};
int slabextract(const unsigned char *buffer, int bufferlen)
{
const struct slabheader *h = (const void *) buffer;
const unsigned char *listpointer;
const unsigned char *datapointer;
int i, count;
count = le16toh(h->entries);
printf("%d entries\n", count);
/* FIXME: Is the 37 really constant? */
if (8 * count + 37 < le32toh(h->headersize)) {
listpointer = buffer + 8 * count + 37;
printf("Name Tp ");
} else {
listpointer = NULL; /* No names present */
printf("Name ");
}
datapointer = buffer + le32toh(h->headersize);
printf("LoadAddr size initialized\n");
for (i = 0; i < count; i++) {
const struct slabentry *block;
char filename[25];
uint32_t len;
int has_data;
if (listpointer) {
const struct nameentry *entry = (const void *) listpointer;
block = (const void *) (buffer + le16toh(entry->dtor_offset));
sprintf(filename, "%.20s.bin", entry->name);
listpointer += strlen(entry->name) + 4;
printf("%-15s %02x ", entry->name, entry->segtype);
} else {
block = (const void *) (buffer + 4 + 8 * i);
sprintf(filename, "block%02d.bin", i);
printf("block%02d ", i);
}
len = le32toh(block->length_flag);
if (len & 0x80000000)
has_data = 1;
else
has_data = 0;
len &= 0x7fffffff;
printf("%08x %8d\t %s\n", le32toh(block->destaddr), len,
has_data ? "yes" : "no");
if (has_data) {
int outfd = open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR);
if (outfd != -1) {
if (write(outfd, datapointer, len) != len)
fprintf(stderr, "Can't write %s: %s\n", filename,
strerror(errno));
close(outfd);
} else
fprintf(stderr, "Can't create output file %s: %s\n", filename,
strerror(errno));
datapointer += len;
}
}
return 0;
}
int main(int argc, char *argv[])
{
int infd;
unsigned char *InputBuffer;
int InputBufferSize;
if (argc != 2) {
printf("usage: %s <input file>\n", argv[0]);
return 1;
}
infd = open(argv[1], O_RDONLY);
if (infd < 0) {
fprintf(stderr, "Error: Failed to open %s: %s\n",
argv[1], strerror(errno));
return 1;
}
InputBufferSize = lseek(infd, 0, SEEK_END);
if (InputBufferSize < 0) {
fprintf(stderr, "Error: Failed to lseek \"%s\": %s\n",
argv[1], strerror(errno));
return 1;
}
InputBuffer = mmap(NULL, InputBufferSize, PROT_READ, MAP_PRIVATE, infd, 0);
if (InputBuffer < 0) {
fprintf(stderr, "Error: Failed to mmap %s: %s\n",
argv[1], strerror(errno));
return 1;
}
if (InputBufferSize < 0x52) { /* probably incorrect */
fprintf(stderr, "Error: \"%s\" is too small to be a SLAB file.\n",
argv[1]);
return 1;
}
return slabextract(InputBuffer, InputBufferSize);
}