Print this page
11210 libm should be cstyle(1ONBLD) clean


   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 2011 Nexenta Systems, Inc.  All rights reserved.
  24  */

  25 /*
  26  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  27  * Use is subject to license terms.
  28  */
  29 
  30 #include <elf.h>
  31 #include <stdio.h>
  32 #include <stdlib.h>
  33 #include <unistd.h>
  34 #include <fcntl.h>
  35 #include <procfs.h>
  36 #include <string.h>
  37 #include <sys/stat.h>
  38 
  39 #if defined(__sparcv9) || defined(__amd64)
  40 
  41 #define Elf_Ehdr        Elf64_Ehdr
  42 #define Elf_Phdr        Elf64_Phdr
  43 #define Elf_Shdr        Elf64_Shdr
  44 #define Elf_Sym         Elf64_Sym
  45 #define ELF_ST_BIND     ELF64_ST_BIND
  46 #define ELF_ST_TYPE     ELF64_ST_TYPE
  47 
  48 #else
  49 
  50 #define Elf_Ehdr        Elf32_Ehdr
  51 #define Elf_Phdr        Elf32_Phdr
  52 #define Elf_Shdr        Elf32_Shdr
  53 #define Elf_Sym         Elf32_Sym
  54 #define ELF_ST_BIND     ELF32_ST_BIND
  55 #define ELF_ST_TYPE     ELF32_ST_TYPE
  56 
  57 #endif  /* __sparcv9 */
  58 
  59 /* semi-permanent data established by __fex_sym_init */
  60 static  prmap_t         *pm = NULL;             /* prmap_t array */
  61 static  int                     npm = 0;                /* number of entries in pm */
  62 
  63 /* transient data modified by __fex_sym */
  64 static  prmap_t         *lpm = NULL;    /* prmap_t found in last call */
  65 static  Elf_Phdr        *ph = NULL;             /* program header array */
  66 static  int                     phsize = 0;             /* size of ph */
  67 static  int                     nph;                    /* number of entries in ph */
  68 static  char            *stbuf = NULL;  /* symbol and string table buffer */
  69 static  int                     stbufsize = 0;  /* size of stbuf */
  70 static  int                     stoffset;               /* offset of string table in stbuf */
  71 static  int                     nsyms;                  /* number of symbols in stbuf */
  72 
  73 /* get a current prmap_t list (must call this before each stack trace) */
  74 void
  75 __fex_sym_init()
  76 {
  77         struct stat     statbuf;
  78         long            n;
  79         int                     i;
  80 
  81         /* clear out the previous prmap_t list */
  82         if (pm != NULL)
  83                 free(pm);

  84         pm = lpm = NULL;
  85         npm = 0;
  86 
  87         /* get the current prmap_t list */
  88         if (stat("/proc/self/map", &statbuf) < 0 || statbuf.st_size <= 0 ||
  89                 (pm = (prmap_t*)malloc(statbuf.st_size)) == NULL)
  90                 return;
  91         if ((i = open("/proc/self/map", O_RDONLY)) < 0)
  92         {
  93                 free(pm);
  94                 pm = NULL;
  95                 return;
  96         }

  97         n = read(i, pm, statbuf.st_size);
  98         close(i);
  99         if (n != statbuf.st_size)
 100         {
 101                 free(pm);
 102                 pm = NULL;


 103         }
 104         else
 105                 npm = (int) (n / sizeof(prmap_t));
 106 }
 107 
 108 /* read ELF program headers and symbols; return -1 on error, 0 otherwise */
 109 static int
 110 __fex_read_syms(int fd)
 111 {
 112         Elf_Ehdr        h;
 113         Elf_Shdr        *sh;
 114         int                     i, size;
 115 
 116         /* read the ELF header */
 117         if (read(fd, &h, sizeof(h)) != sizeof(h))
 118                 return -1;
 119         if (h.e_ident[EI_MAG0] != ELFMAG0 ||
 120                 h.e_ident[EI_MAG1] != ELFMAG1 ||
 121                 h.e_ident[EI_MAG2] != ELFMAG2 ||
 122                 h.e_ident[EI_MAG3] != ELFMAG3 ||
 123                 h.e_phentsize != sizeof(Elf_Phdr) ||
 124                 h.e_shentsize != sizeof(Elf_Shdr))
 125                 return -1;
 126 
 127         /* get space for the program headers */
 128         size = h.e_phnum * h.e_phentsize;
 129         if (size > phsize)
 130         {
 131                 if (ph)
 132                         free(ph);

 133                 phsize = nph = 0;
 134                 if ((ph = (Elf_Phdr*)malloc(size)) == NULL)
 135                         return -1;


 136                 phsize = size;
 137         }
 138 
 139         /* read the program headers */
 140         if (lseek(fd, h.e_phoff, SEEK_SET) != h.e_phoff ||
 141                 read(fd, ph, size) != (ssize_t)size)
 142         {
 143                 nph = 0;
 144                 return -1;
 145         }

 146         nph = h.e_phnum;
 147 
 148         /* read the section headers */
 149         size = h.e_shnum * h.e_shentsize;
 150         if ((sh = (Elf_Shdr*)malloc(size)) == NULL)
 151                 return -1;
 152         if (lseek(fd, h.e_shoff, SEEK_SET) != h.e_shoff ||
 153                 read(fd, sh, size) != (ssize_t)size)
 154         {

 155                 free(sh);
 156                 return -1;
 157         }
 158 
 159         /* find the symtab section header */
 160         for (i = 0; i < h.e_shnum; i++)
 161         {
 162                 if (sh[i].sh_type == SHT_SYMTAB)
 163                         break; /* assume there is only one */
 164         }
 165         if (i == h.e_shnum || sh[i].sh_size == 0 ||
 166                 sh[i].sh_entsize != sizeof(Elf_Sym) ||
 167                 sh[i].sh_link < 1 || sh[i].sh_link >= h.e_shnum ||
 168                 sh[sh[i].sh_link].sh_type != SHT_STRTAB ||
 169                 sh[sh[i].sh_link].sh_size == 0)
 170         {
 171                 free(sh);
 172                 return -1;
 173         }
 174 
 175         /* get space for the symbol and string tables */
 176         size = (int) (sh[i].sh_size + sh[sh[i].sh_link].sh_size);
 177         if (size > stbufsize)
 178         {
 179                 if (stbuf)
 180                         free(stbuf);

 181                 stbufsize = nsyms = 0;
 182                 if ((stbuf = (char*)malloc(size)) == NULL)
 183                 {
 184                         free(sh);
 185                         return -1;
 186                 }

 187                 stbufsize = size;
 188         }
 189 
 190         /* read the symbol and string tables */
 191         if (lseek(fd, sh[i].sh_offset, SEEK_SET) != sh[i].sh_offset ||
 192                 read(fd, stbuf, sh[i].sh_size) != sh[i].sh_size ||
 193                 lseek(fd, sh[sh[i].sh_link].sh_offset, SEEK_SET) !=
 194                         sh[sh[i].sh_link].sh_offset ||
 195                 read(fd, stbuf + sh[i].sh_size, sh[sh[i].sh_link].sh_size) !=
 196                         sh[sh[i].sh_link].sh_size)
 197         {
 198                 free(sh);
 199                 return (-1);
 200         }
 201         nsyms = (int) (sh[i].sh_size / sh[i].sh_entsize);
 202         stoffset = (int) sh[i].sh_size;

 203 
 204         free(sh);
 205         return (0);
 206 }
 207 
 208 /* find the symbol corresponding to the given text address;
 209    return NULL on error, symbol address otherwise */


 210 char *
 211 __fex_sym(char *a, char **name)
 212 {
 213         Elf_Sym                 *s;
 214         unsigned long   fo, va, value;
 215         int                             fd, i, j, nm;
 216         char                    fname[PRMAPSZ+20];
 217 
 218         /* see if the last prmap_t found contains the indicated address */
 219         if (lpm)
 220         {
 221                 if (a >= (char*)lpm->pr_vaddr && a < (char*)lpm->pr_vaddr +
 222                         lpm->pr_size)
 223                         goto cont;
 224         }
 225 
 226         /* look for a prmap_t that contains the indicated address */
 227         for (i = 0; i < npm; i++)
 228         {
 229                 if (a >= (char*)pm[i].pr_vaddr && a < (char*)pm[i].pr_vaddr +
 230                         pm[i].pr_size)
 231                         break;
 232         }

 233         if (i == npm)
 234                 return NULL;
 235 
 236         /* get an open file descriptor for the mapped object */
 237         if (pm[i].pr_mapname[0] == '\0')
 238                 return NULL;

 239         strcpy(fname, "/proc/self/object/");
 240         strncat(fname, pm[i].pr_mapname, PRMAPSZ);
 241         fd = open(fname, O_RDONLY);

 242         if (fd < 0)
 243                 return NULL;
 244 
 245         /* read the program headers and symbols */
 246         lpm = NULL;
 247         j = __fex_read_syms(fd);
 248         close(fd);

 249         if (j < 0)
 250                 return NULL;

 251         lpm = &pm[i];
 252 
 253 cont:
 254         /* compute the file offset corresponding to the mapped address */
 255         fo = (a - (char*)lpm->pr_vaddr) + lpm->pr_offset;
 256 
 257         /* find the program header containing the file offset */
 258         for (i = 0; i < nph; i++)
 259         {
 260                 if (ph[i].p_type == PT_LOAD && fo >= ph[i].p_offset &&
 261                         fo < ph[i].p_offset + ph[i].p_filesz)
 262                         break;
 263         }

 264         if (i == nph)
 265                 return NULL;
 266 
 267         /* compute the virtual address corresponding to the file offset */
 268         va = (fo - ph[i].p_offset) + ph[i].p_vaddr;
 269 
 270         /* find the symbol in this segment with the highest value
 271            less than or equal to the virtual address */
 272         s = (Elf_Sym*)stbuf;


 273         value = nm = 0;
 274         for (j = 0; j < nsyms; j++)
 275         {
 276                 if (s[j].st_name == 0 || s[j].st_shndx == SHN_UNDEF ||
 277                         (ELF_ST_BIND(s[j].st_info) != STB_LOCAL &&
 278                         ELF_ST_BIND(s[j].st_info) != STB_GLOBAL &&
 279                         ELF_ST_BIND(s[j].st_info) != STB_WEAK) ||
 280                         (ELF_ST_TYPE(s[j].st_info) != STT_NOTYPE &&
 281                         ELF_ST_TYPE(s[j].st_info) != STT_OBJECT &&
 282                         ELF_ST_TYPE(s[j].st_info) != STT_FUNC))
 283                 {
 284                         continue;
 285                 }
 286 
 287                 if (s[j].st_value < ph[i].p_vaddr || s[j].st_value >= ph[i].p_vaddr
 288                         + ph[i].p_memsz)
 289                 {
 290                         continue;
 291                 }
 292 
 293                 if (s[j].st_value < value || s[j].st_value > va)
 294                         continue;
 295 
 296                 value = s[j].st_value;
 297                 nm = s[j].st_name;
 298         }

 299         if (nm == 0)
 300                 return NULL;
 301 
 302         /* pass back the name and return the mapped address of the symbol */
 303         *name = stbuf + stoffset + nm;
 304         fo = (value - ph[i].p_vaddr) + ph[i].p_offset;
 305         return (char*)lpm->pr_vaddr + (fo - lpm->pr_offset);
 306 }


   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 2011 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 /*
  27  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  28  * Use is subject to license terms.
  29  */
  30 
  31 #include <elf.h>
  32 #include <stdio.h>
  33 #include <stdlib.h>
  34 #include <unistd.h>
  35 #include <fcntl.h>
  36 #include <procfs.h>
  37 #include <string.h>
  38 #include <sys/stat.h>
  39 
  40 #if defined(__sparcv9) || defined(__amd64)

  41 #define Elf_Ehdr                Elf64_Ehdr
  42 #define Elf_Phdr                Elf64_Phdr
  43 #define Elf_Shdr                Elf64_Shdr
  44 #define Elf_Sym                 Elf64_Sym
  45 #define ELF_ST_BIND             ELF64_ST_BIND
  46 #define ELF_ST_TYPE             ELF64_ST_TYPE

  47 #else

  48 #define Elf_Ehdr                Elf32_Ehdr
  49 #define Elf_Phdr                Elf32_Phdr
  50 #define Elf_Shdr                Elf32_Shdr
  51 #define Elf_Sym                 Elf32_Sym
  52 #define ELF_ST_BIND             ELF32_ST_BIND
  53 #define ELF_ST_TYPE             ELF32_ST_TYPE

  54 #endif /* __sparcv9 */
  55 
  56 /* semi-permanent data established by __fex_sym_init */
  57 static prmap_t *pm = NULL;              /* prmap_t array */
  58 static int npm = 0;                     /* number of entries in pm */
  59 
  60 /* transient data modified by __fex_sym */
  61 static prmap_t *lpm = NULL;             /* prmap_t found in last call */
  62 static Elf_Phdr *ph = NULL;             /* program header array */
  63 static int phsize = 0;                  /* size of ph */
  64 static int nph;                         /* number of entries in ph */
  65 static char *stbuf = NULL;              /* symbol and string table buffer */
  66 static int stbufsize = 0;               /* size of stbuf */
  67 static int stoffset;                    /* offset of string table in stbuf */
  68 static int nsyms;                       /* number of symbols in stbuf */
  69 
  70 /* get a current prmap_t list (must call this before each stack trace) */
  71 void
  72 __fex_sym_init()
  73 {
  74         struct stat statbuf;
  75         long n;
  76         int i;
  77 
  78         /* clear out the previous prmap_t list */
  79         if (pm != NULL)
  80                 free(pm);
  81 
  82         pm = lpm = NULL;
  83         npm = 0;
  84 
  85         /* get the current prmap_t list */
  86         if (stat("/proc/self/map", &statbuf) < 0 || statbuf.st_size <= 0 ||
  87             (pm = (prmap_t *)malloc(statbuf.st_size)) == NULL)
  88                 return;
  89 
  90         if ((i = open("/proc/self/map", O_RDONLY)) < 0) {
  91                 free(pm);
  92                 pm = NULL;
  93                 return;
  94         }
  95 
  96         n = read(i, pm, statbuf.st_size);
  97         close(i);
  98 
  99         if (n != statbuf.st_size) {
 100                 free(pm);
 101                 pm = NULL;
 102         } else {
 103                 npm = (int)(n / sizeof (prmap_t));
 104         }


 105 }
 106 
 107 /* read ELF program headers and symbols; return -1 on error, 0 otherwise */
 108 static int
 109 __fex_read_syms(int fd)
 110 {
 111         Elf_Ehdr h;
 112         Elf_Shdr *sh;
 113         int i, size;
 114 
 115         /* read the ELF header */
 116         if (read(fd, &h, sizeof (h)) != sizeof (h))
 117                 return (-1);
 118 
 119         if (h.e_ident[EI_MAG0] != ELFMAG0 || h.e_ident[EI_MAG1] != ELFMAG1 ||
 120             h.e_ident[EI_MAG2] != ELFMAG2 || h.e_ident[EI_MAG3] != ELFMAG3 ||
 121             h.e_phentsize != sizeof (Elf_Phdr) || h.e_shentsize !=
 122             sizeof (Elf_Shdr))
 123                 return (-1);

 124 
 125         /* get space for the program headers */
 126         size = h.e_phnum * h.e_phentsize;
 127 
 128         if (size > phsize) {
 129                 if (ph)
 130                         free(ph);
 131 
 132                 phsize = nph = 0;
 133 
 134                 if ((ph = (Elf_Phdr *)malloc(size)) == NULL)
 135                         return (-1);
 136 
 137                 phsize = size;
 138         }
 139 
 140         /* read the program headers */
 141         if (lseek(fd, h.e_phoff, SEEK_SET) != h.e_phoff || read(fd, ph, size) !=
 142             (ssize_t)size) {

 143                 nph = 0;
 144                 return (-1);
 145         }
 146 
 147         nph = h.e_phnum;
 148 
 149         /* read the section headers */
 150         size = h.e_shnum * h.e_shentsize;
 151 
 152         if ((sh = (Elf_Shdr *)malloc(size)) == NULL)
 153                 return (-1);
 154 
 155         if (lseek(fd, h.e_shoff, SEEK_SET) != h.e_shoff || read(fd, sh, size) !=
 156             (ssize_t)size) {
 157                 free(sh);
 158                 return (-1);
 159         }
 160 
 161         /* find the symtab section header */
 162         for (i = 0; i < h.e_shnum; i++) {

 163                 if (sh[i].sh_type == SHT_SYMTAB)
 164                         break;          /* assume there is only one */
 165         }
 166 
 167         if (i == h.e_shnum || sh[i].sh_size == 0 || sh[i].sh_entsize !=
 168             sizeof (Elf_Sym) || sh[i].sh_link < 1 || sh[i].sh_link >=
 169             h.e_shnum || sh[sh[i].sh_link].sh_type != SHT_STRTAB ||
 170             sh[sh[i].sh_link].sh_size == 0) {

 171                 free(sh);
 172                 return (-1);
 173         }
 174 
 175         /* get space for the symbol and string tables */
 176         size = (int)(sh[i].sh_size + sh[sh[i].sh_link].sh_size);
 177 
 178         if (size > stbufsize) {
 179                 if (stbuf)
 180                         free(stbuf);
 181 
 182                 stbufsize = nsyms = 0;
 183 
 184                 if ((stbuf = (char *)malloc(size)) == NULL) {
 185                         free(sh);
 186                         return (-1);
 187                 }
 188 
 189                 stbufsize = size;
 190         }
 191 
 192         /* read the symbol and string tables */
 193         if (lseek(fd, sh[i].sh_offset, SEEK_SET) != sh[i].sh_offset ||
 194             read(fd, stbuf, sh[i].sh_size) != sh[i].sh_size ||
 195             lseek(fd, sh[sh[i].sh_link].sh_offset, SEEK_SET) !=
 196             sh[sh[i].sh_link].sh_offset ||
 197             read(fd, stbuf + sh[i].sh_size, sh[sh[i].sh_link].sh_size) !=
 198             sh[sh[i].sh_link].sh_size) {

 199                 free(sh);
 200                 return (-1);
 201         }
 202 
 203         nsyms = (int)(sh[i].sh_size / sh[i].sh_entsize);
 204         stoffset = (int)sh[i].sh_size;
 205 
 206         free(sh);
 207         return (0);
 208 }
 209 
 210 /*
 211  * find the symbol corresponding to the given text address;
 212  * return NULL on error, symbol address otherwise
 213  */
 214 char *
 215 __fex_sym(char *a, char **name)
 216 {
 217         Elf_Sym *s;
 218         unsigned long fo, va, value;
 219         int fd, i, j, nm;
 220         char fname[PRMAPSZ + 20];
 221 
 222         /* see if the last prmap_t found contains the indicated address */
 223         if (lpm) {
 224                 if (a >= (char *)lpm->pr_vaddr && a < (char *)lpm->pr_vaddr +

 225                     lpm->pr_size)
 226                         goto cont;
 227         }
 228 
 229         /* look for a prmap_t that contains the indicated address */
 230         for (i = 0; i < npm; i++) {
 231                 if (a >= (char *)pm[i].pr_vaddr && a < (char *)pm[i].pr_vaddr +

 232                     pm[i].pr_size)
 233                         break;
 234         }
 235 
 236         if (i == npm)
 237                 return (NULL);
 238 
 239         /* get an open file descriptor for the mapped object */
 240         if (pm[i].pr_mapname[0] == '\0')
 241                 return (NULL);
 242 
 243         strcpy(fname, "/proc/self/object/");
 244         strncat(fname, pm[i].pr_mapname, PRMAPSZ);
 245         fd = open(fname, O_RDONLY);
 246 
 247         if (fd < 0)
 248                 return (NULL);
 249 
 250         /* read the program headers and symbols */
 251         lpm = NULL;
 252         j = __fex_read_syms(fd);
 253         close(fd);
 254 
 255         if (j < 0)
 256                 return (NULL);
 257 
 258         lpm = &pm[i];
 259 
 260 cont:
 261         /* compute the file offset corresponding to the mapped address */
 262         fo = (a - (char *)lpm->pr_vaddr) + lpm->pr_offset;
 263 
 264         /* find the program header containing the file offset */
 265         for (i = 0; i < nph; i++) {
 266                 if (ph[i].p_type == PT_LOAD && fo >= ph[i].p_offset && fo <
 267                     ph[i].p_offset + ph[i].p_filesz)

 268                         break;
 269         }
 270 
 271         if (i == nph)
 272                 return (NULL);
 273 
 274         /* compute the virtual address corresponding to the file offset */
 275         va = (fo - ph[i].p_offset) + ph[i].p_vaddr;
 276 
 277         /*
 278          * find the symbol in this segment with the highest value
 279          * less than or equal to the virtual address
 280          */
 281         s = (Elf_Sym *)stbuf;
 282         value = nm = 0;
 283 
 284         for (j = 0; j < nsyms; j++) {
 285                 if (s[j].st_name == 0 || s[j].st_shndx == SHN_UNDEF ||
 286                     (ELF_ST_BIND(s[j].st_info) != STB_LOCAL && ELF_ST_BIND(
 287                     s[j].st_info) != STB_GLOBAL && ELF_ST_BIND(s[j].st_info) !=
 288                     STB_WEAK) || (ELF_ST_TYPE(s[j].st_info) != STT_NOTYPE &&
 289                     ELF_ST_TYPE(s[j].st_info) != STT_OBJECT && ELF_ST_TYPE(
 290                     s[j].st_info) != STT_FUNC))


 291                         continue;

 292 
 293                 if (s[j].st_value < ph[i].p_vaddr || s[j].st_value >=
 294                     ph[i].p_vaddr + ph[i].p_memsz)

 295                         continue;

 296 
 297                 if (s[j].st_value < value || s[j].st_value > va)
 298                         continue;
 299 
 300                 value = s[j].st_value;
 301                 nm = s[j].st_name;
 302         }
 303 
 304         if (nm == 0)
 305                 return (NULL);
 306 
 307         /* pass back the name and return the mapped address of the symbol */
 308         *name = stbuf + stoffset + nm;
 309         fo = (value - ph[i].p_vaddr) + ph[i].p_offset;
 310         return ((char *)lpm->pr_vaddr + (fo - lpm->pr_offset));
 311 }