/* * Read attribute set from memory buffer (see header file for more information). */ Pmelf_attribute_set * pmelf_read_attribute_set(const uint8_t *b, unsigned bsize, int needswap, const char *obj_name) { Pmelf_attribute_set *rval = 0; Pmelf_attribute_vendor *pv; Pmelf_Off n,nbeg; int l; uint8_t v; const char *vendor_name; Pmelf_attribute_tbl *patbl; Elf32_Word len,tag,sublen; if ( ! known_vendors ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_read_attribute_set(): no vendors registered\n"); /* No vendors registered; save us the trouble */ return 0; } if ( ! (rval = calloc(sizeof(*rval),1)) ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_read_attribute_set(): no memory\n"); return 0; } if ( ! (rval->obj_name = strdup(obj_name)) ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_read_attribute_set(): no memory (for obj_name)\n"); goto cleanup; } n = 0; while ( n < bsize ) { nbeg = n; if ( FORMAT_VERSION_A != (v = b[n++]) ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_read_attribute_set(): unknown attribute format version %i\n", v); goto cleanup; } if ( pmelf_getword(needswap, b+n, bsize-n, &len, "subsection") ) goto cleanup; n += sizeof(len); if ( nbeg + len + 1 > bsize ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_read_attribute_set(): vendor subsection length > section length\n"); goto cleanup; } for ( l = n; b[l]; ) { if ( ++l >= bsize ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_read_attribute_set(): reading beyond section (getting vendor name)\n"); goto cleanup; } } vendor_name = (const char*)(b + n); n = l+1; if ( (l = pmelf_guleb128(b+n, &tag, bsize - n)) < 0 ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_read_attribute_size() reading beyond subsubsection (getting tag)\n"); goto cleanup; } n += l; if ( pmelf_getword(needswap, b + n, bsize - n, &sublen, "subsubsection") ) goto cleanup; n += sizeof(sublen); /* subsubsection length includes byte count for tag and length itself */ sublen -= sizeof(sublen) + l; switch ( tag ) { case Tag_File: for ( pv = known_vendors; pv && strcmp(pv->name, vendor_name); ) pv = pv->next; if ( !pv ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_read_attribute_set(): no handlers for vendor '%s' found\n", vendor_name); goto cleanup; } for ( patbl=0, l=0; l<ATTR_MAX_VENDORS; l++ ) { if ( ! rval->attributes[l].file_attributes || rval->attributes[l].file_attributes->pv == pv ) { /* setting a covers the case where we use a new empty slot */ patbl = rval->attributes[l].file_attributes; break; } } if ( ! patbl ) { if ( l >= ATTR_MAX_VENDORS ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_read_attribute_set(): not enough vendor slots\n"); goto cleanup; } /* create attribute table */ if ( !(patbl = calloc(sizeof(*patbl) + sizeof(patbl->map[0])*(pv->max_tag+1), 1)) ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_read_attribute_set(): no memory\n"); goto cleanup; } patbl->vals = 0; patbl->avail = 0; patbl->idx = 1; /* first entry is empty/unused */ patbl->pv = pv; patbl->aset = rval; rval->attributes[l].file_attributes = patbl; } /* read attributes into table */ if ( pv->file_attributes_read(patbl, b+n, sublen) ) goto cleanup; break; case Tag_Section: PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_read_attribute_set(): Tag_Section no yet supported\n"); goto cleanup; case Tag_Symbol: PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_read_attribute_set(): Tag_Symbol no yet supported\n"); goto cleanup; default: PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_read_attribute_set(): unsupported tag %"PRIi32"\n", tag); goto cleanup; } n = nbeg + len + 1; } return rval; cleanup: pmelf_destroy_attribute_set(rval); return 0; }
/* * Decode attributes from byte stream in memory (public format; see header for * more detailed description. */ int pmelf_pub_file_attributes_read(Pmelf_attribute_tbl *patbl, const uint8_t *buf, unsigned size) { Elf32_Word tag; int l,n; Pmelf_pub_attribute_t tagt; Elf32_Word ival; const char * sval; Pmelf_attribute_list *el,**pn,**pp; unsigned csz; if ( !size ) return 0; if ( ! patbl ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_pub_file_attributes_read(): no attribute table (internal error)\n"); return -1; } while ( size ) { if ( (n = pmelf_guleb128(buf, &tag, size)) < 0 ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_pub_file_attributes_read() reading beyond subsubsection (getting tag)\n"); goto cleanup; } buf += n; size -= n; if ( patbl->avail == 0 && (tag <= patbl->pv->max_tag && Tag_Compat != tag) ) { csz = CHUNKSZ < patbl->pv->max_tag ? CHUNKSZ : patbl->pv->max_tag; if ( !(patbl->vals = realloc(patbl->vals, sizeof(*patbl->vals)*(patbl->idx + csz))) ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_pub_file_attributes_read(): no memory\n"); goto cleanup; } patbl->avail += csz; } ival = 0; sval = 0; /* FIXME: we cannot have multiple identical tags in the array (but could in the linked list part) */ if ( (tag <= patbl->pv->max_tag && Tag_Compat != tag) && patbl->map[tag] ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_pub_file_attributes_read() tag %"PRIi32" already defined\n", tag); goto cleanup; } if ( Tag_Compat == tag ) { tagt = Pmelf_Attribute_Type_both; } else if ( ! patbl->pv->file_attributes_tag_type ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_pub_file_attributes_read() vendor %s has no type handler!\n", patbl->pv->name ); tagt = Pmelf_Attribute_Type_unknown; } else { tagt = patbl->pv->file_attributes_tag_type(patbl, tag); } switch ( tagt ) { default: PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_pub_file_attributes_read() unknown tag %"PRIi32"\n", tag ); goto cleanup; case Pmelf_Attribute_Type_none: continue; case Pmelf_Attribute_Type_num: case Pmelf_Attribute_Type_both: if ( (n = pmelf_guleb128(buf, &ival, size)) < 0 ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_pub_file_attributes_read() reading beyond subsubsection (getting (i)value)\n"); goto cleanup; } buf += n; size -= n; if ( Pmelf_Attribute_Type_num == tagt ) break; /* else fall thru */ case Pmelf_Attribute_Type_str: for ( l=0; buf[l++]; ) { if ( l >= size ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_pub_file_attributes_read() reading beyond subsubsection (getting (s)value)\n"); goto cleanup; } } sval = (const char*)buf; buf += l; size -= l; break; } /* Tag_Compat always go to the list */ if ( tag > patbl->pv->max_tag || Tag_Compat == tag ) { if ( ! (el = calloc( sizeof(*el), 1 ) ) ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_pub_file_attributes_read() no memory for attribute list element\n"); goto cleanup; } /* append to possibly existing instances of 'tag' */ for ( pp = &patbl->lst; *pp; pp = &(*pp)->next ) { if ( (*pp)->att.tag == tag ) { for ( pn = &(*pp)->next; *pn && (*pn)->att.tag == tag; pp = pn) ; break; } } el->next = *pp; *pp = el; el->att.tag = tag; el->att.val.pub.i = ival; el->att.val.pub.s = sval; } else { patbl->map[tag] = patbl->idx; patbl->vals[patbl->idx].pub.i = ival; patbl->vals[patbl->idx].pub.s = sval; patbl->idx++; } } return 0; cleanup: return -1; }