1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gate #include <stdio.h> 29*0Sstevel@tonic-gate #include <dwarf.h> 30*0Sstevel@tonic-gate #include <sys/types.h> 31*0Sstevel@tonic-gate #include <sys/elf.h> 32*0Sstevel@tonic-gate #include <gelf.h> 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate /* 35*0Sstevel@tonic-gate * Little Endian Base 128 (LEB128) numbers. 36*0Sstevel@tonic-gate * ---------------------------------------- 37*0Sstevel@tonic-gate * 38*0Sstevel@tonic-gate * LEB128 is a scheme for encoding integers densely that exploits the 39*0Sstevel@tonic-gate * assumption that most integers are small in magnitude. (This encoding 40*0Sstevel@tonic-gate * is equally suitable whether the target machine architecture represents 41*0Sstevel@tonic-gate * data in big-endian or little- endian 42*0Sstevel@tonic-gate * 43*0Sstevel@tonic-gate * Unsigned LEB128 numbers are encoded as follows: start at the low order 44*0Sstevel@tonic-gate * end of an unsigned integer and chop it into 7-bit chunks. Place each 45*0Sstevel@tonic-gate * chunk into the low order 7 bits of a byte. Typically, several of the 46*0Sstevel@tonic-gate * high order bytes will be zero; discard them. Emit the remaining bytes in 47*0Sstevel@tonic-gate * a stream, starting with the low order byte; set the high order bit on 48*0Sstevel@tonic-gate * each byte except the last emitted byte. The high bit of zero on the last 49*0Sstevel@tonic-gate * byte indicates to the decoder that it has encountered the last byte. 50*0Sstevel@tonic-gate * The integer zero is a special case, consisting of a single zero byte. 51*0Sstevel@tonic-gate * 52*0Sstevel@tonic-gate * Signed, 2s complement LEB128 numbers are encoded in a similar except 53*0Sstevel@tonic-gate * that the criterion for discarding high order bytes is not whether they 54*0Sstevel@tonic-gate * are zero, but whether they consist entirely of sign extension bits. 55*0Sstevel@tonic-gate * Consider the 32-bit integer -2. The three high level bytes of the number 56*0Sstevel@tonic-gate * are sign extension, thus LEB128 would represent it as a single byte 57*0Sstevel@tonic-gate * containing the low order 7 bits, with the high order bit cleared to 58*0Sstevel@tonic-gate * indicate the end of the byte stream. 59*0Sstevel@tonic-gate * 60*0Sstevel@tonic-gate * Note that there is nothing within the LEB128 representation that 61*0Sstevel@tonic-gate * indicates whether an encoded number is signed or unsigned. The decoder 62*0Sstevel@tonic-gate * must know what type of number to expect. 63*0Sstevel@tonic-gate * 64*0Sstevel@tonic-gate * DWARF Exception Header Encoding 65*0Sstevel@tonic-gate * ------------------------------- 66*0Sstevel@tonic-gate * 67*0Sstevel@tonic-gate * The DWARF Exception Header Encoding is used to describe the type of data 68*0Sstevel@tonic-gate * used in the .eh_frame_hdr section. The upper 4 bits indicate how the 69*0Sstevel@tonic-gate * value is to be applied. The lower 4 bits indicate the format of the data. 70*0Sstevel@tonic-gate * 71*0Sstevel@tonic-gate * DWARF Exception Header value format 72*0Sstevel@tonic-gate * 73*0Sstevel@tonic-gate * Name Value Meaning 74*0Sstevel@tonic-gate * DW_EH_PE_omit 0xff No value is present. 75*0Sstevel@tonic-gate * DW_EH_PE_absptr 0x00 Value is a void* 76*0Sstevel@tonic-gate * DW_EH_PE_uleb128 0x01 Unsigned value is encoded using the 77*0Sstevel@tonic-gate * Little Endian Base 128 (LEB128) 78*0Sstevel@tonic-gate * DW_EH_PE_udata2 0x02 A 2 bytes unsigned value. 79*0Sstevel@tonic-gate * DW_EH_PE_udata4 0x03 A 4 bytes unsigned value. 80*0Sstevel@tonic-gate * DW_EH_PE_udata8 0x04 An 8 bytes unsigned value. 81*0Sstevel@tonic-gate * DW_EH_PE_signed 0x08 bit on for all signed encodings 82*0Sstevel@tonic-gate * DW_EH_PE_sleb128 0x09 Signed value is encoded using the 83*0Sstevel@tonic-gate * Little Endian Base 128 (LEB128) 84*0Sstevel@tonic-gate * DW_EH_PE_sdata2 0x0A A 2 bytes signed value. 85*0Sstevel@tonic-gate * DW_EH_PE_sdata4 0x0B A 4 bytes signed value. 86*0Sstevel@tonic-gate * DW_EH_PE_sdata8 0x0C An 8 bytes signed value. 87*0Sstevel@tonic-gate * 88*0Sstevel@tonic-gate * DWARF Exception Header application 89*0Sstevel@tonic-gate * 90*0Sstevel@tonic-gate * Name Value Meaning 91*0Sstevel@tonic-gate * DW_EH_PE_absptr 0x00 Value is used with no modification. 92*0Sstevel@tonic-gate * DW_EH_PE_pcrel 0x10 Value is reletive to the location of itself 93*0Sstevel@tonic-gate * DW_EH_PE_textrel 0x20 94*0Sstevel@tonic-gate * DW_EH_PE_datarel 0x30 Value is reletive to the beginning of the 95*0Sstevel@tonic-gate * eh_frame_hdr segment ( segment type 96*0Sstevel@tonic-gate * PT_GNU_EH_FRAME ) 97*0Sstevel@tonic-gate * DW_EH_PE_funcrel 0x40 98*0Sstevel@tonic-gate * DW_EH_PE_aligned 0x50 value is an aligned void* 99*0Sstevel@tonic-gate * DW_EH_PE_indirect 0x80 bit to signal indirection after relocation 100*0Sstevel@tonic-gate * DW_EH_PE_omit 0xff No value is present. 101*0Sstevel@tonic-gate * 102*0Sstevel@tonic-gate */ 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate uint64_t 105*0Sstevel@tonic-gate uleb_extract(unsigned char *data, uint64_t *dotp) 106*0Sstevel@tonic-gate { 107*0Sstevel@tonic-gate uint64_t dot = *dotp; 108*0Sstevel@tonic-gate uint64_t res = 0; 109*0Sstevel@tonic-gate int more = 1; 110*0Sstevel@tonic-gate int shift = 0; 111*0Sstevel@tonic-gate int val; 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate data += dot; 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate while (more) { 116*0Sstevel@tonic-gate /* 117*0Sstevel@tonic-gate * Pull off lower 7 bits 118*0Sstevel@tonic-gate */ 119*0Sstevel@tonic-gate val = (*data) & 0x7f; 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate /* 122*0Sstevel@tonic-gate * Add prepend value to head of number. 123*0Sstevel@tonic-gate */ 124*0Sstevel@tonic-gate res = res | (val << shift); 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate /* 127*0Sstevel@tonic-gate * Increment shift & dot pointer 128*0Sstevel@tonic-gate */ 129*0Sstevel@tonic-gate shift += 7; 130*0Sstevel@tonic-gate dot++; 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate /* 133*0Sstevel@tonic-gate * Check to see if hi bit is set - if not, this 134*0Sstevel@tonic-gate * is the last byte. 135*0Sstevel@tonic-gate */ 136*0Sstevel@tonic-gate more = ((*data++) & 0x80) >> 7; 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate *dotp = dot; 139*0Sstevel@tonic-gate return (res); 140*0Sstevel@tonic-gate } 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate int64_t 143*0Sstevel@tonic-gate sleb_extract(unsigned char *data, uint64_t *dotp) 144*0Sstevel@tonic-gate { 145*0Sstevel@tonic-gate uint64_t dot = *dotp; 146*0Sstevel@tonic-gate int64_t res = 0; 147*0Sstevel@tonic-gate int more = 1; 148*0Sstevel@tonic-gate int shift = 0; 149*0Sstevel@tonic-gate int val; 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate data += dot; 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate while (more) { 154*0Sstevel@tonic-gate /* 155*0Sstevel@tonic-gate * Pull off lower 7 bits 156*0Sstevel@tonic-gate */ 157*0Sstevel@tonic-gate val = (*data) & 0x7f; 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate /* 160*0Sstevel@tonic-gate * Add prepend value to head of number. 161*0Sstevel@tonic-gate */ 162*0Sstevel@tonic-gate res = res | (val << shift); 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate /* 165*0Sstevel@tonic-gate * Increment shift & dot pointer 166*0Sstevel@tonic-gate */ 167*0Sstevel@tonic-gate shift += 7; 168*0Sstevel@tonic-gate dot++; 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate /* 171*0Sstevel@tonic-gate * Check to see if hi bit is set - if not, this 172*0Sstevel@tonic-gate * is the last byte. 173*0Sstevel@tonic-gate */ 174*0Sstevel@tonic-gate more = ((*data++) & 0x80) >> 7; 175*0Sstevel@tonic-gate } 176*0Sstevel@tonic-gate *dotp = dot; 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate /* 179*0Sstevel@tonic-gate * Make sure value is properly sign extended. 180*0Sstevel@tonic-gate */ 181*0Sstevel@tonic-gate res = (res << (64 - shift)) >> (64 - shift); 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate return (res); 184*0Sstevel@tonic-gate } 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate uint64_t 187*0Sstevel@tonic-gate dwarf_ehe_extract(unsigned char *data, uint64_t *dotp, uint_t ehe_flags, 188*0Sstevel@tonic-gate unsigned char *eident, uint64_t pcaddr) 189*0Sstevel@tonic-gate { 190*0Sstevel@tonic-gate uint64_t dot = *dotp; 191*0Sstevel@tonic-gate uint_t lsb; 192*0Sstevel@tonic-gate uint_t wordsize; 193*0Sstevel@tonic-gate uint_t fsize; 194*0Sstevel@tonic-gate uint64_t result; 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate if (eident[EI_DATA] == ELFDATA2LSB) 197*0Sstevel@tonic-gate lsb = 1; 198*0Sstevel@tonic-gate else 199*0Sstevel@tonic-gate lsb = 0; 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate if (eident[EI_CLASS] == ELFCLASS64) 202*0Sstevel@tonic-gate wordsize = 8; 203*0Sstevel@tonic-gate else 204*0Sstevel@tonic-gate wordsize = 4; 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate switch (ehe_flags & 0x0f) { 207*0Sstevel@tonic-gate case DW_EH_PE_omit: 208*0Sstevel@tonic-gate return (0); 209*0Sstevel@tonic-gate case DW_EH_PE_absptr: 210*0Sstevel@tonic-gate fsize = wordsize; 211*0Sstevel@tonic-gate break; 212*0Sstevel@tonic-gate case DW_EH_PE_udata8: 213*0Sstevel@tonic-gate case DW_EH_PE_sdata8: 214*0Sstevel@tonic-gate fsize = 8; 215*0Sstevel@tonic-gate break; 216*0Sstevel@tonic-gate case DW_EH_PE_udata4: 217*0Sstevel@tonic-gate case DW_EH_PE_sdata4: 218*0Sstevel@tonic-gate fsize = 4; 219*0Sstevel@tonic-gate break; 220*0Sstevel@tonic-gate case DW_EH_PE_udata2: 221*0Sstevel@tonic-gate case DW_EH_PE_sdata2: 222*0Sstevel@tonic-gate fsize = 2; 223*0Sstevel@tonic-gate break; 224*0Sstevel@tonic-gate case DW_EH_PE_uleb128: 225*0Sstevel@tonic-gate return (uleb_extract(data, dotp)); 226*0Sstevel@tonic-gate case DW_EH_PE_sleb128: 227*0Sstevel@tonic-gate return ((uint64_t)sleb_extract(data, dotp)); 228*0Sstevel@tonic-gate default: 229*0Sstevel@tonic-gate return (0); 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate if (lsb) { 233*0Sstevel@tonic-gate /* 234*0Sstevel@tonic-gate * Extract unaligned LSB formated data 235*0Sstevel@tonic-gate */ 236*0Sstevel@tonic-gate uint_t cnt; 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate result = 0; 239*0Sstevel@tonic-gate for (cnt = 0; cnt < fsize; 240*0Sstevel@tonic-gate cnt++, dot++) { 241*0Sstevel@tonic-gate uint64_t val; 242*0Sstevel@tonic-gate val = data[dot]; 243*0Sstevel@tonic-gate result |= val << (cnt * 8); 244*0Sstevel@tonic-gate } 245*0Sstevel@tonic-gate } else { 246*0Sstevel@tonic-gate /* 247*0Sstevel@tonic-gate * Extract unaligned MSB formated data 248*0Sstevel@tonic-gate */ 249*0Sstevel@tonic-gate uint_t cnt; 250*0Sstevel@tonic-gate result = 0; 251*0Sstevel@tonic-gate for (cnt = 0; cnt < fsize; 252*0Sstevel@tonic-gate cnt++, dot++) { 253*0Sstevel@tonic-gate uint64_t val; 254*0Sstevel@tonic-gate val = data[dot]; 255*0Sstevel@tonic-gate result |= val << ((fsize - cnt - 1) * 8); 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate /* 259*0Sstevel@tonic-gate * perform sign extension 260*0Sstevel@tonic-gate */ 261*0Sstevel@tonic-gate if ((ehe_flags & DW_EH_PE_signed) && 262*0Sstevel@tonic-gate (fsize < sizeof (uint64_t))) { 263*0Sstevel@tonic-gate int64_t sresult; 264*0Sstevel@tonic-gate uint_t bitshift; 265*0Sstevel@tonic-gate sresult = result; 266*0Sstevel@tonic-gate bitshift = (sizeof (uint64_t) - fsize) * 8; 267*0Sstevel@tonic-gate sresult = (sresult << bitshift) >> bitshift; 268*0Sstevel@tonic-gate result = sresult; 269*0Sstevel@tonic-gate } 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate /* 272*0Sstevel@tonic-gate * If pcrel and we have a value (ie: we've been 273*0Sstevel@tonic-gate * relocated), then adjust the value. 274*0Sstevel@tonic-gate */ 275*0Sstevel@tonic-gate if (result && (ehe_flags & DW_EH_PE_pcrel)) { 276*0Sstevel@tonic-gate result = pcaddr + result; 277*0Sstevel@tonic-gate } 278*0Sstevel@tonic-gate *dotp = dot; 279*0Sstevel@tonic-gate return (result); 280*0Sstevel@tonic-gate } 281