From 055994bb898ed989a53e6686a9329552e95c2709 Mon Sep 17 00:00:00 2001 From: Not Zed Date: Fri, 4 Dec 2020 15:05:02 +1030 Subject: [PATCH] Ressurect the ez-elf code. Add a 'basic' blob serialisation which matches the original libeze. Add a blob serialisation compiler for generating marshalling stubs. --- Makefile | 10 +- ez-bitset.c | 42 +++-- ez-blob-basic.c | 255 +++++++++++++++++++++++++++ ez-blob-basic.h | 36 ++++ ez-blob-compiler.c | 377 ++++++++++++++++++++++++++++++++++++++++ ez-blob-io.c | 82 ++++++++- ez-blob-io.h | 25 ++- ez-blob-tagz.c | 16 +- ez-blob-xdrn.c | 14 +- ez-blob-xdrn.h | 1 + ez-blob.h | 60 +++---- ez-elf.c | 420 +++++++++++++++++++++++++++++++++++++++++++++ ez-elf.h | 40 +++++ test-blob.c | 58 ++++--- 14 files changed, 1351 insertions(+), 85 deletions(-) create mode 100644 ez-blob-basic.c create mode 100644 ez-blob-basic.h create mode 100644 ez-blob-compiler.c create mode 100644 ez-elf.c create mode 100644 ez-elf.h diff --git a/Makefile b/Makefile index f16320f..115646f 100644 --- 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 $@ \ diff --git a/ez-bitset.c b/ez-bitset.c index ae975fb..19a2253 100644 --- a/ez-bitset.c +++ b/ez-bitset.c @@ -40,9 +40,9 @@ #define L1B 9 #define L2B 14 -#define L0 (1<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<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<bit); scan->set->count -= 1; - + return bitset_scan_next(scan->set, scan); } + +#include + +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 index 0000000..c0da23a --- /dev/null +++ b/ez-blob-basic.c @@ -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 + . +*/ + +#include +#include +#include + +#include + +#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;ibd_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;ibd_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;ibd_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 index 0000000..f8a4133 --- /dev/null +++ b/ez-blob-basic.h @@ -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 + . +*/ + +#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 index 0000000..2050d3f --- /dev/null +++ b/ez-blob-compiler.c @@ -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 + . +*/ + +/* + 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 +#include +#include +#include +#include + +#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;ibd_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;ibd_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;ibd_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;ibd_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\n"); + + if (!doinline && !header) { + printf("#include \n"); + printf("#include \n"); + printf("#include \n"); + printf("#include \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; ibd_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; +} diff --git a/ez-blob-io.c b/ez-blob-io.c index 51b59ea..ce26327 100644 --- a/ez-blob-io.c +++ b/ez-blob-io.c @@ -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;ieb_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; } diff --git a/ez-blob-xdrn.c b/ez-blob-xdrn.c index 4c87819..4c6d144 100644 --- a/ez-blob-xdrn.c +++ b/ez-blob-xdrn.c @@ -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; } diff --git a/ez-blob-xdrn.h b/ez-blob-xdrn.h index 90e7af5..0cfa77c 100644 --- a/ez-blob-xdrn.h +++ b/ez-blob-xdrn.h @@ -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); diff --git a/ez-blob.h b/ez-blob.h index f316bd6..dcb4eeb 100644 --- a/ez-blob.h +++ b/ez-blob.h @@ -31,32 +31,33 @@ * 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 index 0000000..5bdc02e --- /dev/null +++ b/ez-elf.c @@ -0,0 +1,420 @@ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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;ie_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;ie_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 (; sssh_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;ie_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 (; sssh_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 (; sssh_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 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 + . +*/ + +#ifndef EZ_ELF_H +#define EZ_ELF_H + +#include + +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 diff --git a/test-blob.c b/test-blob.c index 8ccb92f..e1a7588 100644 --- a/test-blob.c +++ b/test-blob.c @@ -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<blob_decode(d, &blob); data[i] ^= (1<= 2); - + for (int i=0;itestno == 0 || j < f->testno);j++) { printf("* **********************************************************************\n"); printf("* test: %s / %s\n", f->name, tests[j].name); fflush(stdout); -- 2.39.5