Beispiel #1
0
int
pmelf_getsym32(Elf_Stream s, Elf32_Sym *psym)
{
	if ( 1 != SREAD(psym, sizeof(*psym), 1, s) ) {
		return -1;
	}
	if ( s->needswap ) {
#ifdef PMELF_CONFIG_NO_SWAPSUPPORT
		return -2;
#else
		elf_swap32( &psym->st_name);
		elf_swap32( &psym->st_value);
		elf_swap32( &psym->st_size);
		elf_swap16( &psym->st_shndx);
#endif
	}
#ifdef PARANOIA_ON
	{
	int x;
	if ( (x = ELF32_ST_TYPE( psym->st_info )) > STT_MAXSUP ) {
		PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_getsym - paranoia: unsupported type %i\n", x);
		return -1;
	}
	if ( (x = ELF32_ST_BIND( psym->st_info )) > STB_MAXSUP ) {
		PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_getsym - paranoia: unsupported binding %i\n", x);
		return -1;
	}
	}
#endif
	return 0;
}
Beispiel #2
0
int
pmelf_putehdr32(Elf_Stream s, Elf32_Ehdr *pehdr)
{
uint8_t magic[4] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3 };
#ifndef PMELF_CONFIG_NO_SWAPSUPPORT
Elf32_Ehdr nehdr;
#endif

	if ( memcmp(magic, pehdr->e_ident+EI_MAG0, sizeof(magic)) ) {
		PMELF_PRINTF(pmelf_err, PMELF_PRE"error: not an ELF file\n");
		return -1;
	}
	if ( pehdr->e_ident[EI_CLASS] != ELFCLASS32 ) {
		PMELF_PRINTF(pmelf_err, PMELF_PRE"error: not an 32-bit ELF file\n");
		return -1;
	}

	if ( pehdr->e_ident[EI_VERSION] != EV_CURRENT ) {
		PMELF_PRINTF(pmelf_err, PMELF_PRE"error: not a version %i ELF file\n", EV_CURRENT);
		return -1;
	}

	s->needswap = iamlsb() ^ (pehdr->e_ident[EI_DATA] == ELFDATA2LSB ? 1 : 0);

#ifdef PMELF_CONFIG_NO_SWAPSUPPORT
	if ( s->needswap ) {
		PMELF_PRINTF(pmelf_err, PMELF_PRE"error: host/target byte order mismatch but pmelf was configured w/o support for byte-swapping\n");
		return -2;
	}
#else
	if ( s->needswap ) {
		nehdr = *pehdr;
		pehdr = &nehdr;
		elf_swap16( &pehdr->e_type      );
		elf_swap16( &pehdr->e_machine   );
		elf_swap32( &pehdr->e_version   );
		elf_swap32( &pehdr->e_entry     );
		elf_swap32( &pehdr->e_phoff     );
		elf_swap32( &pehdr->e_shoff     );
		elf_swap32( &pehdr->e_flags     );
		elf_swap16( &pehdr->e_ehsize    );
		elf_swap16( &pehdr->e_phentsize );
		elf_swap16( &pehdr->e_phnum     );
		elf_swap16( &pehdr->e_shentsize );
		elf_swap16( &pehdr->e_shnum     );
		elf_swap16( &pehdr->e_shstrndx  );
	}
#endif

	return s->write && 1 == SWRITE(pehdr, sizeof(*pehdr), 1, s) ? 0 : -1;
}
Beispiel #3
0
/*
 * Scan attribute sets 'pa' and 'pb' for common vendors and
 * call their file_attributes_match() methods to find incompatibilities.
 *
 * If the vendor sets in 'pa' and 'pb' do not match or if only one set
 * exists (the other being NULL) this is treated as a mismatch.
 *
 * RETURNS: zero if no incompatibility is found, a value < 0 otherwise.
 *
 * NOTE:    it is legal to pass 'pa==NULL', 'pb==NULL' in which case
 *          the routine returns 0 (SUCCESS).
 */
int
pmelf_match_attribute_set(Pmelf_attribute_set *pa, Pmelf_attribute_set *pb)
{
int                    i,j;
Pmelf_attribute_vendor *pv;
int                    vendor_set_a, vendor_set_b;
int                    rval = 0;

	if ( !pa && !pb )
		return 0;

	if ( ! (pa && pb) )
		return -1;

	if ( (vendor_set_a = vset(pa)) < 0 ) {
		return -1;
	}
	if ( (vendor_set_b = vset(pb)) < 0 ) {
		return -1;
	}

	if ( vendor_set_a != vendor_set_b ) {
		PMELF_PRINTF(pmelf_err, PMELF_PRE"pmelf_match_attribute_set(): vendor set mismatch (objects %s, %s)\n", pa->obj_name, pb->obj_name);
		return -2;
	}

	for ( i=0; i<ATTR_MAX_VENDORS; i++ ) {
		if ( pa->attributes[i].file_attributes ) {
			pv = pa->attributes[i].file_attributes->pv;
			for ( j=0; j<ATTR_MAX_VENDORS; j++ ) {
				if ( pb->attributes[j].file_attributes ) {
					if ( pv == pb->attributes[j].file_attributes->pv ) {
						if ( ! pv->file_attributes_match ) {
							PMELF_PRINTF(pmelf_err, PMELF_PRE"pmelf_match_attribute_set(): vendor %s has no 'match' handler\n", pv->name);
							return -1;
						}
						rval |= pv->file_attributes_match( pa->attributes[i].file_attributes, pb->attributes[j].file_attributes );
					}
				}
			}
		}
	}
	return rval;
}
Beispiel #4
0
/*
 * Read attribute set from ELF stream (see header file for more information).
 */
Pmelf_attribute_set *
pmelf_create_attribute_set(Elf_Stream s, Elf_Shdr *psect)
{
Pmelf_attribute_set    *rval = 0;
uint8_t                *b    = 0;
Pmelf_Off              sh_size;

	/* Hack; accessing sh_type as ELF32 should work for both, ELF32 and ELF64 */
	if ( psect->s32.sh_type != SHT_GNU_ATTRIBUTES ) {
		PMELF_PRINTF(pmelf_err, PMELF_PRE"pmelf_create_attribute_set(): not a .gnu_attributes section\n");
		return 0;
	}

	if ( ! (b = pmelf_getscn(s, psect, 0, 0, 0)) )
		goto cleanup;

	switch ( s->clss ) {
#ifdef PMELF_CONFIG_ELF64SUPPORT
		case ELFCLASS64:
			sh_size   = psect->s64.sh_size;
		break;
#endif
		case ELFCLASS32:
			sh_size   = psect->s32.sh_size;
		break;

		default:
			PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_create_attribute_set(): unsupported ELF class (64?)\n");
			goto cleanup;
	}

	rval = pmelf_read_attribute_set(b, sh_size, s->needswap, s->name);

	if ( !rval ) 
		goto cleanup;

	rval->scn_data = b;
	b              = 0;

cleanup:
	free( b );
	return rval;
}
Beispiel #5
0
/* 
 * Compute bitmask of all vendors present in an attribute set 'pa'
 *
 * E.g., if 'pa' contains attributes associated with vendors "gnu"
 *       and "foo" and the vendors "gnu", "boo" and "foo" are
 *       registered/known then 'vset(pa)' returns 0x5 since it
 *       contains vendors #0 ("gnu") and #2 ("foo").
 */
static int
vset(Pmelf_attribute_set *pa)
{
int i,j;

unsigned rval = 0;

	for ( i=0; i<ATTR_MAX_VENDORS; i++ ) {
		if ( pa->attributes[i].file_attributes ) {
			j = vidx(pa->attributes[i].file_attributes->pv);
			if ( j < 0 ) {
				PMELF_PRINTF(pmelf_err, PMELF_PRE"pmelf_match_attribute_set(): invalid vendor index ?? (object %s)\n", pa->obj_name);
				return -1;
			}
			rval |= (1<<j);
		}
	}
	return rval;
}
Beispiel #6
0
/*
 * 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;
}
Beispiel #7
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;
}
Beispiel #8
0
static Pmelf_Long
_pmelf_find_symhdrs(Elf_Stream s, Pmelf_Shtab shtab, Elf_Shdr **psymsh, Elf_Shdr **pstrsh, int dynamic)
{
Elf_Shdr   *shdr;
uint32_t   i;
Elf_Shdr   *symsh  = 0;
Elf_Shdr   *strsh  = 0;
const char *name;
uint8_t    *p;
uint32_t   shdrsz = get_shdrsz(shtab);
uint32_t   symsz;
Pmelf_Size sh_size, sh_entsize;
Pmelf_Off  sh_offset;
uint32_t   type, destype;
const char *desname;
#ifndef USE_SYM_SH_LINK
const char *desstrn;
#endif

	if ( dynamic ) {
		destype = SHT_DYNSYM;
		desname = ".dynsym";
#ifndef USE_SYM_SH_LINK
		desstrn = ".dynstr";
#endif
	} else {
		destype = SHT_SYMTAB;
		desname = ".symtab";
#ifndef USE_SYM_SH_LINK
		desstrn = ".strtab";
#endif
	}
	destype = dynamic ? SHT_DYNSYM : SHT_SYMTAB;

	for ( i = 0, p = shtab->shdrs.p_raw; i<shtab->nshdrs; i++, p+=shdrsz ) {
		shdr = (Elf_Shdr*)p;

		type = get_sh_type(shtab->clss, shdr);

		if ( type == destype ) {
			if ( ! (name = pmelf_sec_name(shtab, shdr)) ) {
				PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_find_symhdrs: symtab section name out of bounds\n");
				return -1;
			}
			if ( !strcmp(desname, name) ) {
				if ( symsh ) {
					PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_find_symhdrs: multiple symtabs\n");
					return -1;
				}
				symsh = shdr;
#ifdef USE_SYM_SH_LINK
				strsh = get_shtabN(shtab,get_sh_link(shtab->clss, symsh));
#endif
			}
		}
#ifndef USE_SYM_SH_LINK
		else if ( SHT_STRTAB == type ) {
				if ( ! (name = pmelf_sec_name(shtab, shdr)) ) {
					PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_find_symhdrs: strtab section name out of bounds\n");
					return -1;
				}
				if ( !strcmp(desstrn, name) ) {
					if ( strsh ) {
						PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_find_symhdrs: multiple strtabs\n");
						return -1;
					}
					strsh = shdr;
				}
		}
#endif
	}

	if ( !symsh ) {
#if 0
		/* let the caller barf it they think it is appropriate */
		PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_find_symhdrs: no symtab found\n");
#endif
		return -1;
	}

#ifdef PMELF_CONFIG_ELF64SUPPORT
	if ( ELFCLASS64 == shtab->clss ) {
		sh_size    = symsh->s64.sh_size;
		sh_entsize = symsh->s64.sh_entsize;
		sh_offset  = symsh->s64.sh_offset;
		symsz      = sizeof(Elf64_Sym);
	}
	else
#endif
	{
		sh_size    = symsh->s32.sh_size;
		sh_entsize = symsh->s32.sh_entsize;
		sh_offset  = symsh->s32.sh_offset;
		symsz      = sizeof(Elf32_Sym);
	}


	if ( !strsh ) {
		PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_find_symhdrs: no strtab found\n");
		return -1;
	}

	if ( 0 == sh_size ) {
		PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_find_symhdrs: zero size symtab\n");
		return -1;
	}

	if ( sh_entsize && sh_entsize != symsz ) {
		PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_find_symhdrs: symbol size mismatch (sh_entsize %lu\n", (unsigned long)sh_entsize);
		return -1;
	}

	if ( (sh_size % symsz) != 0 ) {
		PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_find_symhdrs: sh_size of symtab not a multiple of sizeof(Elf32_Sym)\n");
		return -1;
	}

	if ( pmelf_seek(s, sh_offset) ) {
		PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_find_symhdrs unable to seek to symtab %s\n", strerror(errno));
		return -1;
	}

	if ( psymsh )
		*psymsh = symsh;
	if ( pstrsh )
		*pstrsh = strsh;

	return sh_size/symsz;
}