summaryrefslogtreecommitdiff
path: root/util/listblob.c
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-03-25 17:36:52 -0400
committerFreya Murphy <freya@freyacat.org>2025-03-25 17:38:22 -0400
commit6af21e6a4f2251e71353562d5df7f376fdffc270 (patch)
treede20c7afc9878422c81e34f30c6b010075e9e69a /util/listblob.c
downloadcomus-6af21e6a4f2251e71353562d5df7f376fdffc270.tar.gz
comus-6af21e6a4f2251e71353562d5df7f376fdffc270.tar.bz2
comus-6af21e6a4f2251e71353562d5df7f376fdffc270.zip
initial checkout from wrc
Diffstat (limited to 'util/listblob.c')
-rw-r--r--util/listblob.c248
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;
+
+}