diff options
Diffstat (limited to 'util/listblob.c')
-rw-r--r-- | util/listblob.c | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/util/listblob.c b/util/listblob.c new file mode 100644 index 0000000..07523a6 --- /dev/null +++ b/util/listblob.c @@ -0,0 +1,248 @@ +/** +** @file listblob.c +** +** @author Warren R. Carithers +** +** Examine a binary blob of ELF files. +*/ +#define _DEFAULT_SOURCE +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <elf.h> +#include <ctype.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; + +} |