static tbc_sym_t *decode_symbols (const tenc_element_t *stb_element) { tenc_element_t element; tbc_sym_t *head = NULL; tbc_sym_t *sym = NULL; BYTE *data = stb_element->data.bytes; unsigned int length = stb_element->length; while (length > 0) { unsigned int s_length; BYTE *s_data; if (tenc_walk_to_element (data, &length, "symL", &element) < 0) return NULL; if (head == NULL) { head = (tbc_sym_t *) data; sym = head; } else { sym->next = (tbc_sym_t *) data; sym = sym->next; } s_data = element.data.bytes; s_length = element.length; data = element.next; if (load_uint (&s_data, &s_length, "offU", &(sym->offset)) < 0) return NULL; if (load_str (&s_data, &s_length, "symS", &(sym->name)) < 0) return NULL; sym->ws = 0; sym->vs = 0; sym->definition = NULL; sym->next = NULL; if (s_length > 0) { if (load_str (&s_data, &s_length, "defS", &(sym->definition)) < 0) continue; if (load_uint (&s_data, &s_length, "ws U", &(sym->ws)) < 0) continue; if (load_uint (&s_data, &s_length, "vs U", &(sym->vs)) < 0) continue; } } return head; }
static asn1_error_code load_count(const void *val, const struct counted_info *counted, size_t *count_out) { const void *countptr = (const char *)val + counted->lenoff; assert(sizeof(size_t) <= sizeof(uintmax_t)); if (counted->lensigned) { intmax_t xlen = load_int(countptr, counted->lensize); if (xlen < 0 || (uintmax_t)xlen > SIZE_MAX) return EINVAL; *count_out = xlen; } else { uintmax_t xlen = load_uint(countptr, counted->lensize); if ((size_t)xlen != xlen || xlen > SIZE_MAX) return EINVAL; *count_out = xlen; } return 0; }
/* Encode a value (contents only, no outer tag) according to a type, and return * its encoded tag information. */ static asn1_error_code encode_atype(asn1buf *buf, const void *val, const struct atype_info *a, taginfo *tag_out, size_t *len_out) { asn1_error_code ret; if (val == NULL) return ASN1_MISSING_FIELD; switch (a->type) { case atype_fn: { const struct fn_info *fn = a->tinfo; assert(fn->enc != NULL); return fn->enc(buf, val, tag_out, len_out); } case atype_sequence: assert(a->tinfo != NULL); ret = encode_sequence(buf, val, a->tinfo, len_out); if (ret) return ret; tag_out->asn1class = UNIVERSAL; tag_out->construction = CONSTRUCTED; tag_out->tagnum = ASN1_SEQUENCE; break; case atype_ptr: { const struct ptr_info *ptr = a->tinfo; assert(ptr->basetype != NULL); return encode_atype(buf, LOADPTR(val, ptr), ptr->basetype, tag_out, len_out); } case atype_offset: { const struct offset_info *off = a->tinfo; assert(off->basetype != NULL); return encode_atype(buf, (const char *)val + off->dataoff, off->basetype, tag_out, len_out); } case atype_optional: { const struct optional_info *opt = a->tinfo; assert(opt->is_present != NULL); if (opt->is_present(val)) return encode_atype(buf, val, opt->basetype, tag_out, len_out); else return ASN1_OMITTED; } case atype_counted: { const struct counted_info *counted = a->tinfo; const void *dataptr = (const char *)val + counted->dataoff; size_t count; assert(counted->basetype != NULL); ret = load_count(val, counted, &count); if (ret) return ret; return encode_cntype(buf, dataptr, count, counted->basetype, tag_out, len_out); } case atype_nullterm_sequence_of: case atype_nonempty_nullterm_sequence_of: assert(a->tinfo != NULL); ret = encode_nullterm_sequence_of(buf, val, a->tinfo, a->type == atype_nullterm_sequence_of, len_out); if (ret) return ret; tag_out->asn1class = UNIVERSAL; tag_out->construction = CONSTRUCTED; tag_out->tagnum = ASN1_SEQUENCE; break; case atype_tagged_thing: { const struct tagged_info *tag = a->tinfo; ret = encode_atype(buf, val, tag->basetype, tag_out, len_out); if (ret) return ret; if (!tag->implicit) { size_t tlen; ret = make_tag(buf, tag_out, *len_out, &tlen); if (ret) return ret; *len_out += tlen; tag_out->construction = tag->construction; } tag_out->asn1class = tag->tagtype; tag_out->tagnum = tag->tagval; break; } case atype_bool: ret = k5_asn1_encode_bool(buf, load_int(val, a->size), len_out); if (ret) return ret; tag_out->asn1class = UNIVERSAL; tag_out->construction = PRIMITIVE; tag_out->tagnum = ASN1_BOOLEAN; break; case atype_int: ret = k5_asn1_encode_int(buf, load_int(val, a->size), len_out); if (ret) return ret; tag_out->asn1class = UNIVERSAL; tag_out->construction = PRIMITIVE; tag_out->tagnum = ASN1_INTEGER; break; case atype_uint: ret = k5_asn1_encode_uint(buf, load_uint(val, a->size), len_out); if (ret) return ret; tag_out->asn1class = UNIVERSAL; tag_out->construction = PRIMITIVE; tag_out->tagnum = ASN1_INTEGER; break; case atype_int_immediate: { const struct immediate_info *imm = a->tinfo; ret = k5_asn1_encode_int(buf, imm->val, len_out); if (ret) return ret; tag_out->asn1class = UNIVERSAL; tag_out->construction = PRIMITIVE; tag_out->tagnum = ASN1_INTEGER; break; } default: assert(a->type > atype_min); assert(a->type < atype_max); abort(); } return 0; }
static int avr_tbc_decode (const prog_char *data, UWORD length, ECTX context, WORDPTR memory, UWORD memory_size) { UWORD ws_size, vs_size; const prog_char *bytecode; WORDPTR ws, vs; avr_tenc_element_t element; int ret, memory_used; /* Decode the required elements */ if ((ret = load_uint (&data, &length, "ws U", &ws_size)) < 0) return ret; if ((ret = load_uint (&data, &length, "vs U", &vs_size)) < 0) return ret; if ((ret = avr_tenc_walk_to_element (data, &length, "bc B", &element)) < 0) return ret; bytecode = element.data.bytes; data = element.next; /* FIXME: check TLP is empty */ #if 0 /* Decode optional elements */ tbc->tlp = NULL; while (length > 0) { if (tenc_decode_element (data, &length, &element) < 0) return 0; /* ignore errors */ if (ids_match (element.id, "tlpL")) { tbc->tlp = decode_tlp (data, tbc->tlp, &element); } data = element.next; } #endif memory_used = tvm_ectx_layout ( context, memory, "", 0, ws_size, vs_size, &ws, &vs ); #ifdef DEBUG printf ("loaded program with ws_size=%d, vs_size=%d, memory_size=%d, used=%d\n", ws_size, vs_size, memory_size, memory_used); #endif /* Check we haven't exhausted memory. */ if (memory_used > memory_size) { terminate ("not enough RAM for program", NULL); } ret = tvm_ectx_install_tlp ( context, tvm_addr_from_progmem ((prog_void *) bytecode), ws, vs, "", 0, NULL ); return ret; }
/* tbc_decode: * If ptr is NULL then this uses in place decoding, * otherwise fills out the structure pointered to. * When not using in place decoding the structure should be * initialised with zeros. tlp elements will be decoded if * tbc->tlp is not NULL. */ int tbc_decode (BYTE *data, unsigned int length, tbc_t **ptr) { tenc_element_t element; tbc_t *tbc; int in_place; int ret; if (*ptr != NULL) { tbc = *ptr; in_place = 0; } else { tbc = (tbc_t *) data; in_place = 1; } /* Decode the required elements */ if ((ret = load_uint (&data, &length, "endU", &(tbc->endian))) < 0) return ret; if ((ret = load_uint (&data, &length, "ws U", &(tbc->ws))) < 0) return ret; if ((ret = load_uint (&data, &length, "vs U", &(tbc->vs))) < 0) return ret; if ((ret = tenc_walk_to_element (data, &length, "bc B", &element)) < 0) return ret; tbc->bytecode_len = element.length; tbc->bytecode = element.data.bytes; data = element.next; /* Decode optional elements */ if (in_place) { tbc->tlp = NULL; tbc->symbols = NULL; tbc->ffi = NULL; tbc->debug = NULL; } else { if (tbc->tlp != NULL) { tbc->tlp->fmt = NULL; tbc->tlp->symbol = NULL; } } /* Copy pointer */ *ptr = tbc; while (length > 0) { if (tenc_decode_element (data, &length, &element) < 0) return 0; /* ignore errors */ if (ids_match (element.id, "tlpL")) { tbc->tlp = decode_tlp (data, tbc->tlp, &element); } else if (in_place && ids_match (element.id, "ffiL")) { tbc->ffi = decode_ffi (data, &element); } else if (in_place && ids_match (element.id, "stbL")) { tbc->symbols = decode_symbols (&element); } else if (in_place && ids_match (element.id, "dbgL")) { tbc->debug = decode_debug (data, &element); } data = element.next; } return 0; }
static int load_int (BYTE **data, unsigned int *length, const char *id, WORD *dst) { return load_uint (data, length, id, (UWORD *) dst); }