util_machelf.c revision d29b2c4438482eb00488be49a1f5d6835f455546
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <libintl.h>
#include <machdep.h>
#include <libelf.h>
#include <link.h>
#include <strings.h>
#include <ctype.h>
#include "msg.h"
#include <elfedit.h>
#include <conv.h>
#include <sys/elf_SPARC.h>
#include <sys/elf_amd64.h>
/*
* ELFCLASS specific code that would otherwise be found in util.c
*/
/*
* When you modify ELF constructs, you need to tell libelf that you've
* done so. Otherwise, the changes may not be flushed back to the
* output file.
*
* The elfedit_modified_*() functions exist to simplify the calls to
* the underlying elf_flag*() functions.
*/
void
{
}
void
{
}
void
{
}
void
{
}
/*
* Prepare an elfedit_dyn_elt_t structure for use.
*/
void
{
}
/*
* Given a dynamic section item, save it in the given elfedit_dyn_elt_t
* structure and mark that structure to show that it is present.
*/
void
{
}
/*
* Return the index of the first section that has the given name.
*
* entry:
* obj_state - Object state.
* shnam - Name of desired section
*
* exit:
* On success, returns the section index. On failure, an error
* is issued, and this routine does not return to the caller.
*/
{
return (ndx);
}
}
/* If didn't return in loop above, the name doesn't match */
/*NOTREACHED*/
return (SHN_UNDEF);
}
/*
* Return the index of the first section that has the given type.
*
* entry:
* obj_state - Object state.
* shtype - Type of desired section
*
* exit:
* On success, returns the section index. On failure, an error
* is issued, and this routine does not return to the caller.
*/
{
return (ndx);
}
}
/* If didn't return in loop above, the name doesn't match */
/*NOTREACHED*/
return (SHN_UNDEF);
}
/*
* Locate the index of the first symbol that has the given name
*
* entry:
* obj_state - Object state.
* symsec - Symbol section
* strsec = String section
* name - String giving name of symbol to lookup
* msg_type - ELFEDIT_MSG_ type code to use with message
* issued if name does not exist in symbol table.
* ret_symndx - Address of variable to receive index.
*
* exit:
* On success, issues debug message, sets *ret_symndx, and returns
* True (1).
*
* On failure, issues a message using msg_type to determine
* the type of message sent. If the message does not take control away
* from the caller, False (0) is returned.
*
* note:
* Although the string table is referenced by the sh_link field of
* the symbol table, we require the user to supply it rather than
* look it up. The reason for this is that the caller will usually
* have looked it up, and we wish to avoid multiple debug messages
* from being issued to that effect.
*/
int
{
const char *curname;
ELFEDIT_MSG_ERR, 0);
*ret_symndx = ndx;
return (1);
}
}
/* If didn't return in loop above, the name doesn't match */
/*NOTREACHED*/
return (0); /* lint */
}
/*
* Given a section index, turn it into a descriptive string.
* - If it is one of the special reserved indexes, the
* symbolic name is returned.
* - If it is a regular section, in range for the file,
* the name associated with the section is returned.
* - Otherwise, the number is formatted as numeric ASCII.
*
* exit:
* A pointer to the static buffer containing the name is
* returned. This pointer is valid until the next call
* to elfedit_shndx_to_name(), and which point it may
* be overwritten.
*/
const char *
{
/*
* This routine can be called twice within a single C statement,
* so we use alternating buffers on each call to allow this
* without requiring the caller to supply a buffer (the size of
* which they don't know).
*/
static char *buf;
(shndx == SHN_AMD64_LCOMMON))
return (MSG_ORIG(MSG_SHN_AMD64_LCOMMON));
switch (shndx) {
case SHN_UNDEF:
return (MSG_ORIG(MSG_SHN_UNDEF));
case SHN_SUNW_IGNORE:
return (MSG_ORIG(MSG_SHN_SUNW_IGNORE));
case SHN_BEFORE:
return (MSG_ORIG(MSG_SHN_BEFORE));
case SHN_AFTER:
return (MSG_ORIG(MSG_SHN_AFTER));
case SHN_AMD64_LCOMMON:
return (MSG_ORIG(MSG_SHN_AMD64_LCOMMON));
break;
case SHN_ABS:
return (MSG_ORIG(MSG_SHN_ABS));
case SHN_COMMON:
return (MSG_ORIG(MSG_SHN_COMMON));
case SHN_XINDEX:
return (MSG_ORIG(MSG_SHN_XINDEX));
}
/*
* If it is outside of the reserved area, and inside the
* range of section indexes in the ELF file, then show
* the section name.
*/
/* Switch buffers */
/*
* If we haven't identified it by now, format the
* number in a static buffer and return that.
*/
return (buf);
}
/*
* Locate the capabilities section for this object
*
* entry:
* obj_state - Object state for open object to query.
* cap - Address of variable to recieve pointer to capabilities
* section data buffer.
* num - Address of variable to receive number of items
* referenced by cap.
*
* exit:
* On success, returns section descriptor, and sets the
* variables referenced by cap and num. On failure,
* does not return.
*/
{
return (cache);
}
}
/* If here, this object has no capabilities section */
/*NOTREACHED*/
return (NULL);
}
/*
* Locate the dynamic section for this object
*
* entry:
* obj_state - Object state for open object to query.
* dyn - Address of variable to recieve pointer to dynamic
* section data buffer.
* numdyn - Address of variable to receive number of items
* referenced by dyn.
*
* exit:
* On success, returns section descriptor, and sets the
* variables referenced by dyn and numdyn. On failure,
* does not return.
*/
{
return (cache);
}
/* If here, this object has no dynamic section */
/*NOTREACHED*/
return (NULL);
}
/*
* Locate the syminfo section for this object
*
* entry:
* obj_state - Object state for open object to query.
* syminfo - Address of variable to recieve pointer to syminfo
* section data buffer.
* num - Address of variable to receive number of items
* referenced by syminfo.
*
* exit:
* On success, returns section descriptor, and sets the
* variables referenced by syminfo and num. On failure,
* does not return.
*/
{
return (cache);
}
}
/* If here, this object has no syminfo section */
/*NOTREACHED*/
return (NULL);
}
/*
* Check the given section to see if it is a known symbol table type.
*
* entry:
* sec - Section to check
* issue_err - True if this routine should issue an error and
* not return to the caller if sec is not a symbol table.
* atoui_list - NULL, or address of variable to receive a pointer to
* an array of elfedit_atoui_sym_t items describing the
* type of symbol table found. This array is useful for
* doing command completion.
*
* exit:
* If sec is a symbol table:
* - If atoui_list is non-NULL, *atoui_list is set to the
* appropriate ELFEDIT_CONST_xx list of items.
* - True (1) is returned
* If sec is not a symbol table and issue_err is True:
* - An error is issued, and this routine does not
* return to the caller.
* Otherwise:
* - If atoui_list is non-NULL, *atoui_list is set to NULL.
* - False (0) is returned
*/
int
{
int ret = 1;
/* Is the section a symbol table? */
case SHT_SYMTAB:
break;
case SHT_DYNSYM:
break;
case SHT_SUNW_LDYNSYM:
break;
default:
if (issue_err)
ret = 0;
break;
}
if (atoui_list != NULL)
return (ret);
}
/*
* Locate a symbol table section for this object
*
* entry:
* obj_state - Object state for open object to query.
* by_index - If True, we want to locate the section with the
* section index given by index. If False, we return
* the section with the name given by name.
* index, name - Key to search for. See by_index.
* sym - Address of variable to recieve pointer to symbol
* section data buffer.
* numsym - Address of variable to receive number of symbols
* referenced by sym.
* aux_info - Address of variable to receive pointer to the
* elfedit_symtab_t struct that ties the symbol table and
* its related auxiliary sections together. NULL if this
* information is not required.
*
* exit:
* On success, returns section descriptor, and sets the
* variables referenced by sym, and numsym. On failure,
* does not return.
*/
{
const char *type_name;
/* If looking it up by index, make sure the index is in range */
/*
* Look at each known symbol table in turn until the desired
* one is hit, or there are no more.
*/
elfedit_section_t *s =
symsec = s;
break;
}
}
/* Did we get a section? */
/* Got it. Report to the user and return the necessary data */
return (symsec);
}
/*
* Locate the extended symbol index section associated with a symbol
* table section.
*
* entry:
* obj_state - Object state for open object to query.
* symsec - Symbol table section for which extended index
* index section is required.
* xshndx - Address of variable to recieve pointer to section index
* array data buffer.
* numxshndx - Address of variable to receive number of indices
* referenced by ndx.
*
* exit:
* On success, returns extended index section descriptor, and sets the
* variables referenced by xshndx, and numxshndx. On failure,
* does not return.
*
* note:
* Since the extended section index is found in the sec_xshndx field
* of the elfedit_section_t, the caller may be tempted to bypass this
* routine and access it directly. That temptation should be resisted,
* as this routine performs useful error checking, and also handles
* the issuing of the standard MSG_DEBUG messages.
*/
{
/* Sanity check: symsec must be a symbol table */
break;
/*
* Issue error if the symbol table lacks an extended index section.
* The caller won't ask unless they encounter an SHN_XINDEX value,
* in which case the lack of the index section denotes a corrupt
* ELF file.
*/
/* Got it. Report to the user and return the necessary data */
return (xshndxsec);
}
/*
* Locate the versym section associated with a symbol table section.
*
* entry:
* obj_state - Object state for open object to query.
* symsec - Symbol table section for which extended index
* index section is required.
* versym - Address of variable to recieve pointer to section index
* array data buffer.
* numversym - Address of variable to receive number of indices
* referenced by ndx.
*
* exit:
* On success, returns versym section descriptor, and sets the
* variables referenced by versym, and numversym. On failure,
* does not return.
*
* note:
* Since the versym section index is found in the sec_versym field
* of the elfedit_section_t, the caller may be tempted to bypass this
* routine and access it directly. That temptation should be resisted,
* as this routine performs useful error checking, and also handles
* the issuing of the standard MSG_DEBUG messages.
*/
{
/* Sanity check: symsec must be a symbol table */
break;
/*
* Issue error if the symbol table lacks a versym section.
* The caller won't ask unless they see a non-null
* aux.symtab.sec_versym, so this should not be a problem.
*/
/* Got it. Report to the user and return the necessary data */
return (versymsec);
}
/*
* Locate the string table specified by shndx for this object.
*
* exit:
* Returns section descriptor on success. On failure, does not return.
*/
{
return (strsec);
}
/*
* Returns the offset of the specified string from within
* the given section.
*
* entry:
* sec - Descriptor for section
* tail_ign - If non-zero, the # of characters at the end of the
* section that should be ignored and not searched.
* str - String we are looking for.
* ret_offset - Address of variable to receive result
*
* exit:
* Returns 1 for success, and 0 for failure. If successful, *ret_offset
* is set to the offset of the found string within the section.
*/
int
{
char *s; /* ptr to strings within table */
const char *tail; /* 1 past final character of table */
/* Size of the section, minus the reserved part (if any) at the end */
/*
* Move through the section character by character looking for
* a match. Moving character by character instead of skipping
* from NULL terminated string to string allows us to use
* the tails longer strings (i.e. we want "bar", and "foobar" exists).
* We look at the first character manually before calling strcmp()
* to lower the cost of this approach.
*/
for (; s <= tail; s++) {
EC_WORD(*ret_offset), s);
return (1);
}
}
/* Didn't find it. Report failure */
return (0);
}
/*
* Locate the DT_SUNW_STRPAD element of the given dynamic section if
* it exists.
*
* entry:
* dynsec - Dynamic section descriptor
* dyn_strpad - Address of variable to receive the results.
* The caller is responsible for calling elfedit_dyn_elt_init()
* on this variable beforehand.
*
* exit:
* The dynamic section is searched, and if a DT_SUNW_STRPAD element
* is found, dyn_strpad is updated via elfedit_dyn_elt_save() to
* reference it.
*
* Returns the final value of dyn_strpad->dn_seen.
*/
int
{
Word i;
/* Go through dynamic section tags and find the STRPAD entry */
for (i = 0; i < numdyn; i++) {
break;
}
}
return (dyn_strpad->dn_seen);
}
/*
* Given references to the dynamic section, its string table,
* and the DT_SUNW_STRPAD entry of the dynamic section, returns
* the offset of the specified string from within the given string table,
* adding it if possible.
*
* entry:
* dynsec - Dynamic section descriptor
* strsec - Descriptor for string table assocated with dynamic section
* dyn_strpad - DT_SUNW_STRPAD element from dynamic section
* str - String we are looking for.
*
* exit:
* On success, the offset of the given string within the string
* table is returned. If the string does not exist within the table,
* but there is a valid DT_SUNW_STRPAD reserved section, then we
* add the string, and update the dynamic section STRPAD element
* to reflect the space we use.
*
* This routine does not return on failure.
*/
{
char *s; /* ptr to strings within table */
/* Does the string already existin the string table? */
return (len);
/*
* The desired string does not already exist. Do we have
* room to add it?
*/
/*
* We will add the string at the first byte of the reserved NULL
* area at the end. The DT_SUNW_STRPAD dynamic element gives us
* the size of that reserved space.
*/
/* Announce the operation */
/*
* Copy the string into the pad area at the end, and
* mark the data area as dirty so libelf will flush our
* changes to the string data.
*/
/* Update the DT_STRPAD dynamic entry */
return (ins_off);
}
/*
* Test to see if a call to elfedit_strtab_insert() will succeed.
*
* entry:
* obj_state - Object state for open object to query.
* strsec - Descriptor for string table
* dynsec - NULL, or descriptor for dynamic section. Providing
* a non-NULL value here will prevent elfedit_strtab_insert()
* from looking it up, and the duplicate debug message that
* would result.
* str - String we are looking for.
*
* exit:
* If the string exists within the string table, or if an attempt
* to insert it will be successful, quietly return. Otherwise, throw
* the error elfedit_strtab_insert() would throw under the
* same circumstances.
*
*/
void
{
int is_dynstr = 0;
/*
* The dynstr is a special case, because we can add strings
* to it under certain circumstances. So, we look for the
* dynamic section, and if it exists, compare its sh_link to
* the string section index. If they match, it is the dynstr,
* and we use elfedit_dynstr_insert() to do the work.
*/
is_dynstr = 1;
}
}
} else {
is_dynstr = 1;
}
if (is_dynstr) {
/* Determine the size of the STRPAD area, if any */
}
/*
* If the string is already in the string table, we
* can't fail.
*/
return;
/*
* It's not in the table, but if this is the dynstr, and
* there is enough room, we will be able to add it.
*/
return;
/* Can't do it. Issue error */
}
/*
* Returns the offset of the specified string from within
* the given string table, adding it if possible.
*
* entry:
* obj_state - Object state for open object to query.
* strsec - Descriptor for string table
* dynsec - NULL, or descriptor for dynamic section. Providing
* a non-NULL value here will prevent elfedit_strtab_insert()
* from looking it up, and the duplicate debug message that
* would result.
* str - String we are looking for.
*
* exit:
* On success, the offset of the given string within the string
* table is returned. If the string does not exist within the table,
* and it is possible to add it, elfedit_strtab_insert() will
* add the string, and then return the offset.
*
* If the string does not exist in the string table, and cannot
* be added, this routine issues an error message and does not
* return to the caller.
*/
{
int is_dynstr = 0;
/*
* The dynstr is a special case, because we can add strings
* to it under certain circumstances. So, we look for the
* dynamic section, and if it exists, compare its sh_link to
* the string section index. If they match, it is the dynstr,
* and we use elfedit_dynstr_insert() to do the work.
*/
is_dynstr = 1;
}
}
} else {
is_dynstr = 1;
}
if (is_dynstr) {
&dyn_strpad, str));
}
/*
* This is not the dynstr, so we are limited to strings that
* already exist within it. Try to find one.
*/
return (len);
/* Can't do it. Issue error */
/*NOTREACHED*/
return (0);
}
/*
* Return the string found at the given offset within the specified
* string table.
*
* entry:
* strsec - Section descriptor for string table section
* offset - Offset of desired string in string table
* msg_type - ELFEDIT_MSG_ type code to use with message
* issued if offset is out of range for the symbol table.
* debug_msg - True if should issue debug message for string found.
*
* exit:
* If the offset is within the section, the string pointer
* is returned. Otherwise an error is issued using msg_type
* to determine the type of message. If this routine retains
* control after the message is issued, a safe string is returned.
*/
const char *
{
const char *str;
/* Make sure it is a string table section */
/* Ensure the offset is in range */
/*
* If the msg_type is a type that returns, give the
* user a safe string to use.
*/
} else {
/* Return the string */
}
if (debug_msg)
return (str);
}
/*
* Given a string table section, and a dynamic section entry
* that supplies a string offset, return the string found at
* the given offset. This routine is a convenience wrapper on
* elfedit_offset_to_str().
*
* exit:
* As per elfedit_offset_to_str().
*/
const char *
{
ELFEDIT_MSG_ERR, 0));
}
/*
* Given a section, fabricate a string for the form:
*
* "[#: name]"
*
* as used at the beginning of debug messages. A pointer to static
* memory is returned, and is good until the next such call.
*/
const char *
{
static char *buf;
}
return (buf);
}