Ressurect the ez-elf code.
authorNot Zed <notzed@gmail.com>
Fri, 4 Dec 2020 04:35:02 +0000 (15:05 +1030)
committerNot Zed <notzed@gmail.com>
Fri, 4 Dec 2020 04:35:02 +0000 (15:05 +1030)
Add a 'basic' blob serialisation which matches the original libeze.
Add a blob serialisation compiler for generating marshalling stubs.

14 files changed:
Makefile
ez-bitset.c
ez-blob-basic.c [new file with mode: 0644]
ez-blob-basic.h [new file with mode: 0644]
ez-blob-compiler.c [new file with mode: 0644]
ez-blob-io.c
ez-blob-io.h
ez-blob-tagz.c
ez-blob-xdrn.c
ez-blob-xdrn.h
ez-blob.h
ez-elf.c [new file with mode: 0644]
ez-elf.h [new file with mode: 0644]
test-blob.c

index f16320f..115646f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -9,11 +9,13 @@ SRCS=                                         \
  ez-bitset.c                                   \
  ez-blob.c                                     \
  ez-blob.c                                     \
+ ez-blob-basic.c                               \
  ez-blob-io.c                                  \
  ez-blob-print.c                               \
  ez-blob-dump.c                                        \
  ez-blob-tagz.c                                        \
  ez-blob-xdrn.c                                        \
+ ez-elf.c                                      \
  ez-port.c                                     \
  ez-set.c                                      \
  ez-tree.c
@@ -21,9 +23,11 @@ SRCS=                                                \
 HEADERS =                                      \
  ez-bitset.h                                   \
  ez-blob.h                                     \
+ ez-blob-basic.h                               \
  ez-blobio.h                                   \
  ez-blob-tagz.h                                        \
  ez-blob-xdrn.h                                        \
+ ez-elf.h                                      \
  ez-list.h                                     \
  ez-node.h                                     \
  ez-port.h                                     \
@@ -36,7 +40,9 @@ TESTS=$(test_SRCS:.c=)
 
 OBJS=$(SRCS:.c=.o)
 
-all: libeze.a($(OBJS))
+all: libeze.a($(OBJS)) ez-blob-compiler
+
+ez-blob-compiler: ez-blob-compiler.o libeze.a
 
 libeze.a: libeze.a($(OBJS))
 tests: $(TESTS)
@@ -58,7 +64,7 @@ test-tree: libeze.a(ez-tree.o)
 
 dist: libeze-$(VERSION).tar.gz
 
-libeze-$(VERSION).tar.gz: $(HEADERS) $(SRCS) $(test_SRCS) Makefile README CHANGES COPYING
+libeze-$(VERSION).tar.gz: $(HEADERS) $(SRCS) $(test_SRCS) Makefile README CHANGES COPYING ez-blob-compiler.c
        tar -c                                          \
                --transform=s@^@libeze-$(VERSION)/@     \
                -f $@                                   \
index ae975fb..19a2253 100644 (file)
@@ -40,9 +40,9 @@
 #define L1B 9
 #define L2B 14
 
-#define L0 (1<<L0B)
-#define L1 (1<<L1B)
-#define L2 ((1<<L2B)/32)
+#define L0 (1U<<L0B)
+#define L1 (1U<<L1B)
+#define L2 ((1U<<L2B)/32)
 
 #define L0S (L1B+L2B)
 #define L1S (L2B)
@@ -86,7 +86,7 @@ static uint32_t bitset_scan_next(ez_bitset *set, ez_bitset_scan *scan) __attribu
 static uint32_t bitset_scan_next(ez_bitset *set, ez_bitset_scan *scan) {
        struct level1 *l1 = scan->l1;
        struct level2 *l2 = scan->l2;
-       
+
        while (scan->bits == 0 && scan->id0 < L0) {
                if (l2) {
                retrybit:
@@ -109,7 +109,7 @@ static uint32_t bitset_scan_next(ez_bitset *set, ez_bitset_scan *scan) {
                                }
                        }
                }
-               
+
                scan->id1 = 0;
 
                while (scan->id0 < L0) {
@@ -126,7 +126,7 @@ static uint32_t bitset_scan_next(ez_bitset *set, ez_bitset_scan *scan) {
                index = ffs(scan->bits) -1 ;
                scan->bits &= ~(1<<index);
                scan->bit = index;
-               
+
                return scan->offset + index;
        }
 
@@ -157,7 +157,7 @@ void ez_bitset_clear(ez_bitset *bs) {
                        bs->level1[id0] = NULL;
                        free(l1);
                }
-               
+
        }
        bs->count = 0;
 }
@@ -177,8 +177,8 @@ int ez_bitset_get(ez_bitset *bs, uint32_t bit) {
                        return (l2->bits[id2] & id3) != 0;
                }
        }
-       
-       return 0;       
+
+       return 0;
 }
 
 int ez_bitset_set(ez_bitset *bs, uint32_t bit, int value) {
@@ -218,9 +218,9 @@ int ez_bitset_set(ez_bitset *bs, uint32_t bit, int value) {
                        }
                }
        }
-       
-       return 0;       
-       
+
+       return 0;
+
 }
 
 uint32_t ez_bitset_card(ez_bitset *bs) {
@@ -242,6 +242,22 @@ uint32_t ez_bitset_scan_remove(ez_bitset_scan *scan) {
 
        l2->bits[scan->id2 - 1] &= ~(1<<scan->bit);
        scan->set->count -= 1;
-       
+
        return bitset_scan_next(scan->set, scan);
 }
+
+#include <stdio.h>
+
+int main(int argc, char **argv) {
+       printf("L0 %3d L0M %08x L0S %2d  %08x\n", L0, L0M, L0S, L0M << L0S);
+       printf("L1 %3d L1M %08x L1S %2d  %08x\n", L1, L1M, L1S, L1M << L1S);
+       printf("L2 %3d L2M %08x L2S %2d  %08x\n", L2, L2M, L2S, L2M << L2S);
+
+       uint32_t s = 0xffffffff;
+       uint32_t t = 0xf0000000;
+
+       printf(" %d %d\n", s-t, t-s);
+
+
+       return 0;
+}
diff --git a/ez-blob-basic.c b/ez-blob-basic.c
new file mode 100644 (file)
index 0000000..c0da23a
--- /dev/null
@@ -0,0 +1,255 @@
+/* ez-blob-basic.c: Basic encoding
+
+   Copyright (C) 2020 Michael Zucchi
+
+   This program is free software: you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation, either version 3 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this program. If not, see
+   <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <assert.h>
+
+#include "ez-blob.h"
+#include "ez-blob-basic.h"
+
+/*
+ This implements a basic 'high performance' serialisation based on the
+ descriptors.
+
+ Fields are encoded in the same order as the descriptor with no
+ labelling.  Therefore the same descriptor must be used on both ends.
+ Fields may be at arbitrary alignments.
+
+ primitives
+  encoded in machine order at native size
+
+ strings
+  4-byte length followed by characters.  No nul termination.  A length
+  of ~0 indicates a null string pointer.
+
+** not implemented yet
+ arrays
+  4-byte length followed by data.  ** currently null pointer arrays with zero length are converted to a zero-length array.
+
+ struct
+  4-byte length followed by blob-encoded data.
+
+** not implemented yet
+ pointer
+  4-byte length followed by blob-encoded data.  A length of ~0
+  indicates a null pointer.
+
+*/
+
+size_t ez_basic_size(const ez_blob_desc *desc, const void *p) {
+       size_t size = 0;
+
+       for (int i=0,dlen=desc->bd_length;i<dlen;i++) {
+               const ez_blob_desc *d = &desc[i+1];
+               int pshift = (d->bd_type & 3);
+               int ptype = d->bd_type & EZ_BLOB_TYPE;
+               const void *v = (p + d->bd_offset);
+
+               switch (d->bd_type & EZ_BLOB_STORAGE) {
+               case EZ_BLOB_SINGLE:
+                       if (ptype == EZ_BLOB_STRUCT)
+                               size += 4 + ez_basic_size(d->bd_table, v);
+                       else
+                               size += 1 << pshift;
+                       break;
+               case EZ_BLOB_SINGLEP:
+                       if (ptype == EZ_BLOB_STRUCT)
+                               size += ez_basic_size(d->bd_table, *(const void **)v);
+                       else
+                               abort();
+                       break;
+               case EZ_BLOB_CSTRING:
+                       if (ptype == EZ_BLOB_INT8)
+                               size += (*(const char **)v) ? 4 + strlen(*(const char **)v) : 4;
+                       else
+                               abort();
+                       break;
+               default:
+                       abort();
+               }
+       }
+
+       return size;
+}
+
+int ez_basic_decode_raw(const ez_blob_desc *desc, const ez_blob *blob, void *p) {
+       const char *b = blob->eb_data;
+       size_t size = blob->eb_size;
+       const char *be = b + size;
+
+       memset(p, 0, desc->bd_offset);
+
+       for (int i=0,dlen=desc->bd_length;i<dlen;i++) {
+               const ez_blob_desc *d = &desc[i+1];
+               int ptype = d->bd_type & EZ_BLOB_TYPE;
+               void *v = (p + d->bd_offset);
+
+               switch (d->bd_type & EZ_BLOB_STORAGE) {
+               case EZ_BLOB_SINGLE:
+                       switch (ptype) {
+                       case EZ_BLOB_INT8:
+                               *(uint8_t *)v = *(uint8_t *)b;
+                               b += 1;
+                               break;
+                       case EZ_BLOB_INT16:
+                               *(uint16_t *)v = *(uint16_t *)b;
+                               b += 2;
+                               break;
+                       case EZ_BLOB_INT32:
+                       case EZ_BLOB_FLOAT32:
+                               *(uint32_t *)v = *(uint32_t *)b;
+                               b += 4;
+                               break;
+                       case EZ_BLOB_INT64:
+                       case EZ_BLOB_FLOAT64:
+                               *(uint64_t *)v = *(uint64_t *)b;
+                               b += 8;
+                               break;
+                       case EZ_BLOB_STRUCT: {
+                               const ez_blob data = { .eb_size = *(uint32_t *)b, .eb_data = (void *)(b+4) };
+
+                               ez_basic_decode_raw(d->bd_table, &data, v);
+                               b += 4 + data.eb_size;
+                               break;
+                       }
+                       }
+                       break;
+               case EZ_BLOB_SINGLEP:
+                       abort();
+                       break;
+               case EZ_BLOB_CSTRING:
+                       if (ptype == EZ_BLOB_INT8) {
+                               uint32_t size = *(uint32_t *)b;
+                               if (size != ~0U) {
+                                       *(char **)v = malloc(size+1);
+                                       memcpy(*(char **)v, b+4, size);
+                                       (*(char **)v)[size] = 0;
+                                       b += 4 + size;
+                               } else {
+                                       *(char **)v = NULL;
+                                       b += 4;
+                               }
+                       } else
+                               abort();
+                       break;
+               default:
+                       abort();
+               }
+       }
+       if (b != be)
+               goto fail;
+
+       return 0;
+ fail:
+       ez_blob_free_raw(desc, p);
+       return -1;
+}
+
+void *ez_basic_decode(const ez_blob_desc *d, const ez_blob *blob) {
+       void *p = calloc(d->bd_offset, 1);
+
+       if (ez_basic_decode_raw(d, blob, p) != 0) {
+               free(p);
+               return NULL;
+       }
+
+       return p;
+}
+
+int ez_basic_encode_raw(const ez_blob_desc *desc, const void *p, ez_blob *blob) {
+       char *b = blob->eb_data;
+       size_t size = blob->eb_size;
+       char *be = b+size;
+
+       for (int i=0,dlen=desc->bd_length;i<dlen;i++) {
+               const ez_blob_desc *d = &desc[i+1];
+               int ptype = d->bd_type & EZ_BLOB_TYPE;
+               const void *v = (p + d->bd_offset);
+
+               switch (d->bd_type & EZ_BLOB_STORAGE) {
+               case EZ_BLOB_SINGLE:
+                       switch (ptype) {
+                       case EZ_BLOB_INT8:
+                               *(uint8_t *)b = *(uint8_t *)v;
+                               b += 1;
+                               break;
+                       case EZ_BLOB_INT16:
+                               *(uint16_t *)b = *(uint16_t *)v;
+                               b += 2;
+                               break;
+                       case EZ_BLOB_INT32:
+                       case EZ_BLOB_FLOAT32:
+                               *(uint32_t *)b = *(uint32_t *)v;
+                               b += 4;
+                               break;
+                       case EZ_BLOB_INT64:
+                       case EZ_BLOB_FLOAT64:
+                               *(uint64_t *)b = *(uint64_t *)v;
+                               b += 8;
+                               break;
+                       case EZ_BLOB_STRUCT: {
+                               ez_blob data = { .eb_size = ez_basic_size(d->bd_table, v), .eb_data = b + 4 };
+
+                               *(uint32_t *)b = data.eb_size;
+
+                               ez_basic_encode_raw(d->bd_table, v, &data);
+                               b += 4 + data.eb_size;
+                               break;
+                       }
+                       }
+                       break;
+               case EZ_BLOB_SINGLEP:
+                       abort();
+                       break;
+               case EZ_BLOB_CSTRING:
+                       if (ptype == EZ_BLOB_INT8) {
+                               const char *s = *(const char **)v;
+
+                               if (s) {
+                                       size_t len = strlen(s);
+                                       *(uint32_t *)b = len;
+                                       memcpy(b+4, s, len);
+                                       b[4+len] = 0;
+                                       b += 4 + len;
+                               } else {
+                                       *(uint32_t *)b = ~0U;
+                                       b += 4;
+                               }
+                       } else
+                               abort();
+                       break;
+               default:
+                       abort();
+               }
+       }
+       assert(b == be);
+       return 0;
+}
+
+int ez_basic_encode(const ez_blob_desc *d, const void *p, ez_blob *blob) {
+       blob->eb_size = ez_basic_size(d, p);
+       blob->eb_data = malloc(blob->eb_size);
+
+       ez_basic_encode_raw(d, p, blob);
+
+       return 0;
+}
diff --git a/ez-blob-basic.h b/ez-blob-basic.h
new file mode 100644 (file)
index 0000000..f8a4133
--- /dev/null
@@ -0,0 +1,36 @@
+/* ez-blob-basic.c: Basic encoder.
+
+   Copyright (C) 2020 Michael Zucchi
+
+   This program is free software: you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation, either version 3 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this program. If not, see
+   <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef EZ_BLOB_BASIC_H
+#define EZ_BLOB_BASIC_H
+
+/*
+  Currently 'basic' only has limited encoding support for
+  primitive types, strings of int8, and embedded structures.
+ */
+
+size_t ez_basic_size(const ez_blob_desc *d, const void *p);
+
+int ez_basic_encode_raw(const ez_blob_desc *d, const void *p, ez_blob *blob);
+int ez_basic_encode(const ez_blob_desc *d, const void *p, ez_blob *blob);
+
+int ez_basic_decode_raw(const ez_blob_desc *d, const ez_blob *blob, void *p);
+void *ez_basic_decode(const ez_blob_desc *d, const ez_blob *blob);
+
+#endif
diff --git a/ez-blob-compiler.c b/ez-blob-compiler.c
new file mode 100644 (file)
index 0000000..2050d3f
--- /dev/null
@@ -0,0 +1,377 @@
+/* ez-blob-compiler.c: Compiler for blob descriptors.
+
+   Copyright (C) 2020 Michael Zucchi
+
+   This program is free software: you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation, either version 3 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this program. If not, see
+   <http://www.gnu.org/licenses/>.
+*/
+
+/*
+  This generates encode/decode for a specific structure in a manner compatible
+  with the 'basic' encoder.  It is about 2-3x faster than using the table based
+  routines.
+
+  This also generates an 'obstack' based decoder interface which
+  stores all data in an obstack memory allocator - much faster for the
+  decode routine.
+
+  usage: ez-blob-compiler object.o descriptor-name > api.c
+
+  First compile the code that contains the descriptor array, then run this on
+  the generated object file to extract the compiled descriptor information.  The
+  descriptors must be exported symbols.
+
+ */
+
+#define _GNU_SOURCE
+
+#include <time.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ez-blob.h"
+#include "ez-elf.h"
+
+static int doinline = 0;
+//static int doobstack = 1;
+static ez_elf *elf;
+
+void export_size(const ez_blob_desc *desc, const char *name) {
+       size_t size = 0;
+       int strings = 0;
+
+       printf("size_t %s_size(const void * __restrict p) {\n", name);
+
+       for (int i=0,dlen=desc->bd_length;i<dlen;i++) {
+               const ez_blob_desc *d = &desc[i+1];
+               switch (d->bd_type) {
+               case EZ_BLOB_INT8:
+                       size += 1;
+                       break;
+               case EZ_BLOB_INT16:
+                       size += 2;
+                       break;
+               case EZ_BLOB_INT32:
+               case EZ_BLOB_FLOAT32:
+                       size += 4;
+                       break;
+               case EZ_BLOB_INT64:
+               case EZ_BLOB_FLOAT64:
+                       size += 8;
+                       break;
+               case EZ_BLOB_INT8 | EZ_BLOB_CSTRING:
+                       strings = 1;
+                       break;
+               default:
+                       fprintf(stderr, "Unsupported type: %d\n", d->bd_type);
+                       abort();
+               }
+       }
+
+       if (strings) {
+               printf("\tsize_t size = %zd;\n", size);
+               printf("\tconst char *s;\n");
+               for (int i=0,dlen=desc->bd_length;i<dlen;i++) {
+                       const ez_blob_desc *d = &desc[i+1];
+                       switch (d->bd_type) {
+                       case EZ_BLOB_INT8:
+                       case EZ_BLOB_INT16:
+                       case EZ_BLOB_INT32:
+                       case EZ_BLOB_INT64:
+                       case EZ_BLOB_FLOAT32:
+                       case EZ_BLOB_FLOAT64:
+                               break;
+                       case EZ_BLOB_INT8 | EZ_BLOB_CSTRING:
+                               if (doinline) {
+                                       printf("\ts = *(const char **)(p + %d);\n", d->bd_offset);
+                                       printf("\tsize += s ? strlen(s) + 4 : 4;\n");
+                               } else {
+                                       printf("\tsize += string_size(*(const char **)(p + %d));\n", d->bd_offset);
+                               }
+                               break;
+                       default:
+                               fprintf(stderr, "Unsupported type: %d\n", d->bd_type);
+                               abort();
+                       }
+               }
+               printf("\treturn size;\n");
+       } else {
+               printf("\treturn (size_t)%zd;\n", size);
+       }
+
+       printf("}\n");
+}
+
+void export_encode(const ez_blob_desc *desc, const char *name) {
+       printf("void %s_encode_raw(const void * __restrict p, ez_blob *blob) {\n", name);
+       printf("\tchar * __restrict b = blob->eb_data;\n");
+       printf("\tconst char *s;\n");
+
+       for (int i=0,dlen=desc->bd_length;i<dlen;i++) {
+               const ez_blob_desc *d = &desc[i+1];
+
+               printf("\t// %d: %s\n", d->bd_id, (char *)ez_elf_read_addr(elf, &d->bd_name));
+
+               switch (d->bd_type) {
+               case EZ_BLOB_INT8:
+                       printf("\t*(uint8_t *)b = *(uint8_t *)(p + %d); b += 1;\n", d->bd_offset);
+                       break;
+               case EZ_BLOB_INT16:
+                       printf("\t*(uint16_t *)b = *(uint16_t *)(p + %d); b += 2;\n", d->bd_offset);
+                       break;
+               case EZ_BLOB_INT32:
+               case EZ_BLOB_FLOAT32:
+                       printf("\t*(uint32_t *)b = *(uint32_t *)(p + %d); b += 4;\n", d->bd_offset);
+                       break;
+               case EZ_BLOB_INT64:
+               case EZ_BLOB_FLOAT64:
+                       printf("\t*(uint64_t *)b = *(uint64_t *)(p + %d); b += 8;\n", d->bd_offset);
+                       break;
+               case EZ_BLOB_INT8 | EZ_BLOB_CSTRING:
+                       if (doinline) {
+                               printf("\ts = *(const char **)(p + %d);\n", d->bd_offset);
+                               printf("\tif (s) {\n"
+                                      "\t\tsize_t len = strlen(s);\n"
+                                      "\t\t*(uint32_t *)b = len;\n"
+                                      "\t\tmemcpy(b+4, s, len);\n"
+                                      "\t\tb += 4 + len;\n"
+                                      "\t} else {\n"
+                                      "\t\t*(uint32_t *)b = ~0U;\n"
+                                      "\t\tb += 4;\n"
+                                      "\t}\n");
+                       } else {
+                               printf("\tb = string_encode(b, *(const char **)(p + %d));\n", d->bd_offset);
+                       }
+                       break;
+               default:
+                       fprintf(stderr, "Unsupported type: %d\n", d->bd_type);
+                       abort();
+               }
+       }
+       printf("\tif (b - blob->eb_data != blob->eb_size) abort();\n");
+       printf("}\n");
+}
+
+void export_decode(const ez_blob_desc *desc, const char *name, int doos) {
+       if (doos) {
+               printf("void *%s_decode_os(const ez_blob * __restrict ez_blob *blob, struct obstack * __restrict os) {\n", name);
+               printf("\tvoid *p = obstack_alloc(os, %u);\n", desc->bd_offset);
+       } else {
+               printf("void %s_decode_raw(const ez_blob * __restrict blob, void * __restrict p) {\n", name);
+       }
+       printf("\tconst char * __restrict b = blob.eb_data;\n");
+       printf("\tsize_t len;\n");
+       printf("\tchar **sp;\n");
+       if (doos)
+               printf("\tmemset(p, 0, %u);\n", desc->bd_offset);
+
+       for (int i=0,dlen=desc->bd_length;i<dlen;i++) {
+               const ez_blob_desc *d = &desc[i+1];
+               switch (d->bd_type) {
+               case EZ_BLOB_INT8:
+                       printf("\t*(uint8_t *)(p + %d) = *(uint8_t *)b; b += 1;\n", d->bd_offset);
+                       break;
+               case EZ_BLOB_INT16:
+                       printf("\t*(uint16_t *)(p + %d) = *(uint16_t *)b; b += 2;\n", d->bd_offset);
+                       break;
+               case EZ_BLOB_INT32:
+               case EZ_BLOB_FLOAT32:
+                       printf("\t*(uint32_t *)(p + %d) = *(uint32_t *)b; b += 4;\n", d->bd_offset);
+                       break;
+               case EZ_BLOB_INT64:
+               case EZ_BLOB_FLOAT64:
+                       printf("\t*(uint64_t *)(p + %d) = *(uint64_t *)b; b += 8;\n", d->bd_offset);
+                       break;
+               case EZ_BLOB_INT8 | EZ_BLOB_CSTRING:
+                       if (doinline) {
+                               printf("\tsp = (char **)(p + %d);\n"
+                                      "\tlen = *(uint32_t *)b;\n"
+                                      "\tif (len != ~0U) {\n", d->bd_offset);
+                               if (doos)
+                                       printf("\t\t*sp = obstack_copy0(os, b+4, len);\n");
+                               else
+                                       printf("\t\tchar *s = malloc(len+1);\n"
+                                              "\t\tmemcpy(s, b+4, len);\n"
+                                              "\t\ts[len] = 0;\n"
+                                              "\t\t*sp = s;\n");
+                               printf("\t\tb += 4 + len;\n"
+                                      "\t} else {\n"
+                                      "\t\t*sp = NULL;\n"
+                                      "\t\tb += 4;\n"
+                                      "\t}\n");
+                       } else {
+                               if (doos)
+                                       printf("\tb = string_decodeos(b, (char **)(p + %d), os);\n", d->bd_offset);
+                               else
+                                       printf("\tb = string_decode(b, (char **)(p + %d));\n", d->bd_offset);
+                       }
+                       break;
+               default:
+                       fprintf(stderr, "Unsupported type: %d\n", d->bd_type);
+                       abort();
+               }
+       }
+       printf("\tif (b - blob->eb_data != blob->eb_size) abort();\n");
+       if (doos)
+               printf("\treturn p;\n");
+       printf("}\n");
+}
+
+int main(int argc, char **argv) {
+       int gen = ~0;
+       int header = 0;
+       char *file = NULL;
+       int tables = argc;
+
+       for (int i=1;i<argc;i++) {
+               char *cmd = argv[i];
+
+               if (strcmp(cmd, "--generate") == 0 || strcmp(cmd, "-g") == 0) {
+                       char *genset = argv[i+1];
+                       int dogen = 0;
+                       while (genset) {
+                               char *s = genset;
+                               char *c = strchr(genset, ',');
+
+                               if (c) {
+                                       *c = 0;
+                                       genset = c + 1;
+                               } else {
+                                       genset = NULL;
+                               }
+
+                               if (strcmp(s, "all") == 0)
+                                       dogen = ~0;
+                               else if (strcmp(s, "size") == 0)
+                                       dogen |= 1;
+                               else if (strcmp(s, "encode") ==0)
+                                       dogen |= 2;
+                               else if (strcmp(s, "decode") == 0)
+                                       dogen |= 4;
+                               else if (strcmp(s, "decode_obstack") == 0)
+                                       dogen |= 8;
+                               else if (strcmp(s, "header") == 0)
+                                       header = 1;
+                       }
+                       if (dogen)
+                               gen = dogen;
+                       i += 1;
+               } else {
+                       file = cmd;
+                       tables = i + 1;
+                       break;
+               }
+       }
+
+       if (!file) {
+               fprintf(stderr, "No file supplied");
+               return 1;
+       }
+
+       if (gen & 8)
+               printf("#include <obstack.h>\n");
+
+       if (!doinline && !header) {
+               printf("#include <stdint.h>\n");
+               printf("#include <libeze/ez-blob.h>\n");
+               printf("#include <string.h>\n");
+               printf("#include <stdlib.h>\n");
+
+               // should just be another link file i suppose
+               printf("static char *string_encode(char * __restrict b, const char *s) {\n"
+                      "\tif (s) {\n"
+                      "\t\tsize_t len = strlen(s);\n"
+                      "\t\t*(uint32_t *)b = len;\n"
+                      "\t\tmemcpy(b+4, s, len);\n"
+                      "\t\tb += 4 + len;\n"
+                      "\t} else {\n"
+                      "\t\t*(uint32_t *)b = ~0U;\n"
+                      "\t\tb += 4;\n"
+                      "\t}\n"
+                      "\treturn b;\n"
+                      "}\n");
+               printf("static const char *string_decode(const char * __restrict b, char **sp) {\n"
+                      "\tsize_t len = *(uint32_t *)b;\n"
+                      "\tif (len != ~0U) {\n"
+                      "\t\tchar *s = malloc(len+1);\n"
+                      "\t\tmemcpy(s, b+4, len);\n"
+                      "\t\ts[len] = 0;\n"
+                      "\t\t*sp = s;\n"
+                      "\t\tb += 4 + len;\n"
+                      "\t} else {\n"
+                      "\t\t*sp = NULL;\n"
+                      "\t\tb += 4;\n"
+                      "\t}\n"
+                      "\treturn b;\n"
+                      "}\n");
+               if (gen & 8)
+                       printf("static const char *string_decodeos(const char * __restrict b, char **sp, struct obstack *os) {\n"
+                              "\tsize_t len = *(uint32_t *)b;\n"
+                              "\tif (len != ~0U) {\n"
+                              "\t\t*sp = obstack_copy0(os, b+4, len);\n"
+                              "\t\tb += 4 + len;\n"
+                              "\t} else {\n"
+                              "\t\t*sp = NULL;\n"
+                              "\t\tb += 4;\n"
+                              "\t}\n"
+                              "\treturn b;\n"
+                              "}\n");
+               printf("static size_t string_size(const char *s) {\n"
+                      "\treturn s ? strlen(s) + 4 : 4;\n"
+                      "}\n");
+       }
+
+       elf = ez_elf_open(file);
+
+       for (int i=tables; i<argc; i++) {
+
+               int dsize;
+               const ez_blob_desc *desc;
+
+               ez_elf_addr(elf, argv[i], &dsize, (const void **)&desc);
+
+               //printf("Desc %p, size %d\n", desc, dsize);
+               const char *name = ez_elf_read_addr(elf, &desc->bd_name);
+               char *xname = strdupa(name);
+
+               if (strncmp(xname, "struct ", 7) == 0)
+                       xname[6] = '_';
+
+               if (header) {
+                       if (gen & 1)
+                               printf("size_t %s_size(const void *p);\n", xname);
+                       if (gen & 2)
+                               printf("void %s_encode_raw(const void *p, ez_blob *blob);\n", xname);
+                       if (gen & 4)
+                               printf("void %s_decode_raw(const ez_blob *blob, void *p);\n", xname);
+                       if (gen & 8)
+                               printf("void *%s_decode_os(const ez_blob *blob, struct obstack *os)\n", xname);
+               } else {
+                       if (gen & 1)
+                               export_size(desc, xname);
+                       if (gen & 2)
+                               export_encode(desc, xname);
+                       if (gen & 4)
+                               export_decode(desc, xname, 0);
+                       if (gen & 8)
+                               export_decode(desc, xname, 1);
+               }
+
+       }
+       ez_elf_close(elf);
+
+       return 0;
+}
index 51b59ea..ce26327 100644 (file)
@@ -41,11 +41,11 @@ void *blobio_reserve(struct ez_blobio * __restrict io, size_t len) {
        case BLOBIO_WRITE_ALLOC:
                if (to > size) {
                        void *alloc;
-                       
+
                        do {
                                size = size ? size * 2 : 256;
                        } while (to > size);
-                       
+
                        io->size = size;
                        alloc = realloc(io->data, size);
 
@@ -101,10 +101,8 @@ void blobio_write_align(struct ez_blobio *io, unsigned int step) {
        int skip = (step - io->index) & (step-1);
        uint8_t *v;
 
-       if (skip && (v = blobio_reserve(io, skip))) {
-               for (int i=0;i<skip;i++)
-                       v[i] = 0;
-       }
+       if (skip && (v = blobio_reserve(io, skip)))
+               memset(v, 0, skip);
 }
 
 void blobio_read_align(struct ez_blobio *io, unsigned int step) {
@@ -112,3 +110,75 @@ void blobio_read_align(struct ez_blobio *io, unsigned int step) {
 
        blobio_take(io, skip);
 }
+
+#ifndef BLOBIO_INLINE
+ void blobio_write(struct ez_blobio *io, const void *data, size_t len) {
+       void *v = blobio_reserve(io, len);
+       if (v) memcpy(v, data, len);
+}
+
+void blobio_writeb(struct ez_blobio *io, uint8_t val) {
+       uint8_t *v = blobio_reserve(io, 1);
+       if (v) *v = val;
+}
+
+void blobio_write8(struct ez_blobio *io, uint8_t val) {
+       uint8_t *v = blobio_reserve(io, 1);
+       if (v) *v = val;
+}
+
+void blobio_write16(struct ez_blobio *io, uint16_t val) {
+       uint16_t *v = blobio_reserve(io, 2);
+       if (v) *v = val;
+}
+
+void blobio_write32(struct ez_blobio *io, uint32_t val) {
+       uint32_t *v = blobio_reserve(io, 4);
+       if (v) *v = val;
+}
+
+void blobio_write64(struct ez_blobio *io, uint64_t val) {
+       uint64_t *v = blobio_reserve(io, 8);
+       if (v) *v = val;
+}
+
+void blobio_writef(struct ez_blobio *io, float val) {
+       float *v = blobio_reserve(io, 4);
+       if (v) *v = val;
+}
+
+void blobio_writed(struct ez_blobio *io, double val) {
+       double *v = blobio_reserve(io, 8);
+       if (v) *v = val;
+}
+
+uint8_t blobio_readi8(struct ez_blobio *io) {
+       uint8_t *v = blobio_take(io, 1);
+       return v ? *v : 0;
+}
+
+uint16_t blobio_readi16(struct ez_blobio *io) {
+       uint16_t *v = blobio_take(io, 2);
+       return v ? *v : 0;
+}
+
+uint32_t blobio_readi32(struct ez_blobio *io) {
+       uint32_t *v = blobio_take(io, 4);
+       return v ? *v : 0;
+}
+
+uint64_t blobio_readi64(struct ez_blobio *io) {
+       uint64_t *v = blobio_take(io, 8);
+       return v ? *v : 0;
+}
+
+float blobio_readf(struct ez_blobio *io) {
+       float *v = blobio_take(io, 4);
+       return v ? *v : 0.0f;
+}
+
+double blobio_readd(struct ez_blobio *io) {
+       double *v = blobio_take(io, 8);
+       return v ? *v : 0.0;
+}
+#endif
index f3ccf4a..8e07197 100644 (file)
@@ -44,7 +44,7 @@ struct ez_blobio {
  * Reserve write-space.
  *
  * For BLOBIO_WRITE_ALLOC mode this will fail if any allocation fails.
- * 
+ *
  * For BLOBIO_WRITE_FIXED this will fail if there is a buffer
  * overflow.
  *
@@ -100,6 +100,9 @@ void blobio_dumphex(const char *data, size_t size, const char *prefix);
   calls an external function anyway.
  */
 
+#define BLOBIO_INLINE
+#ifdef BLOBIO_INLINE
+
 static __inline__  void blobio_write(struct ez_blobio *io, const void *data, size_t len) {
        void *v = blobio_reserve(io, len);
        if (v) memcpy(v, data, len);
@@ -169,3 +172,23 @@ static __inline__ double blobio_readd(struct ez_blobio *io) {
        double *v = blobio_take(io, 8);
        return v ? *v : 0.0;
 }
+
+#else
+
+void blobio_write(struct ez_blobio *io, const void *data, size_t len);
+void blobio_writeb(struct ez_blobio *io, uint8_t val);
+void blobio_write8(struct ez_blobio *io, uint8_t val);
+void blobio_write16(struct ez_blobio *io, uint16_t val);
+void blobio_write32(struct ez_blobio *io, uint32_t val);
+void blobio_write64(struct ez_blobio *io, uint64_t val);
+void blobio_writef(struct ez_blobio *io, float val);
+void blobio_writed(struct ez_blobio *io, double val);
+
+uint8_t blobio_readi8(struct ez_blobio *io);
+uint16_t blobio_readi16(struct ez_blobio *io);
+uint32_t blobio_readi32(struct ez_blobio *io);
+uint64_t blobio_readi64(struct ez_blobio *io);
+float blobio_readf(struct ez_blobio *io);
+double blobio_readd(struct ez_blobio *io);
+
+#endif
index 467eba7..80b4bc9 100644 (file)
@@ -332,8 +332,8 @@ int ez_tagz_encode(const ez_blob_desc *d, const void *p, ez_blob *blob) {
                blob->eb_data = io.data;
                return 0;
        }
-       
-       free(io.data);  
+
+       free(io.data);
        blob->eb_data = NULL;
        blob->eb_size = 0;
 
@@ -405,7 +405,7 @@ static void tagz_decode_fields(struct ez_blobio *io, const ez_blob_desc *desc, v
                                        io->error = EILSEQ;
                                        return;
                                }
-                               
+
                                switch (d->bd_type & (EZ_BLOB_STORAGE | EZ_BLOB_TYPE)) {
                                        /* typed vectors */
                                case EZ_BLOB_VECTOR | EZ_BLOB_INT8:
@@ -439,7 +439,7 @@ static void tagz_decode_fields(struct ez_blobio *io, const ez_blob_desc *desc, v
                                        void *src = blobio_take(io, size);
                                        if (src) {
                                                char *mem = malloc(size+1);
-                                               
+
                                                if (mem) {
                                                        memcpy(mem, src, size);
                                                        mem[size] = 0;
@@ -451,7 +451,7 @@ static void tagz_decode_fields(struct ez_blobio *io, const ez_blob_desc *desc, v
                                        }
                                        break;
                                }
-                                       
+
                                        /* List */
                                case EZ_BLOB_STRUCT | EZ_BLOB_LISTP:
                                        *(void **)v = malloc(sizeof(ez_list));
@@ -464,7 +464,7 @@ static void tagz_decode_fields(struct ez_blobio *io, const ez_blob_desc *desc, v
                                case EZ_BLOB_STRUCT | EZ_BLOB_LIST:
                                        for (int i=0; !io->error && i < fcount; i++) {
                                                void *node = ez_blob_alloc(d->bd_table);
-                                               
+
                                                if (node) {
                                                        tagz_decode_struct(io, d->bd_table, node);
                                                        ez_list_addtail((ez_list *)v, node);
@@ -487,7 +487,7 @@ static void tagz_decode_fields(struct ez_blobio *io, const ez_blob_desc *desc, v
                                }
 
                                switch (d->bd_type & (EZ_BLOB_STORAGE | EZ_BLOB_TYPE)) {
-                               
+
                                case EZ_BLOB_SINGLE | EZ_BLOB_INT8:
                                        *(uint8_t *)v = blobio_readi(io, sc);
                                        break;
@@ -587,7 +587,7 @@ int ez_tagz_decode_raw(const ez_blob_desc *desc, const ez_blob *blob, void *p) {
 
        if (!io.error)
                return 0;
-       
+
        ez_blob_free_raw(desc, p);
        return io.error;
 }
index 4c87819..4c6d144 100644 (file)
@@ -102,10 +102,20 @@ static void xdrio_readv(struct ez_blobio *io, ez_blob *data, size_t elshift) {
 static void xdrio_writes(struct ez_blobio *io, const char *v) {
        if (v) {
                int32_t size = strlen(v);
-
+#if 0
+               int32_t total = (size + 4 + 3) & ~3;
+               void *v = blobio_reserve(io, total);
+
+               if (v) {
+                       *((uint32_t *)v) = size;
+                       memcpy(v+4, v, size);
+                       memset(v+4+size, 0, total-size-4);
+               }
+#else
                blobio_write32(io, size);
                blobio_write(io, v, size);
                blobio_write_align(io, 4);
+#endif
        } else {
                io->error = EINVAL;
        }
@@ -396,7 +406,7 @@ int ez_xdrn_decode_raw(const ez_blob_desc *desc, const ez_blob *blob, void *p) {
 
        if (!io.error)
                return 0;
-       
+
        ez_blob_free_raw(desc, p);
        return io.error;
 }
index 90e7af5..0cfa77c 100644 (file)
@@ -21,6 +21,7 @@
 #define _EZ_BLOB_XDRN_H
 
 size_t ez_xdrn_size(const ez_blob_desc *d, const void *p);
+
 int ez_xdrn_encode_raw(const ez_blob_desc *d, const void *p, ez_blob *blob);
 int ez_xdrn_encode(const ez_blob_desc *d, const void *p, ez_blob *blob);
 
index f316bd6..dcb4eeb 100644 (file)
--- a/ez-blob.h
+++ b/ez-blob.h
  * A structure is described by an array of ez_blob_desc.  The first
  * entry must have bd_offset=sizeof(structure), and bd_length=the
  * number of field annotats which follow.
- * 
+ *
  * As an example:
- * 
+ *
  * typedef struct dbdisk {
  *     int id;
  *     char *uuid;
  *     char *label;
  *     char *type;
  * } dbdisk;
- * 
+ *
  * Has a table such as this, using the init macros.
- * 
+ *
  * static ez_blob_desc DISK_ENC[] = {
  *     EZ_BLOB_START(dbdisk, 0, 3),
  *     EZ_BLOB_STRING(dbdisk, 1, uuid),
  *     EZ_BLOB_STRING(dbdisk, 2, label),
  *     EZ_BLOB_STRING(dbdisk, 3, type),
  * };
- * 
+ *
  * The 'id' field and it's semantics are serialiser dependent.
- * 
+ *
  */
 typedef struct ez_blob_desc {
        unsigned short bd_type;         // type of field
        unsigned short bd_id;           // used to tag encoded entries
        unsigned int bd_offset;         // offset into structure, if type == EZ_BLOB_PK then this is sizeof(struct)
+       const char *bd_name;            // name of entry
        union {
                const struct ez_blob_desc *bd_table;// embedded structure or pointer
                unsigned int bd_length;
@@ -80,24 +81,25 @@ typedef enum ez_blob_desc_type {
        EZ_BLOB_SINGLE = 0x00,          // the value at bd_offset
        EZ_BLOB_SINGLEP = 0x10,         // pointer to value at bd_offset
        EZ_BLOB_CSTRING = 0x20,         // 0-terminated string pointer
-       
+
        EZ_BLOB_VECTOR = 0x40,          // ez_blob at bd_offset
        EZ_BLOB_VECTORP = 0x50,         // pointer to ez_blob at bd_offset
        EZ_BLOB_LIST = 0x60,            // ez_list at bd_offset
        EZ_BLOB_LISTP = 0x70,           // pointer to ez_list at bd_offset
 
        /* Options */
-       EZ_BLOB_ISNULLABLE = (1<<8),
+       EZ_BLOB_ISNULLABLE = 0x100,
 
        /* meta */
        EZ_BLOB_SIZE = 0x03,            // size mask for int or float types
        EZ_BLOB_TYPE = 0x0f,            // Type mask
        EZ_BLOB_STORAGE = 0xf0,         // Storage mask
+       EZ_BLOB_STORAGEB = 4,           // Storage shift
 
        EZ_BLOB_MAGIC = 0x10f5
 } ez_blob_desc_type;
 
-/** 
+/**
  * This is compatible with lmdb MDB_val
  */
 typedef struct ez_blob {
@@ -113,31 +115,31 @@ typedef struct ez_blob {
        };
 } ez_blob;
 
-#define EZ_BLOB_START(s, id, len) { EZ_BLOB_MAGIC, id, sizeof(s), .bd_length = len }
+#define EZ_BLOB_START(s, id, len) { EZ_BLOB_MAGIC, id, sizeof(s), #s, .bd_length = len }
 
-#define EZ_BLOB_INT8(s, id, f) { EZ_BLOB_INT8 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
-#define EZ_BLOB_INT16(s, id, f) { EZ_BLOB_INT16 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
-#define EZ_BLOB_INT32(s, id, f) { EZ_BLOB_INT32 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
-#define EZ_BLOB_INT64(s, id, f) { EZ_BLOB_INT64 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
-#define EZ_BLOB_FLOAT32(s, id, f) { EZ_BLOB_FLOAT32 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
-#define EZ_BLOB_FLOAT64(s, id, f) { EZ_BLOB_FLOAT64 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
+#define EZ_BLOB_INT8(s, id, f) { EZ_BLOB_INT8 | EZ_BLOB_SINGLE, id, offsetof(s, f), #f }
+#define EZ_BLOB_INT16(s, id, f) { EZ_BLOB_INT16 | EZ_BLOB_SINGLE, id, offsetof(s, f), #f }
+#define EZ_BLOB_INT32(s, id, f) { EZ_BLOB_INT32 | EZ_BLOB_SINGLE, id, offsetof(s, f), #f }
+#define EZ_BLOB_INT64(s, id, f) { EZ_BLOB_INT64 | EZ_BLOB_SINGLE, id, offsetof(s, f), #f }
+#define EZ_BLOB_FLOAT32(s, id, f) { EZ_BLOB_FLOAT32 | EZ_BLOB_SINGLE, id, offsetof(s, f), #f }
+#define EZ_BLOB_FLOAT64(s, id, f) { EZ_BLOB_FLOAT64 | EZ_BLOB_SINGLE, id, offsetof(s, f), #f }
 
-#define EZ_BLOB_INT8V(s, id, f) { EZ_BLOB_INT8 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
-#define EZ_BLOB_INT16V(s, id, f) { EZ_BLOB_INT16 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
-#define EZ_BLOB_INT32V(s, id, f) { EZ_BLOB_INT32 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
-#define EZ_BLOB_INT64V(s, id, f) { EZ_BLOB_INT64 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
-#define EZ_BLOB_FLOAT32V(s, id, f) { EZ_BLOB_FLOAT32 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
-#define EZ_BLOB_FLOAT64V(s, id, f) { EZ_BLOB_FLOAT64 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
+#define EZ_BLOB_INT8V(s, id, f) { EZ_BLOB_INT8 | EZ_BLOB_VECTOR, id, offsetof(s, f), #f }
+#define EZ_BLOB_INT16V(s, id, f) { EZ_BLOB_INT16 | EZ_BLOB_VECTOR, id, offsetof(s, f), #f }
+#define EZ_BLOB_INT32V(s, id, f) { EZ_BLOB_INT32 | EZ_BLOB_VECTOR, id, offsetof(s, f), #f }
+#define EZ_BLOB_INT64V(s, id, f) { EZ_BLOB_INT64 | EZ_BLOB_VECTOR, id, offsetof(s, f), #f }
+#define EZ_BLOB_FLOAT32V(s, id, f) { EZ_BLOB_FLOAT32 | EZ_BLOB_VECTOR, id, offsetof(s, f), #f }
+#define EZ_BLOB_FLOAT64V(s, id, f) { EZ_BLOB_FLOAT64 | EZ_BLOB_VECTOR, id, offsetof(s, f), #f }
 
-#define EZ_BLOB_STRING(s, id, f) { EZ_BLOB_INT8 | EZ_BLOB_CSTRING, id, offsetof(s, f) }
-#define EZ_BLOB_STRINGN(s, id, f) { EZ_BLOB_INT8 | EZ_BLOB_CSTRING | EZ_BLOB_ISNULLABLE, id, offsetof(s, f) }
+#define EZ_BLOB_STRING(s, id, f) { EZ_BLOB_INT8 | EZ_BLOB_CSTRING, id, offsetof(s, f), #f }
+#define EZ_BLOB_STRINGN(s, id, f) { EZ_BLOB_INT8 | EZ_BLOB_CSTRING | EZ_BLOB_ISNULLABLE, id, offsetof(s, f), #f }
 
-#define EZ_BLOB_STRUCT(s, id, f, other) {  EZ_BLOB_STRUCT | EZ_BLOB_SINGLE, id, offsetof(s, f), .bd_table = other }
-#define EZ_BLOB_STRUCTP(s, id, f, other) {  EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP, id, offsetof(s, f), .bd_table = other }
-#define EZ_BLOB_STRUCTPN(s, id, f, other) {  EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP | EZ_BLOB_ISNULLABLE, id, offsetof(s, f), .bd_table = other }
+#define EZ_BLOB_STRUCT(s, id, f, other) {  EZ_BLOB_STRUCT | EZ_BLOB_SINGLE, id, offsetof(s, f), #f, .bd_table = other }
+#define EZ_BLOB_STRUCTP(s, id, f, other) {  EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP, id, offsetof(s, f), #f, .bd_table = other }
+#define EZ_BLOB_STRUCTPN(s, id, f, other) {  EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP | EZ_BLOB_ISNULLABLE, id, offsetof(s, f), #f, .bd_table = other }
 
-#define EZ_BLOB_LIST(s, id, f, other) { EZ_BLOB_STRUCT | EZ_BLOB_LIST, id, offsetof(s, f), .bd_table = other }
-#define EZ_BLOB_LISTPN(s, id, f, other) { EZ_BLOB_STRUCT | EZ_BLOB_LISTP | EZ_BLOB_ISNULLABLE, id, offsetof(s, f), .bd_table = other }
+#define EZ_BLOB_LIST(s, id, f, other) { EZ_BLOB_STRUCT | EZ_BLOB_LIST, id, offsetof(s, f), #f, .bd_table = other }
+#define EZ_BLOB_LISTPN(s, id, f, other) { EZ_BLOB_STRUCT | EZ_BLOB_LISTP | EZ_BLOB_ISNULLABLE, id, offsetof(s, f), #f, .bd_table = other }
 
 /**
  * Allocate a new structure to hold a blob.
diff --git a/ez-elf.c b/ez-elf.c
new file mode 100644 (file)
index 0000000..5bdc02e
--- /dev/null
+++ b/ez-elf.c
@@ -0,0 +1,420 @@
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stddef.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "ez-elf.h"
+#include "ez-set.h"
+
+typedef Elf64_Xword elf_addr_t;
+
+struct ez_elf {
+       void *base;
+       size_t size;
+       char *name;
+
+       Elf64_Shdr *symtab; // elf_shdr_name(hdr, ".symtab");
+
+       // Symbol indices
+       const char *names;
+
+       // Both tables store the same object.  Only one should free
+       // its items.
+       struct ez_set byname;
+       struct ez_set byaddr;
+};
+
+/**
+   This same object is stored in both hash tables.
+
+   Use by*_as_entry to map to the object.
+ */
+struct elf_entry {
+       struct ez_node byname;
+       struct ez_node byaddr;
+
+       const char *name;
+       const Elf64_Sym *sym;
+       //elf_add_t addr;
+};
+
+static struct elf_entry *byaddr_as_entry(const void *a) {
+       return (struct elf_entry *)(a - offsetof(struct elf_entry, byaddr));
+}
+
+static struct elf_entry *byname_as_entry(const void *a) {
+       return (struct elf_entry *)(a - offsetof(struct elf_entry, byname));
+}
+
+static int byaddr_equals(const void *ap, const void *bp) {
+       struct elf_entry *a = byaddr_as_entry(ap), *b = byaddr_as_entry(bp);
+
+       return a->sym->st_value == b->sym->st_value;
+}
+
+static unsigned int byaddr_hash(const void *ap) {
+       const struct elf_entry *a = byaddr_as_entry(ap);
+
+       return ez_hash_int64(a->sym->st_value);
+}
+
+static int byname_equals(const void *ap, const void *bp) {
+       const struct elf_entry *a = byname_as_entry(ap), *b = byname_as_entry(bp);
+
+       return strcmp(a->name, b->name) == 0;
+}
+
+static unsigned int byname_hash(const void *ap) {
+       const struct elf_entry *a = byname_as_entry(ap);
+
+       return ez_hash_string(a->name);
+}
+
+/**
+ * Resolve the starting address of a data block of a section
+ */
+static void *elf_data(Elf64_Ehdr *hdr, int i) {
+       void *base = hdr;
+       Elf64_Shdr *shdr = base + hdr->e_shoff + hdr->e_shentsize * i;
+
+       return base + shdr->sh_offset;
+}
+
+#if 0
+/**
+ * Resolve the address of an item in a section table
+ */
+static void *elf_data_item(Elf64_Ehdr *hdr, Elf64_Shdr *sh, int i) {
+       void *base = hdr;
+
+       return base + sh->sh_offset + sh->sh_entsize * i;
+}
+#endif
+
+/**
+ * Resolve section by number
+ */
+static Elf64_Shdr *elf_shdr(Elf64_Ehdr *hdr, int i) {
+       void *base = hdr;
+
+       return base + hdr->e_shoff + hdr->e_shentsize * i;
+}
+
+/**
+ * Resolve section by name
+ */
+static Elf64_Shdr *elf_shdr_name(Elf64_Ehdr *hdr, const char *name) {
+       const char *names = elf_data(hdr, hdr->e_shstrndx);
+       int i;
+
+       for (i=0;i<hdr->e_shnum;i++) {
+               Elf64_Shdr *shdr =  elf_shdr(hdr, i);
+               int nameid = shdr->sh_name;
+
+               if (nameid == SHN_UNDEF
+                   || nameid >= SHN_LORESERVE)
+                       continue;
+
+               if (!strcmp(name, names + nameid))
+                       return shdr;
+       }
+
+       return NULL;
+}
+
+#if 0
+/**
+ * Resolve programme header by id
+ */
+static Elf64_Phdr *elf_phdr(Elf64_Ehdr *hdr, int i) {
+       void *base = hdr;
+
+       return base + hdr->e_phoff + hdr->e_phentsize * i;
+}
+#endif
+
+/**
+ * Find a reloc hunk that references section
+ */
+static Elf64_Shdr *elf_reloc_section(Elf64_Ehdr *hdr, int section) {
+       int i;
+
+       for (i=0;i<hdr->e_shnum;i++) {
+               Elf64_Shdr *shdr = elf_shdr(hdr, i);
+
+               if (shdr->sh_type == SHT_RELA  && shdr->sh_info == section)
+                       return shdr;
+       }
+
+       return NULL;
+}
+
+static Elf64_Sym *elf_sym(struct ez_elf *elf, int i) {
+       return elf->base + elf->symtab->sh_offset + elf->symtab->sh_entsize * i;
+}
+
+static void elf_init(struct ez_elf *elf) {
+       Elf64_Ehdr *hdr = elf->base;
+       Elf64_Shdr *shdr = elf_shdr_name(hdr, ".symtab");
+       void *ss, *se;
+
+       ez_set_init(&elf->byname, byname_hash, byname_equals, free);
+       ez_set_init(&elf->byaddr, byaddr_hash, byaddr_equals, NULL);
+
+       if (!shdr) {
+               elf->names = NULL;
+               return;
+       }
+
+       elf->names = elf_data(hdr, shdr->sh_link);
+
+       elf->symtab = shdr;
+
+       ss = elf->base + shdr->sh_offset;
+       se = ss + shdr->sh_size;
+
+       for (; ss<se; ss += shdr->sh_entsize) {
+               Elf64_Sym *sym = ss;
+
+               if (sym->st_name) {
+                       struct elf_entry *e;
+
+                       e = malloc(sizeof(*e));
+                       e->name = elf->names + sym->st_name;
+                       e->sym = sym;
+
+                       //printf("entry: %s\n", e->name);
+
+                       if (ez_set_get(&elf->byname, &e->byname)) {
+                               fprintf(stderr, "duplicate symbol name ignored: %s\n", e->name);
+                               free(e);
+                               continue;
+                       }
+                       ez_set_put(&elf->byname, &e->byname);
+
+                       if (sym->st_value) {
+                               if (ez_set_get(&elf->byaddr, &e->byaddr)) {
+                                       fprintf(stderr, "duplicate symbol addr ignored: %s\n", e->name);
+                               } else
+                                       ez_set_put(&elf->byaddr, &e->byaddr);
+                       }
+               }
+       }
+}
+
+/**
+ * Open an elf file
+ */
+struct ez_elf *ez_elf_open(const char *name) {
+       int fd;
+       void *base;
+       struct stat st;
+       struct ez_elf *elf = NULL;
+
+       fd = open(name, O_RDONLY);
+       if (fd == -1)
+               return NULL;
+
+       if (fstat(fd, &st) == -1)
+               goto fail;
+
+       base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if (!base)
+               goto fail;
+
+       fprintf(stderr, "elf_open('%s') mmap=%p\n", name, base);
+
+       elf = malloc(sizeof(*elf));
+       elf->name = strdup(name);
+       elf->base = base;
+       elf->size = st.st_size;
+
+       elf_init(elf);
+
+ fail:
+       close(fd);
+
+       return elf;
+}
+
+void ez_elf_close(struct ez_elf *elf) {
+       munmap(elf->base, elf->size);
+
+       ez_set_clear(&elf->byaddr);
+       ez_set_clear(&elf->byname);
+
+       free(elf);
+}
+
+const void *ez_elf_read_addr(struct ez_elf *elf, const void *addr) {
+       // find section it belongs to
+       Elf64_Ehdr *hdr = elf->base;
+       off_t offset = addr - elf->base;
+       //const char *names = elf_data(hdr, hdr->e_shstrndx);
+
+       for (int i=0;i<hdr->e_shnum;i++) {
+               Elf64_Shdr *shdr = elf_shdr(hdr, i);
+
+               //printf("offset %zd section %d '%s' %zd-%zd\n",
+               //      offset, i, names + shdr->sh_name,
+               //      shdr->sh_offset, shdr->sh_offset + shdr->sh_size);
+
+               if (offset >= shdr->sh_offset && offset < shdr->sh_offset + shdr->sh_size) {
+                       offset -= shdr->sh_offset;
+
+                       //printf("Section is %d  offset %p\n", i, offset);
+
+                       Elf64_Shdr *rhdr = elf_reloc_section(elf->base, i);
+                       if (rhdr) {
+                               void *ss, *se;
+
+                               ss = elf->base + rhdr->sh_offset;
+                               se = ss + rhdr->sh_size;
+                               for (; ss<se; ss += rhdr->sh_entsize) {
+                                       Elf64_Rela *rel = ss;
+                                       int symi = ELF64_R_SYM(rel->r_info);
+                                       Elf64_Sym *sym = elf_sym(elf, symi);
+
+                                       //printf("check rel offset %p\n", rel->r_offset);
+
+                                       if (rel->r_offset == offset) {
+                                               //printf(" reloc %08x [%08x] + %08x\n", rel->r_info, rel->r_offset, rel->r_addend);
+                                               switch (ELF64_R_TYPE(rel->r_info)) {
+                                               case R_X86_64_64:
+#if 0
+                                                       printf("  R_X86_64_64  sym %d '%s'\n", symi, elf->names + sym->st_name);
+                                                       printf(" name %08x\n", sym->st_name);
+                                                       printf(" valu %08x\n", sym->st_value);
+                                                       printf(" size %d\n", sym->st_size);
+                                                       printf(" info %02x\n", sym->st_info);
+                                                       printf(" sidx %02x\n", sym->st_shndx);
+                                                       printf("value: %s\n", elf_data(elf->base, sym->st_shndx) + rel->r_addend);
+#endif
+                                                       return elf_data(elf->base, sym->st_shndx) + rel->r_addend;
+                                               default:
+                                                       printf("unknown reloc type\n");
+                                               }
+                                       }
+                               }
+                       }
+                       break;
+               }
+
+               //if (shdr->sh_type == SHT_RELA  && shdr->sh_info == section)
+               //      return shdr;
+       }
+
+       return NULL;
+
+//     Elf64_Shdr *shdr = base + hdr->e_shoff + hdr->e_shentsize * i;
+
+//     return base + shdr->sh_offset;
+}
+
+/**
+ * Resolve a raw symbol value, optionally the mapped address and data size
+ *
+ * TODO: reloc entries?
+ */
+elf_addr_t ez_elf_addr(struct ez_elf *elf, const char *name, int *sizep, const void **ptr) {
+       struct elf_entry key = { .name = name };
+       struct ez_node *n;
+
+       n = ez_set_get(&elf->byname, &key.byname);
+       if (n) {
+               struct elf_entry *e = byname_as_entry(n);
+               void *mem = elf_data(elf->base, e->sym->st_shndx) + e->sym->st_value;
+               int size = e->sym->st_size;
+
+               if (sizep)
+                       *sizep = size;
+               if (ptr)
+                       *ptr = mem;
+
+               //ez_elf_reloc(elf, mem + 8);
+
+               /* TODO: find a way to get relocs to actual data
+                  Perhaps resolve_addr(), but it's dependent on ?
+                  addr -> find section
+                  section -> find relocs
+               */
+
+#if 0
+               printf(" name %08x\n", e->sym->st_name);
+               printf(" valu %08x\n", e->sym->st_value);
+               printf(" size %d\n", e->sym->st_size);
+               printf(" info %02x\n", e->sym->st_info);
+               printf(" sidx %02x\n", e->sym->st_shndx);
+
+               Elf64_Shdr *rhdr = elf_reloc_section(elf->base, e->sym->st_shndx);
+               if (rhdr) {
+                       void *ss, *se;
+
+                       ss = elf->base + rhdr->sh_offset;
+                       se = ss + rhdr->sh_size;
+                       for (; ss<se; ss += rhdr->sh_entsize) {
+                               Elf64_Rela *rel = ss;
+                               int symi = ELF64_R_SYM(rel->r_info);
+                               Elf64_Sym *sym = elf_sym(elf, symi);
+
+                               printf("\n*Check sym range %d-%d value %d\n",
+                                      e->sym->st_value,
+                                      e->sym->st_value + e->sym->st_size,
+                                      rel->r_offset);
+
+                               if (rel->r_offset >= e->sym->st_value
+                                   && rel->r_offset < e->sym->st_value + e->sym->st_size) {
+
+                                       printf(" reloc %08x [%08x] + %08x\n", rel->r_info, rel->r_offset, rel->r_addend);
+                                       switch (ELF64_R_TYPE(rel->r_info)) {
+                                       case R_X86_64_64:
+                                               printf("  R_X86_64_64  sym %d '%s'\n", symi, elf->names + sym->st_name);
+                                               printf(" name %08x\n", sym->st_name);
+                                               printf(" valu %08x\n", sym->st_value);
+                                               printf(" size %d\n", sym->st_size);
+                                               printf(" info %02x\n", sym->st_info);
+                                               printf(" sidx %02x\n", sym->st_shndx);
+                                               printf("value: %s\n", elf_data(elf->base, sym->st_shndx) + rel->r_addend);
+                                               break;
+                                       default:
+                                               printf("unknown reloc type\n");
+                                       }
+                               }
+                       }
+               }
+#endif
+#if 0
+               printf("find addr %s\n", name);
+#endif
+               return e->sym->st_value;
+       }
+
+       return 0;
+}
+
+/**
+ * Resolve a symbol address.
+ */
+const char *ez_elf_name(struct ez_elf *elf, elf_addr_t addr, int *size) {
+       const Elf64_Sym sym = { .st_value = addr };
+       struct elf_entry key = { .sym = &sym };
+       struct ez_node *n;
+
+       n = ez_set_get(&elf->byaddr, &key.byaddr);
+       if (n) {
+               struct elf_entry *e = byaddr_as_entry(n);
+
+               if (size)
+                       *size =e->sym->st_size;
+               return e->name;
+       }
+
+       return NULL;
+}
diff --git a/ez-elf.h b/ez-elf.h
new file mode 100644 (file)
index 0000000..5ef057a
--- /dev/null
+++ b/ez-elf.h
@@ -0,0 +1,40 @@
+/* ez-elf.h: elf(64) processing
+
+   Copyright (C) 2019 Michael Zucchi
+
+   This program is free software: you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation, either version 3 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this program. If not, see
+   <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef EZ_ELF_H
+#define EZ_ELF_H
+
+#include <elf.h>
+
+typedef struct ez_elf ez_elf;
+
+typedef Elf64_Xword elf_addr_t;
+
+struct ez_elf *ez_elf_open(const char *name);
+void ez_elf_close(struct ez_elf *elf);
+elf_addr_t ez_elf_addr(struct ez_elf *elf, const char *name, int *size, const void **ptr);
+const char *ez_elf_name(struct ez_elf *elf, elf_addr_t addr, int *size);
+
+/**
+ * Read an address pointer from a structure inside the elf file.
+ * If the address has a relocation entry then it is relocated.
+ */
+const void *ez_elf_read_addr(struct ez_elf *elf, const void *addr);
+
+#endif
index 8ccb92f..e1a7588 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "ez-blob-tagz.h"
 #include "ez-blob-xdrn.h"
+#include "ez-blob-basic.h"
 
 #include "ez-blob-io.h"
 
@@ -19,7 +20,7 @@
   TODO: some bad data tests.
 
   This depends a lot on the structure and the format.
-  
+
   * lengths outside of data
   * counts that will exhaust memory
   * field id's out of range
@@ -42,16 +43,18 @@ struct simple {
        int64_t l;
        float c;
        double d;
+       char *string;
 };
 
-static const ez_blob_desc simple_DESC[] = {
-       EZ_BLOB_START(struct simple, 0, 6),
+const ez_blob_desc simple_DESC[] = {
+       EZ_BLOB_START(struct simple, 0, 7),
        EZ_BLOB_INT8(struct simple, 1, b),
        EZ_BLOB_INT16(struct simple, 2, s),
        EZ_BLOB_INT32(struct simple, 3, a),
        EZ_BLOB_INT64(struct simple, 4, l),
        EZ_BLOB_FLOAT32(struct simple, 5, c),
        EZ_BLOB_FLOAT64(struct simple, 6, d),
+       EZ_BLOB_STRING(struct simple, 7, string),
 };
 
 struct arrays {
@@ -200,7 +203,7 @@ static int blob_equals(const ez_blob_desc *desc, const void *a, const void *b) {
                                && memcmp(ua->eb_data, va->eb_data, ua->eb_size) == 0;
                        break;
                }
-                       
+
                case EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP | EZ_BLOB_ISNULLABLE:
                        if (!*(void **)u || !*(void **)v) {
                                e &= *(void **)u == *(void **)v;
@@ -235,7 +238,7 @@ static int blob_equals(const ez_blob_desc *desc, const void *a, const void *b) {
                                ez_list *ul = (void *)u;
                                ez_list *vl = (void *)v;
 
-                       
+
                                e &= ez_list_size(ul) == ez_list_size(vl);
                                for (ez_node *uw = ez_list_head(ul), *un = ez_node_succ(uw),
                                             *vw = ez_list_head(vl), *vn = ez_node_succ(uw);
@@ -264,6 +267,7 @@ static int blob_equals(const ez_blob_desc *desc, const void *a, const void *b) {
 
 struct test_funcs {
        const char *name;
+       int testno;
        int (*blob_encode)(const ez_blob_desc *d, const void *p, ez_blob *blob);
        void *(*blob_decode)(const ez_blob_desc *desc, const ez_blob *blob);
        int (*blob_decode_raw)(const ez_blob_desc *desc, const ez_blob *blob, void *p);
@@ -280,7 +284,7 @@ static void test_basics(const ez_blob_desc *d, void *src, struct test_funcs *fun
                printf("source\n");
                blob_print(d, src, 4);
        }
-       
+
        res = funcs->blob_encode(d, src, &blob);
        if (res == ENOMEM) {
                printf(" encode failed: probably out of memory, skipped testing this\n");
@@ -292,7 +296,7 @@ static void test_basics(const ez_blob_desc *d, void *src, struct test_funcs *fun
                dumphex(blob.eb_data, blob.eb_size, "serial: ");
        else
                dumphex(blob.eb_data, blob.eb_size < 256 ? blob.eb_size : 256, "header: ");
-               
+
        // check decode equals
        t = funcs->blob_decode(d, &blob);
        assert(t != NULL);
@@ -330,7 +334,7 @@ static void test_basics(const ez_blob_desc *d, void *src, struct test_funcs *fun
 
 static void test_simple(struct test_funcs *funcs) {
        struct simple src = {
-               'z', 0xff0f, 1, 0xf01040a04010dULL, 3.14159f, 5644941221133
+               'z', 0xff0f, 1, 0xf01040a04010dULL, 3.14159f, 5644941221133, "hello test"
        };
        const ez_blob_desc *d = simple_DESC;
 
@@ -356,7 +360,7 @@ static void test_struct(struct test_funcs *funcs) {
        char data[10] = { 1, 2, 3, 4, 5, 6, 7, 1, 2, 3 };
        struct embedded src = {
                {
-                       -1, -1, -1, -1, 1337.4004, 6.022E23,
+                       -1, -1, -1, -1, 1337.4004, 6.022E23, "foobar"
                },
                {
                        55, "Jane was there.", .array.eb_size = 10, .array.eb_data = data
@@ -398,7 +402,7 @@ static void test_list(struct test_funcs *funcs) {
        //      ez_list_init(&list.
        for (int i=0;i<3;i++)
                ez_list_addtail(&list.list, &nodes[i]);
-       
+
        const ez_blob_desc *d = list_DESC;
 
        printf("test list\n");
@@ -411,14 +415,14 @@ static void test_intsize(struct test_funcs *funcs) {
        struct intsize src;
 
        // Checks that the sizes reconstruct to their original values
-       
+
        for (int i=0;i<8;i++) {
                uint64_t size = sizes[i];
 
                src.value16 = size;
                src.value32 = size;
                src.value64 = size;
-               
+
                printf("test int value %016lx\n", size);
                test_basics(d, &src, funcs);
        }
@@ -429,7 +433,7 @@ static void test_stringsize(struct test_funcs *funcs) {
        const ez_blob_desc *d = stringsize_DESC;
        struct stringsize src;
        int sprint = doprint;
-       
+
        for (int i=0;i<7;i++) {
                size_t size = sizes[i];
 
@@ -440,7 +444,7 @@ static void test_stringsize(struct test_funcs *funcs) {
                        printf("skip string size %zd\n", size);
                        continue;
                }
-               
+
                src.value = malloc(size+1);
                if (src.value) {
                        memset(src.value, ' ', size);
@@ -464,7 +468,7 @@ static void test_corrupt_bit(struct test_funcs *funcs) {
        char data[10] = { 1, 2, 3, 4, 5, 6, 7, 1, 2, 3 };
        struct embedded src = {
                {
-                       -1, -1, -1, -1, 1337.4004, 6.022E23,
+                       -1, -1, -1, -1, 1337.4004, 6.022E23, "hello goodbyte"
                },
                {
                        55, "Jane was there.", .array.eb_size = 10, .array.eb_data = data
@@ -476,10 +480,10 @@ static void test_corrupt_bit(struct test_funcs *funcs) {
        ez_blob blob;
 
        // test 1 corrupt bit in every position
-       
+
        // we don't know the internals so which ones would fail, but
        // can check for bad memory accesses with valgrind or crash
-       
+
        int good = 0, bad = 0;
        res = funcs->blob_encode(d, &src, &blob);
        assert(res == 0);
@@ -489,7 +493,7 @@ static void test_corrupt_bit(struct test_funcs *funcs) {
                        data[i] ^= (1<<j);
                        dst = funcs->blob_decode(d, &blob);
                        data[i] ^= (1<<j);
-                       
+
                        if (dst) {
                                good++;
                                ez_blob_free(d, dst);
@@ -506,7 +510,7 @@ static void test_corrupt_byte(struct test_funcs *funcs) {
        char data[10] = { 1, 2, 3, 4, 5, 6, 7, 1, 2, 3 };
        struct embedded src = {
                {
-                       -1, -1, -1, -1, 1337.4004, 6.022E23,
+                       -1, -1, -1, -1, 1337.4004, 6.022E23, "lol"
                },
                {
                        55, "Jane was there.", .array.eb_size = 10, .array.eb_data = data
@@ -542,17 +546,23 @@ static void test_corrupt_byte(struct test_funcs *funcs) {
 
 struct test_funcs backends[] = {
        {
-               "tagz",
+               "tagz", 0,
                ez_tagz_encode,
                ez_tagz_decode,
                ez_tagz_decode_raw
        },
        {
-               "xdrn",
+               "xdrn", 0,
                ez_xdrn_encode,
                ez_xdrn_decode,
                ez_xdrn_decode_raw
-       },      
+       },
+       {
+               "basic", 1,
+               ez_basic_encode,
+               ez_basic_decode,
+               ez_basic_decode_raw
+       },
 };
 
 struct {
@@ -575,11 +585,11 @@ int main(int argc, char **argv) {
        int ntest = sizeof(tests)/sizeof(tests[0]);
 
        dolarge = (argc >= 2);
-       
+
        for (int i=0;i<nfunc;i++) {
                struct test_funcs *f = &backends[i];
 
-               for (int j=0;j<ntest;j++) {
+               for (int j=0;j<ntest && (f->testno == 0 || j < f->testno);j++) {
                        printf("* **********************************************************************\n");
                        printf("* test: %s / %s\n", f->name, tests[j].name);
                        fflush(stdout);