/*
* 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 <libelf.h>
#include <link.h>
#include <strings.h>
#include <ctype.h>
#include <elfedit.h>
#include <_elfedit.h>
#include <sys/elf_SPARC.h>
#include <sys/elf_amd64.h>
#include <msg.h>
/*
* This file contains utility functions that are of general use
* to different elfedit modules for solving common problems.
* The functions in this file are not ELFCLASS specific. Those
* functions are found in util_machelf.c
*
* NOTE: This module contains functions with names
* elfedit_atoi, and elfedit_atoui, that are otherwise identical.
* These functions are for signed, and unsigned integers, respectively.
* In general, I supply one comment header for each such pair,
* and put their implementations together.
*
* There are also functions with names elfedit_atoconst. These are
* convenience wrappers that use the corresponding elfedit_atoui()
* function to process an array of symbolic names provided by a call
* elfedit_const_to_atoui().
*/
/*
* Given a value and an array of elfedit_ato[u]i items, return a pointer
* to the symbolic name for the value.
*
* entry:
* sym - NULL terminated array of name->value mappings.
* value - Value to be found
* required - If True, and value is not found, an error is issued.
* Callers should only set required to True when they know
* a priori that the value will be found --- the error
* is reported as an internal programming error.
*
* exit:
* If the array contains an entry with the given value, the
* name for the first such entry will be returned.
*
* If no entry is found: If required is True (1), an error is
* issued and this routine does not return to the caller. If required
* is False (0), then NULL is returned.
*/
const char *
int required)
{
/* Value did not match any of the entries */
if (required)
return (NULL);
}
const char *
{
/* Value did not match any of the entries */
if (required)
return (NULL);
}
const char *
int required)
{
}
/*
* Process the symbolic name to value mappings passed to the
* atoi and atoui functions.
*
* entry:
* sym - NULL terminated array of name->value mappings.
* value - Address of variable to recieve corresponding value.
*
* exit:
* If a mapping is found, *value is set to it, and True is returned.
* Otherwise False is returned.
*/
static int
{
const char *tail;
str++;
tail--;
return (1);
}
}
/* No symbolic mapping was found */
return (0);
}
static int
{
const char *tail;
str++;
tail--;
return (1);
}
}
/* No symbolic mapping was found */
return (0);
}
/*
* A command completion function for atoi and atoui mappings.
*/
void
{
}
void
{
}
void
{
}
/*
* Convert a string to a numeric value. Strings starting with '0'
* are taken to be octal, those staring with '0x' are hex, and all
* others are decimal.
*
* entry:
* str - String to be converted
*
* [elfedit_atoi2() and elfedit_atoui2() only]
* v - Address of variable to receive resulting value.
*
* exit:
* elfedit_atoi2() and elfedit_atoui2():
* On success, returns True (1) and *v is set to the value.
* On failure, returns False (0) and *v is undefined.
*
* elfedit_atoi() and elfedit_atoui():
* If the string is convertable, the value is returned.
* Otherwise an error is issued and this routine does
* not return to the caller.
*/
int
{
char *endptr;
return (1);
/* If the left over part contains anything but whitespace, fail */
return (0);
return (1);
}
{
return (v);
}
int
elfedit_atoui_t *v)
{
char *endptr;
return (1);
/* If the left over part contains anything but whitespace, fail */
return (0);
return (1);
}
{
return (v);
}
int
elfedit_atoui_t *v)
{
}
{
}
/*
* Convert a string to a numeric value using elfedit_ato[u]i and
* ensure that the resulting value lies within a given range.
* elfedit_ato[u]i_range() requires values to be in the range
* (min <= value <= max).
*
* entry:
* str - String to be converted
* min, max - If check_range is true, the allowed range that the
* resulting value must lie in.
*
* entry [elfedit_atoi_range() and elfedit_atoui_range() only]:
* item_name - String describing item for which value is being read.
*
* entry [elfedit_atoi_range2() and elfedit_atoui_range2() only]:
* v - Address of variable to receive resulting value.
*
* exit:
* elfedit_atoi_range2() and elfedit_atoui_range2():
* On success, returns True (1) and *v is set to the value.
* On failure, returns False (0) and *v is undefined.
*
* elfedit_atoi_range() and elfedit_atoui_range():
* If the string is convertable, the value is returned.
* Otherwise an error is issued and this routine does
* not return to the caller.
*/
int
{
}
{
return (v);
}
int
{
}
{
return (v);
}
int
{
elfedit_const_to_atoui(const_type), v));
}
{
}
/*
* Convenience wrapper on elfedit_atoui_range() that expects to see
* boolean values. Returns 1 for true, and 0 for false.
*/
int
{
ELFEDIT_CONST_BOOL) != 0);
}
/*
* Convenience wrapper on elfedit_atoui() to read a section index
* that understands the special SHN_ names.
*
* entry:
* str - String to process
* shnum - Number of sections in the ELF file
*
* exit:
* If it is possible to convert str to a number, that value
* is returned. If the value is out of range for the file,
* a warning message to that effect is issued. On failure,
* an error is issued and this routine does not return to
* the caller.
*/
{
return (ndx);
}
/*
* Convert an output style string into it's integer constant. This
* by throwing errors so that it can be used to process command
* line options at program startup, before
* the elfedit framework is initialized.
*/
int
{
int ret;
if (ret != 0)
return (ret);
}
/*
* Initialize a state block for processing by elfedit_getopt().
*
* entry:
* state - State block to initialize
* cmd_name - NULL, or name of command for which we are processing
* options.
* argc, argv - Address of variables giving number of options and
* access to the option strings.
*
* note:
* cmd_name can only be set to NULL when this routine is called
* by, or below, a currently active command. Otherwise, results
* are undefined (crashing or corruption) if there isn't one.
*/
void
{
}
/*
* elfedit-centric version of getopt()
*
* entry:
* state - Getopt state, which must have been previously initialized
* via a call to elfedit_getopt_init.
*
* exit:
* If an option is matched, this routine returns a pointer to an
* elfedit_getopt_ret_t buffer (which comes from the storage used
* for state). If there are no more options to process, NULL is returned.
*
* Syntax errors are reported via elfedit_command_usage(), and this
* routine does not return to the caller.
*
* note:
* - The caller should not access the contents of state directly.
* Those contents are private, and subject to change.
* have been ajusted so that they reference the plain arguments.
*/
{
const char *argstr;
struct {
int valid;
int is_outstyle;
/*
* Reasons to bail out immediately:
* - The command does not accept options
* - We've already reported the final option.
* - There are no more arguments.
* - The next argument does not start with '-'
*/
return (NULL);
}
/* A '-' by itself is a syntax error */
/* A '--' option means we should stop at this point */
return (NULL);
}
/*
* We have a string that starts with a '-'.
* Does it match an option?
*/
sgl_with_value.valid = 0;
int is_outstyle =
int need_value;
/*
* If the option is a single letter that accepts
* a value, then we allow the combined syntax
* -ovalue, where no space is reqired between the
* option flag and the value string.
*/
/*
* We have a match. However, there may also
* be a straightforward match that we have
* not yet found. If so, we want to prefer that
* case over this one. So rather than return
* it immediately, we capture the information
* and keep looking. If nothing else surfaces,
* we'll use this later.
*/
continue;
}
/* Try for a straightforward match */
/* Mutually exclusive option already seen? */
/* Return the match */
if (need_value) {
/* If out of args, syntax error */
if (argc <= 0)
} else {
}
if (is_outstyle)
}
}
/*
* No straightforward matches: Did we get a match with
* the special single letter and combined value? If so
* return that now.
*/
if (sgl_with_value.valid) {
/* Mutually exclusive option already seen? */
}
/*
* If nothing above matched, make this option the single
* group string and see if the characters in it all match
* as single letter options without values.
*/
}
/*
* If there is a single group string, take the first character
* and try to match it to an 1-letter option that does not
* require a value.
*/
/* If that is the last character, clear single group mode */
}
/*
* It matches. If the option requires a value
* then it cannot be in a group.
*/
/* Mutually exclusive option already seen? */
/* Return the match */
}
}
}
/* Nothing matched. We have a syntax error */
/*NOTREACHED*/
return (NULL);
}
/*
* Return the count of non-zero bits in the value v.
*
* entry:
* v - Value to test
* sizeof_orig_v - The result of using the sizeof operator
* on the original value of v. The value received
* by this routine has been cast to an unsigned 64-bit
* integer, so having the caller use sizeof allows us to
* avoid testing bits that were not in the original.
*/
int
{
int mask;
int cnt = 0;
if (v & mask)
cnt++;
return (cnt);
}
/*
* "delete" items in an array by copying the following items up
* over the "deleted" items and then zero filling the vacated
* slots at the bottom.
*
* entry:
* name_str - Array identification prefix to use for debug message
* data_start - Address of 1st byte in array
* entsize - sizeof a single element of the array
* num_ent - # of elements in array
* start_ndx - Index of first item to be deleted
* cnt - # of items to delete
*
* exit:
* Any errors are issued and control does not return to the
* caller. On success, the items have been removed, zero filling
* has been done, and debug messages issued.
*/
void
{
/* The specified index and range must be in bounds */
/*
* Everything below the deleted items moves up.
* Note that bcopy() is documented to handle overlapping
* element by element, but issue a single operation.
*
* If we're doing the last element, there is nothing to
* move up, and we skip this step, moving on to the zeroing below.
*/
if (ncpy == 1) {
} else {
}
}
/* Zero out the vacated elements at the end */
if (cnt == 1) {
} else {
}
}
/*
* move the location of items in an array by shifting the surround
* items into the vacated hole and them putting the values into
* the new location.
*
* entry:
* name_str - Array identification prefix to use for debug message
* data_start - Address of 1st byte in array
* entsize - sizeof a single element of the array
* num_ent - # of elements in array
* start_ndx - Index of first item to be moved
* dst_ndx - Index to receive the moved block
* cnt - # of items to move
* scr_item - Space allocated by the caller sufficient to hold
* one item from the array. Used to swap elements.
*
* exit:
* Any errors are issued and control does not return to the
* caller. On success, the items have been moved, and debug
* messages issued.
*/
void
{
/* The specified source and destination ranges must be in bounds */
/* If source and destination are same, there's nothing to do */
return;
/*
* It is meaningless to do a move where the source and destination
* are overlapping, because this "move" amounts to shifting
* the existing items around into a new position. If there is
* more than one element, then overlap is possible and we need
* to test for it.
*/
if (cnt > 1) {
} else {
}
/* Ensure that the src and dst don't overlap */
}
if (cnt == 1)
else
/*
* Copy item at srcndx to scratch location
*
* save = dyn[srcndx];
*/
/*
* Shift items after source up through destination
* to source. bcopy() handles overlapped copies.
*
* for (i = srcndx; i < dstndx; i++)
* dyn[i] = dyn[i + 1];
*/
/*
* Copy saved item into destination slot
*
* dyn[dstndx] = save;
*/
}
} else {
/*
* Copy item at srcndx to scratch location
*
* save = dyn[srcndx];
*/
/*
* Shift items from destination through item below
* source up one. bcopy() handles overlapped copies.
*
* for (i = srcndx; i > dstndx; i--)
* dyn[i] = dyn[i - 1];
*/
/*
* Copy saved item into destination slot
*
* dyn[dstndx] = save;
*/
}
}
}