1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
|
/**
** @file listblob.c
**
** @author Warren R. Carithers
**
** Examine a binary blob of ELF files.
*/
#define _DEFAULT_SOURCE
#include <ctype.h>
#include <elf.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
/*
** Blob file organization
**
** The file begins with a four-byte magic number and a four-byte integer
** indicating the number of ELF files contained in the blob. This is
** followed by an array of 32-byte file entries, and then the contents
** of the ELF files in the order they appear in the program file table.
**
** Bytes Contents
** ----- ----------------------------
** 0 - 3 File magic number ("BLB\0")
** 4 - 7 Number of ELF files in blob ("n")
** 8 - n*32+8 Program file table
** n*32+9 - ? ELF file contents
**
** Each program file table entry contains the following information:
**
** name File name (up to 19 characters long)
** offset Byte offset to the ELF header for this file
** size Size of this ELF file, in bytes
** flags Flags related to this file
*/
// blob header: 8 bytes
typedef struct header_s {
char magic[4];
uint32_t num;
} header_t;
// The program table entry is 32 bytes long. To accomplish this, the
// name field is 20 bytes long, which allows file names of 19 characters
// (followed by a trailing NUL byte).
//
// If that field is made longer, it should be incremented in multiples
// of four to avoid the insertion of padding bytes.
#define NAMELEN 20
// program descriptor: 32 bytes
typedef struct prog_s {
char name[NAMELEN]; // truncated name (19 chars plus NUL)
uint32_t offset; // offset from the beginning of the blob
uint32_t size; // size of this ELF module
uint32_t flags; // miscellaneous flags
} prog_t;
// modules must be written as multiples of eight bytes
#define FL_ROUNDUP 0x00000001
// mask for mod 8 checking
#define FSIZE_MASK 0x00000007
// program list entry
typedef struct node_s {
prog_t *data;
struct node_s *next;
} node_t;
node_t *progs, *last_prog; // list pointers
uint32_t n_progs; // number of files being copied
uint32_t offset; // current file area offset
bool defs = false; // print CPP #defines?
bool enums = false; // print C enums?
// header string for the userids.h file
const char header[] =
"/**\n"
"** @file userids.h\n"
"**\n"
"** @author Warren R. Carithers\n"
"**\n"
"** @brief IDs for user-level programs\n"
"**\n"
"** NOTE: this file is automatically generated when the user.img file\n"
"** is created. Do not edit this manually!\n"
"*/\n"
"\n"
"#ifndef USERIDS_H_\n"
"#define USERIDS_H_\n"
"\n"
"#ifndef ASM_SRC\n"
"/*\n"
"** These IDs are used to identify the various user programs.\n"
"** Each call to exec() will provide one of these as the first\n"
"** argument.\n"
"**\n"
"** This list should be updated if/when the collection of\n"
"** user processes changes.\n"
"*/\n"
"enum users_e {";
// trailer string for the userids.h file
const char trailer[] = "\n\t// sentinel\n\t, N_USERS\n"
"};\n"
"#endif /* !ASM_SRC */\n"
"\n"
"#endif";
/**
** Name: process
**
** Process a program list entry
**
** @param num Program list index
** @param prog Pointer to the program list entry
*/
void process(uint32_t num, prog_t *prog)
{
if (defs || enums) {
char *slash = strrchr(prog->name, '/');
if (slash == NULL) {
slash = prog->name;
} else {
++slash;
}
slash[0] = toupper(slash[0]);
if (defs) {
// just printing #define statements
printf("#define %-15s %2d\n", prog->name, num);
} else {
// printing a new userids.h file
if (num == 0) {
// first one, so print the file header
puts(header);
putchar('\t');
} else {
// second or later entry; limit to 8 per line
fputs(((num & 0x7) == 0) ? ",\n\t" : ", ", stdout);
}
printf("%s", prog->name);
}
} else {
// just printing information
printf("Entry %2d: ", num);
printf("%-s,", prog->name);
printf(" offset 0x%x, size 0x%x, flags %08x\n", prog->offset,
prog->size, prog->flags);
}
}
void usage(char *name)
{
fprintf(stderr, "usage: %s [-d | -e] blob_name\n", name);
}
int main(int argc, char *argv[])
{
if (argc < 2 || argc > 3) {
usage(argv[0]);
exit(1);
}
int nameix = 1;
// could use getopt() for this, but this is easy enough
if (argc == 3) {
if (strcmp(argv[1], "-d") == 0) {
defs = true;
} else if (strcmp(argv[1], "-e") == 0) {
enums = true;
} else {
usage(argv[0]);
exit(1);
}
nameix = 2;
}
char *name = argv[nameix];
int fd = open(name, O_RDONLY);
if (fd < 0) {
perror(name);
exit(1);
}
header_t hdr;
int n = read(fd, &hdr, sizeof(header_t));
if (n != sizeof(header_t)) {
fprintf(stderr, "%s: header read returned only %d bytes\n", name, n);
close(fd);
exit(1);
}
if (strcmp(hdr.magic, "BLB") != 0) {
fprintf(stderr, "%s: bad magic number\n", name);
close(fd);
exit(1);
}
if (hdr.num < 1) {
fprintf(stderr, "%s: no programs in blob?\n", name);
close(fd);
exit(1);
}
prog_t progs[hdr.num];
n = read(fd, progs, hdr.num * sizeof(prog_t));
if (n != (int)(hdr.num * sizeof(prog_t))) {
fprintf(stderr, "%s: prog table only %d bytes, expected %lu\n", name, n,
hdr.num * sizeof(prog_t));
close(fd);
exit(1);
}
for (uint32_t i = 0; i < hdr.num; ++i) {
process(i, &progs[i]);
}
if (enums) {
// print the file trailer
puts(trailer);
}
close(fd);
return 0;
}
|