mirror of
https://github.com/kenshineto/kern.git
synced 2025-04-13 22:17:25 +00:00
229 lines
5.4 KiB
C
229 lines
5.4 KiB
C
/**
|
|
** @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;
|
|
}
|