1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include <stdlib.h>
  28 #include <stdio.h>
  29 #include <string.h>
  30 #include <msg.h>
  31 #include <_elfdump.h>
  32 #include <struct_layout.h>
  33 #include <conv.h>
  34 
  35 
  36 /*
  37  * Functions for extracting and formatting numeric values from
  38  * structure data.
  39  */
  40 
  41 
  42 
  43 
  44 /*
  45  * Extract the integral field into the value union given and
  46  * perform any necessary byte swapping to make the result readable
  47  * on the elfdump host.
  48  */
  49 void
  50 sl_extract_num_field(const char *data, int do_swap, const sl_field_t *fdesc,
  51     sl_data_t *field_data)
  52 {
  53         /* Copy the value bytes into our union */
  54         (void) memcpy(field_data, data + fdesc->slf_offset,
  55             fdesc->slf_eltlen);
  56 
  57         /* Do byte swapping as necessary */
  58         if (do_swap) {
  59                 switch (fdesc->slf_eltlen) {
  60                 case 2:
  61                         field_data->sld_ui16 = BSWAP_HALF(field_data->sld_ui16);
  62                         break;
  63 
  64                 case 4:
  65                         field_data->sld_ui32 = BSWAP_WORD(field_data->sld_ui32);
  66                         break;
  67 
  68                 case 8:
  69                         field_data->sld_ui64 =
  70                             BSWAP_LWORD(field_data->sld_ui64);
  71                         break;
  72                 }
  73         }
  74 }
  75 
  76 /*
  77  * Extract the given integer field, and return its value, cast
  78  * to Word. Note that this operation must not be used on values
  79  * that can be negative, or larger than 32-bits, as information
  80  * can be lost.
  81  */
  82 Word
  83 sl_extract_as_word(const char *data, int do_swap, const sl_field_t *fdesc)
  84 {
  85         sl_data_t       v;
  86 
  87         /* Extract the value from the raw data */
  88         sl_extract_num_field(data, do_swap, fdesc, &v);
  89 
  90         if (fdesc->slf_sign) {
  91                 switch (fdesc->slf_eltlen) {
  92                         case 1:
  93                                 return ((Word) v.sld_i8);
  94                         case 2:
  95                                 return ((Word) v.sld_i16);
  96                         case 4:
  97                                 return ((Word) v.sld_i32);
  98                         case 8:
  99                                 return ((Word) v.sld_i64);
 100                 }
 101         } else {
 102                 switch (fdesc->slf_eltlen) {
 103                         case 1:
 104                                 return ((Word) v.sld_ui8);
 105                         case 2:
 106                                 return ((Word) v.sld_ui16);
 107                         case 4:
 108                                 return ((Word) v.sld_ui32);
 109                         case 8:
 110                                 return ((Word) v.sld_ui64);
 111                 }
 112         }
 113 
 114         /* This should not be reached */
 115         assert(0);
 116         return (0);
 117 }
 118 
 119 
 120 /*
 121  * Extract the given integer field, and return its value, cast
 122  * to Lword. Note that this operation must not be used on values
 123  * that can be negative, as information can be lost.
 124  */
 125 Lword
 126 sl_extract_as_lword(const char *data, int do_swap, const sl_field_t *fdesc)
 127 {
 128         sl_data_t       v;
 129 
 130         /* Extract the value from the raw data */
 131         sl_extract_num_field(data, do_swap, fdesc, &v);
 132 
 133         if (fdesc->slf_sign) {
 134                 switch (fdesc->slf_eltlen) {
 135                         case 1:
 136                                 return ((Lword) v.sld_i8);
 137                         case 2:
 138                                 return ((Lword) v.sld_i16);
 139                         case 4:
 140                                 return ((Lword) v.sld_i32);
 141                         case 8:
 142                                 return ((Lword) v.sld_i64);
 143                 }
 144         } else {
 145                 switch (fdesc->slf_eltlen) {
 146                         case 1:
 147                                 return ((Lword) v.sld_ui8);
 148                         case 2:
 149                                 return ((Lword) v.sld_ui16);
 150                         case 4:
 151                                 return ((Lword) v.sld_ui32);
 152                         case 8:
 153                                 return ((Lword) v.sld_ui64);
 154                 }
 155         }
 156 
 157         /* This should not be reached */
 158         assert(0);
 159         return (0);
 160 }
 161 
 162 
 163 /*
 164  * Extract the given integer field, and return its value, cast
 165  * to int32_t. Note that this operation must not be used on unsigned
 166  * values larger than 31-bits, or on signed values larger than 32-bits,
 167  * as information can be lost.
 168  */
 169 Sword
 170 sl_extract_as_sword(const char *data, int do_swap, const sl_field_t *fdesc)
 171 {
 172         sl_data_t       v;
 173 
 174         /* Extract the value from the raw data */
 175         sl_extract_num_field(data, do_swap, fdesc, &v);
 176 
 177         if (fdesc->slf_sign) {
 178                 switch (fdesc->slf_eltlen) {
 179                         case 1:
 180                                 return ((Sword)v.sld_i8);
 181                         case 2:
 182                                 return ((Sword)v.sld_i16);
 183                         case 4:
 184                                 return ((Sword)v.sld_i32);
 185                         case 8:
 186                                 return ((Sword)v.sld_i64);
 187                 }
 188         } else {
 189                 switch (fdesc->slf_eltlen) {
 190                         case 1:
 191                                 return ((Sword)v.sld_ui8);
 192                         case 2:
 193                                 return ((Sword)v.sld_ui16);
 194                         case 4:
 195                                 return ((Sword)v.sld_ui32);
 196                         case 8:
 197                                 return ((Sword)v.sld_ui64);
 198                 }
 199         }
 200 
 201         /* This should not be reached */
 202         assert(0);
 203         return (0);
 204 }
 205 
 206 
 207 /*
 208  * Extract the integral field and format it into the supplied buffer.
 209  */
 210 const char *
 211 sl_fmt_num(const char *data, int do_swap, const sl_field_t *fdesc,
 212     sl_fmt_num_t fmt_type, sl_fmtbuf_t buf)
 213 {
 214         /*
 215          * These static arrays are indexed by [fdesc->slf_sign][fmt_type]
 216          * to get a format string to use for the specified combination.
 217          */
 218         static const char *fmt_i8[2][3] = {
 219                 {
 220                         MSG_ORIG(MSG_CNOTE_FMT_U),
 221                         MSG_ORIG(MSG_CNOTE_FMT_X),
 222                         MSG_ORIG(MSG_CNOTE_FMT_Z2X)
 223                 },
 224                 {
 225                         MSG_ORIG(MSG_CNOTE_FMT_D),
 226                         MSG_ORIG(MSG_CNOTE_FMT_X),
 227                         MSG_ORIG(MSG_CNOTE_FMT_Z2X)
 228                 }
 229         };
 230         static const char *fmt_i16[2][3] = {
 231                 {
 232                         MSG_ORIG(MSG_CNOTE_FMT_U),
 233                         MSG_ORIG(MSG_CNOTE_FMT_X),
 234                         MSG_ORIG(MSG_CNOTE_FMT_Z4X)
 235                 },
 236                 {
 237                         MSG_ORIG(MSG_CNOTE_FMT_D),
 238                         MSG_ORIG(MSG_CNOTE_FMT_X),
 239                         MSG_ORIG(MSG_CNOTE_FMT_Z4X)
 240                 }
 241         };
 242         static const char *fmt_i32[2][3] = {
 243                 {
 244                         MSG_ORIG(MSG_CNOTE_FMT_U),
 245                         MSG_ORIG(MSG_CNOTE_FMT_X),
 246                         MSG_ORIG(MSG_CNOTE_FMT_Z8X)
 247                 },
 248                 {
 249                         MSG_ORIG(MSG_CNOTE_FMT_D),
 250                         MSG_ORIG(MSG_CNOTE_FMT_X),
 251                         MSG_ORIG(MSG_CNOTE_FMT_Z8X)
 252                 }
 253         };
 254         static const char *fmt_i64[2][3] = {
 255                 {
 256                         MSG_ORIG(MSG_CNOTE_FMT_LLU),
 257                         MSG_ORIG(MSG_CNOTE_FMT_LLX),
 258                         MSG_ORIG(MSG_CNOTE_FMT_Z16LLX)
 259                 },
 260                 {
 261                         MSG_ORIG(MSG_CNOTE_FMT_LLD),
 262                         MSG_ORIG(MSG_CNOTE_FMT_LLX),
 263                         MSG_ORIG(MSG_CNOTE_FMT_Z16LLX)
 264                 }
 265         };
 266 
 267         sl_data_t       v;
 268 
 269         /* Extract the value from the raw data */
 270         sl_extract_num_field(data, do_swap, fdesc, &v);
 271 
 272         /*
 273          * Format into the buffer. Note that we depend on the signed
 274          * and unsigned versions of each width being equivalent as long
 275          * as the format specifies the proper formatting.
 276          */
 277         switch (fdesc->slf_eltlen) {
 278         case 1:
 279                 (void) snprintf(buf, sizeof (sl_fmtbuf_t),
 280                     fmt_i8[fdesc->slf_sign][fmt_type], (uint32_t)v.sld_ui8);
 281                 break;
 282 
 283         case 2:
 284                 (void) snprintf(buf, sizeof (sl_fmtbuf_t),
 285                     fmt_i16[fdesc->slf_sign][fmt_type], (uint32_t)v.sld_ui16);
 286                 break;
 287 
 288         case 4:
 289                 (void) snprintf(buf, sizeof (sl_fmtbuf_t),
 290                     fmt_i32[fdesc->slf_sign][fmt_type], v.sld_ui32);
 291                 break;
 292 
 293         case 8:
 294                 (void) snprintf(buf, sizeof (sl_fmtbuf_t),
 295                     fmt_i64[fdesc->slf_sign][fmt_type], v.sld_ui64);
 296                 break;
 297         }
 298 
 299         return (buf);
 300 }
 301 
 302 /*
 303  * Return structure layout definition for the given machine type,
 304  * or NULL if the specified machine is not supported.
 305  */
 306 const sl_arch_layout_t  *
 307 sl_mach(Half mach)
 308 {
 309         switch (mach) {
 310         case EM_386:
 311                 return (struct_layout_i386());
 312 
 313         case EM_AMD64:
 314                 return (struct_layout_amd64());
 315 
 316         case EM_SPARC:
 317         case EM_SPARC32PLUS:
 318                 return (struct_layout_sparc());
 319 
 320         case EM_SPARCV9:
 321                 return (struct_layout_sparcv9());
 322         }
 323 
 324         /* Unsupported architecture */
 325         return (NULL);
 326 }