/*
* 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
* or http://www.opensolaris.org/os/licensing.
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <msg.h>
#include <_elfdump.h>
#include <struct_layout.h>
#include <conv.h>
/*
* Functions for extracting and formatting numeric values from
* structure data.
*/
/*
* Extract the integral field into the value union given and
* perform any necessary byte swapping to make the result readable
* on the elfdump host.
*/
void
sl_extract_num_field(const char *data, int do_swap, const sl_field_t *fdesc,
sl_data_t *field_data)
{
/* Copy the value bytes into our union */
(void) memcpy(field_data, data + fdesc->slf_offset,
fdesc->slf_eltlen);
/* Do byte swapping as necessary */
if (do_swap) {
switch (fdesc->slf_eltlen) {
case 2:
field_data->sld_ui16 = BSWAP_HALF(field_data->sld_ui16);
break;
case 4:
field_data->sld_ui32 = BSWAP_WORD(field_data->sld_ui32);
break;
case 8:
field_data->sld_ui64 =
BSWAP_LWORD(field_data->sld_ui64);
break;
}
}
}
/*
* Extract the given integer field, and return its value, cast
* to Word. Note that this operation must not be used on values
* that can be negative, or larger than 32-bits, as information
* can be lost.
*/
Word
sl_extract_as_word(const char *data, int do_swap, const sl_field_t *fdesc)
{
sl_data_t v;
/* Extract the value from the raw data */
sl_extract_num_field(data, do_swap, fdesc, &v);
if (fdesc->slf_sign) {
switch (fdesc->slf_eltlen) {
case 1:
return ((Word) v.sld_i8);
case 2:
return ((Word) v.sld_i16);
case 4:
return ((Word) v.sld_i32);
case 8:
return ((Word) v.sld_i64);
}
} else {
switch (fdesc->slf_eltlen) {
case 1:
return ((Word) v.sld_ui8);
case 2:
return ((Word) v.sld_ui16);
case 4:
return ((Word) v.sld_ui32);
case 8:
return ((Word) v.sld_ui64);
}
}
/* This should not be reached */
assert(0);
return (0);
}
/*
* Extract the given integer field, and return its value, cast
* to Lword. Note that this operation must not be used on values
* that can be negative, as information can be lost.
*/
Lword
sl_extract_as_lword(const char *data, int do_swap, const sl_field_t *fdesc)
{
sl_data_t v;
/* Extract the value from the raw data */
sl_extract_num_field(data, do_swap, fdesc, &v);
if (fdesc->slf_sign) {
switch (fdesc->slf_eltlen) {
case 1:
return ((Lword) v.sld_i8);
case 2:
return ((Lword) v.sld_i16);
case 4:
return ((Lword) v.sld_i32);
case 8:
return ((Lword) v.sld_i64);
}
} else {
switch (fdesc->slf_eltlen) {
case 1:
return ((Lword) v.sld_ui8);
case 2:
return ((Lword) v.sld_ui16);
case 4:
return ((Lword) v.sld_ui32);
case 8:
return ((Lword) v.sld_ui64);
}
}
/* This should not be reached */
assert(0);
return (0);
}
/*
* Extract the given integer field, and return its value, cast
* to int32_t. Note that this operation must not be used on unsigned
* values larger than 31-bits, or on signed values larger than 32-bits,
* as information can be lost.
*/
Sword
sl_extract_as_sword(const char *data, int do_swap, const sl_field_t *fdesc)
{
sl_data_t v;
/* Extract the value from the raw data */
sl_extract_num_field(data, do_swap, fdesc, &v);
if (fdesc->slf_sign) {
switch (fdesc->slf_eltlen) {
case 1:
return ((Sword)v.sld_i8);
case 2:
return ((Sword)v.sld_i16);
case 4:
return ((Sword)v.sld_i32);
case 8:
return ((Sword)v.sld_i64);
}
} else {
switch (fdesc->slf_eltlen) {
case 1:
return ((Sword)v.sld_ui8);
case 2:
return ((Sword)v.sld_ui16);
case 4:
return ((Sword)v.sld_ui32);
case 8:
return ((Sword)v.sld_ui64);
}
}
/* This should not be reached */
assert(0);
return (0);
}
/*
* Extract the integral field and format it into the supplied buffer.
*/
const char *
sl_fmt_num(const char *data, int do_swap, const sl_field_t *fdesc,
sl_fmt_num_t fmt_type, sl_fmtbuf_t buf)
{
/*
* These static arrays are indexed by [fdesc->slf_sign][fmt_type]
* to get a format string to use for the specified combination.
*/
static const char *fmt_i8[2][3] = {
{
MSG_ORIG(MSG_CNOTE_FMT_U),
MSG_ORIG(MSG_CNOTE_FMT_X),
MSG_ORIG(MSG_CNOTE_FMT_Z2X)
},
{
MSG_ORIG(MSG_CNOTE_FMT_D),
MSG_ORIG(MSG_CNOTE_FMT_X),
MSG_ORIG(MSG_CNOTE_FMT_Z2X)
}
};
static const char *fmt_i16[2][3] = {
{
MSG_ORIG(MSG_CNOTE_FMT_U),
MSG_ORIG(MSG_CNOTE_FMT_X),
MSG_ORIG(MSG_CNOTE_FMT_Z4X)
},
{
MSG_ORIG(MSG_CNOTE_FMT_D),
MSG_ORIG(MSG_CNOTE_FMT_X),
MSG_ORIG(MSG_CNOTE_FMT_Z4X)
}
};
static const char *fmt_i32[2][3] = {
{
MSG_ORIG(MSG_CNOTE_FMT_U),
MSG_ORIG(MSG_CNOTE_FMT_X),
MSG_ORIG(MSG_CNOTE_FMT_Z8X)
},
{
MSG_ORIG(MSG_CNOTE_FMT_D),
MSG_ORIG(MSG_CNOTE_FMT_X),
MSG_ORIG(MSG_CNOTE_FMT_Z8X)
}
};
static const char *fmt_i64[2][3] = {
{
MSG_ORIG(MSG_CNOTE_FMT_LLU),
MSG_ORIG(MSG_CNOTE_FMT_LLX),
MSG_ORIG(MSG_CNOTE_FMT_Z16LLX)
},
{
MSG_ORIG(MSG_CNOTE_FMT_LLD),
MSG_ORIG(MSG_CNOTE_FMT_LLX),
MSG_ORIG(MSG_CNOTE_FMT_Z16LLX)
}
};
sl_data_t v;
/* Extract the value from the raw data */
sl_extract_num_field(data, do_swap, fdesc, &v);
/*
* Format into the buffer. Note that we depend on the signed
* and unsigned versions of each width being equivalent as long
* as the format specifies the proper formatting.
*/
switch (fdesc->slf_eltlen) {
case 1:
(void) snprintf(buf, sizeof (sl_fmtbuf_t),
fmt_i8[fdesc->slf_sign][fmt_type], (uint32_t)v.sld_ui8);
break;
case 2:
(void) snprintf(buf, sizeof (sl_fmtbuf_t),
fmt_i16[fdesc->slf_sign][fmt_type], (uint32_t)v.sld_ui16);
break;
case 4:
(void) snprintf(buf, sizeof (sl_fmtbuf_t),
fmt_i32[fdesc->slf_sign][fmt_type], v.sld_ui32);
break;
case 8:
(void) snprintf(buf, sizeof (sl_fmtbuf_t),
fmt_i64[fdesc->slf_sign][fmt_type], v.sld_ui64);
break;
}
return (buf);
}
/*
* Return structure layout definition for the given machine type,
* or NULL if the specified machine is not supported.
*/
const sl_arch_layout_t *
sl_mach(Half mach)
{
switch (mach) {
case EM_386:
return (struct_layout_i386());
case EM_AMD64:
return (struct_layout_amd64());
case EM_SPARC:
case EM_SPARC32PLUS:
return (struct_layout_sparc());
case EM_SPARCV9:
return (struct_layout_sparcv9());
}
/* Unsupported architecture */
return (NULL);
}