Add a 'basic' blob serialisation which matches the original libeze.
Add a blob serialisation compiler for generating marshalling stubs.
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
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 \
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)
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 $@ \
#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)
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:
}
}
}
-
+
scan->id1 = 0;
while (scan->id0 < L0) {
index = ffs(scan->bits) -1 ;
scan->bits &= ~(1<<index);
scan->bit = index;
-
+
return scan->offset + index;
}
bs->level1[id0] = NULL;
free(l1);
}
-
+
}
bs->count = 0;
}
return (l2->bits[id2] & id3) != 0;
}
}
-
- return 0;
+
+ return 0;
}
int ez_bitset_set(ez_bitset *bs, uint32_t bit, int value) {
}
}
}
-
- return 0;
-
+
+ return 0;
+
}
uint32_t ez_bitset_card(ez_bitset *bs) {
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;
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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;
+}
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);
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) {
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
* 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.
*
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);
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
blob->eb_data = io.data;
return 0;
}
-
- free(io.data);
+
+ free(io.data);
blob->eb_data = NULL;
blob->eb_size = 0;
io->error = EILSEQ;
return;
}
-
+
switch (d->bd_type & (EZ_BLOB_STORAGE | EZ_BLOB_TYPE)) {
/* typed vectors */
case EZ_BLOB_VECTOR | EZ_BLOB_INT8:
void *src = blobio_take(io, size);
if (src) {
char *mem = malloc(size+1);
-
+
if (mem) {
memcpy(mem, src, size);
mem[size] = 0;
}
break;
}
-
+
/* List */
case EZ_BLOB_STRUCT | EZ_BLOB_LISTP:
*(void **)v = malloc(sizeof(ez_list));
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);
}
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;
if (!io.error)
return 0;
-
+
ez_blob_free_raw(desc, p);
return io.error;
}
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;
}
if (!io.error)
return 0;
-
+
ez_blob_free_raw(desc, p);
return io.error;
}
#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);
* 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;
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 {
};
} 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.
--- /dev/null
+
+#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;
+}
--- /dev/null
+/* 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
#include "ez-blob-tagz.h"
#include "ez-blob-xdrn.h"
+#include "ez-blob-basic.h"
#include "ez-blob-io.h"
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
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 {
&& 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;
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);
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);
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");
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);
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;
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
// 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");
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);
}
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];
printf("skip string size %zd\n", size);
continue;
}
-
+
src.value = malloc(size+1);
if (src.value) {
memset(src.value, ' ', size);
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
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);
data[i] ^= (1<<j);
dst = funcs->blob_decode(d, &blob);
data[i] ^= (1<<j);
-
+
if (dst) {
good++;
ez_blob_free(d, dst);
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
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 {
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);