blob: 40a19699dfa5e7e3168d67e5793188773a73eefe [file] [log] [blame]
Michael Karcher703c6b92010-01-14 16:23:23 +01001/*
2 * Copyright 2010 Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; see the file COPYING. If not, write to
16 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19#include <stdio.h>
20#include <unistd.h>
21#include <fcntl.h>
22#include <errno.h>
23#include <string.h>
24#include <inttypes.h>
Michael Karcher703c6b92010-01-14 16:23:23 +010025#include <sys/mman.h>
26
Idwer Vollering0ab44552012-09-23 01:22:20 +020027#include "compat.h"
28
Luc Verhaegen9e43c3a2010-03-27 16:56:06 +010029#if !defined(le32toh) || !defined(le16toh)
30#if BYTE_ORDER == LITTLE_ENDIAN
31#define le32toh(x) (x)
32#define le16toh(x) (x)
33#else
34#include <byteswap.h>
35#define le32toh(x) bswap_32(x)
36#define le16toh(x) bswap_16(x)
37#endif
38#endif
39
Michael Karcher703c6b92010-01-14 16:23:23 +010040struct slabentry {
Anton Kochkov8f9427f2013-04-07 13:20:30 +040041 uint32_t destaddr;
42 uint32_t length_flag;
Michael Karcher703c6b92010-01-14 16:23:23 +010043};
44
45struct slabheader {
Anton Kochkov8f9427f2013-04-07 13:20:30 +040046 uint16_t entries;
47 uint16_t headersize;
48 struct slabentry blocks[0];
Michael Karcher703c6b92010-01-14 16:23:23 +010049};
50
51struct nameentry {
Anton Kochkov8f9427f2013-04-07 13:20:30 +040052 uint8_t segtype;
53 uint16_t dtor_offset;
54 char name[0];
Michael Karcher703c6b92010-01-14 16:23:23 +010055};
56
57int slabextract(const unsigned char *buffer, int bufferlen)
58{
Anton Kochkov8f9427f2013-04-07 13:20:30 +040059 const struct slabheader *h = (const void *)buffer;
60 const unsigned char *listpointer;
61 const unsigned char *datapointer;
62 int i, count, headersize;
Michael Karcher703c6b92010-01-14 16:23:23 +010063
Anton Kochkov8f9427f2013-04-07 13:20:30 +040064 headersize = le16toh(h->headersize);
65 count = le16toh(h->entries);
66 if ((headersize < ((count * 8) + 4)) || (bufferlen < headersize)) {
67 fprintf(stderr,
68 "Invalid file header - probably not a SLAB file\n");
Michael Karcher5c93e5c2010-12-07 12:27:36 +010069 return 1;
Anton Kochkov8f9427f2013-04-07 13:20:30 +040070 }
71 printf("%d entries\n", count);
Michael Karcher703c6b92010-01-14 16:23:23 +010072
Anton Kochkov8f9427f2013-04-07 13:20:30 +040073 /* FIXME: Is the 37 really constant? */
74 if (((8 * count) + 37) < headersize) {
75 listpointer = buffer + 8 * count + 37;
76 printf("Name Tp ");
77 } else {
78 listpointer = NULL; /* No names present */
79 printf("Name ");
80 }
Michael Karcher5c93e5c2010-12-07 12:27:36 +010081
Anton Kochkov8f9427f2013-04-07 13:20:30 +040082 datapointer = buffer + le32toh(h->headersize);
83
84 printf("LoadAddr size initialized\n");
85
86 for (i = 0; i < count; i++) {
87 const struct slabentry *block;
88 char filename[25];
89 uint32_t len;
90 int has_data;
91
92 if (listpointer) {
93 const struct nameentry *entry =
94 (const void *)listpointer;
95 block =
96 (const void *)(buffer +
97 le16toh(entry->dtor_offset));
98 sprintf(filename, "%.20s.bin", entry->name);
99 listpointer += strlen(entry->name) + 4;
100 printf("%-15s %02x ", entry->name, entry->segtype);
101 } else {
102 block = (const void *)(buffer + 4 + 8 * i);
103 sprintf(filename, "block%02d.bin", i);
104 printf("block%02d ", i);
105 }
106
107 len = le32toh(block->length_flag);
108 if (len & 0x80000000)
109 has_data = 1;
110 else
111 has_data = 0;
112 len &= 0x7fffffff;
113
114 printf("%08x %8d\t %s\n", le32toh(block->destaddr), len,
115 has_data ? "yes" : "no");
116
117 if (has_data) {
118 int outfd;
119
120 if (datapointer + len > buffer + bufferlen) {
121 fprintf(stderr,
122 "Not enough data. File truncated?\n");
123 return 1;
124 }
125 outfd =
126 open(filename, O_WRONLY | O_CREAT | O_TRUNC,
127 S_IRUSR | S_IWUSR);
128 if (outfd != -1) {
129 int ret = write(outfd, datapointer, len);
130 if (ret == -1)
131 fprintf(stderr, "Can't write %s: %s\n",
132 filename, strerror(errno));
133 else if (ret < len)
134 fprintf(stderr,
135 "Can't write %s completely: Disk full?\n",
136 filename);
137 close(outfd);
138 } else
139 fprintf(stderr,
140 "Can't create output file %s: %s\n",
141 filename, strerror(errno));
142 datapointer += len;
143 }
144 }
145
146 if (datapointer != buffer + bufferlen)
147 fprintf(stderr, "Warning: Unexpected %d trailing bytes",
148 (int)(buffer + bufferlen - datapointer));
149
150 return 0;
Michael Karcher703c6b92010-01-14 16:23:23 +0100151}
152
153int main(int argc, char *argv[])
154{
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400155 int infd;
156 unsigned char *InputBuffer;
157 int InputBufferSize;
Michael Karcher703c6b92010-01-14 16:23:23 +0100158
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400159 if (argc != 2) {
160 printf("usage: %s <input file>\n", argv[0]);
161 return 1;
162 }
Michael Karcher703c6b92010-01-14 16:23:23 +0100163
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400164 infd = open(argv[1], O_RDONLY);
165 if (infd < 0) {
166 fprintf(stderr, "Error: Failed to open %s: %s\n", argv[1],
167 strerror(errno));
168 return 1;
169 }
Michael Karcher703c6b92010-01-14 16:23:23 +0100170
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400171 InputBufferSize = lseek(infd, 0, SEEK_END);
172 if (InputBufferSize < 0) {
173 fprintf(stderr, "Error: Failed to lseek \"%s\": %s\n", argv[1],
174 strerror(errno));
175 return 1;
176 }
Michael Karcher703c6b92010-01-14 16:23:23 +0100177
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400178 InputBuffer =
179 mmap(NULL, InputBufferSize, PROT_READ, MAP_PRIVATE, infd, 0);
180 if (InputBuffer < 0) {
181 fprintf(stderr, "Error: Failed to mmap %s: %s\n", argv[1],
182 strerror(errno));
183 return 1;
184 }
Michael Karcher703c6b92010-01-14 16:23:23 +0100185
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400186 /* fixed header size - everything else is checked dynamically in slabextract */
187 if (InputBufferSize < 4) {
188 fprintf(stderr,
189 "Error: \"%s\" is too small to be a SLAB file.\n",
190 argv[1]);
191 return 1;
192 }
Michael Karcher703c6b92010-01-14 16:23:23 +0100193
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400194 return slabextract(InputBuffer, InputBufferSize);
Michael Karcher703c6b92010-01-14 16:23:23 +0100195}