1 /*
   2  * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 /*
  26  * Name:        add_gnu_debuglink.c
  27  *
  28  * Description: Add a ".gnu_debuglink" section that refers to the specified
  29  *     debug_info_path to the specified ELF object.
  30  *
  31  *     This program is adapted from the example program shown on the
  32  *     elf(3elf) man page and from code from the Solaris compiler
  33  *     driver.
  34  */
  35 
  36 /*
  37  * needed to define SHF_EXCLUDE
  38  */
  39 #define ELF_TARGET_ALL
  40 
  41 #include <fcntl.h>
  42 #include <stdio.h>
  43 #include <libelf.h>
  44 #include <stdlib.h>
  45 #include <string.h>
  46 #include <unistd.h>
  47 
  48 static void failure(void);
  49 static unsigned int gnu_debuglink_crc32(unsigned int crc, unsigned char *buf,
  50                                         size_t len);
  51 
  52 void
  53 main(int argc, char ** argv) {
  54                                  /* new ELF section name */
  55     static char SEC_NAME[] = ".gnu_debuglink";
  56 
  57     unsigned char buffer[8 * 1024];  /* I/O buffer */
  58     int           buffer_len;        /* buffer length */
  59     char *        debug_info_path;   /* debug info path */
  60     void *        ehdr;              /* ELF header */
  61     Elf *         elf;               /* ELF descriptor */
  62     char *        elf_ident;         /* ELF identity string */
  63     char *        elf_obj;           /* elf_obj file */
  64     int           fd;                /* descriptor for files */
  65     unsigned int  file_crc = 0;      /* CRC for debug info file */
  66     int           is_elfclass64;     /* is an ELFCLASS64 file? */
  67     Elf_Data *    link_dat;          /* ELF data for new debug info link */
  68     Elf_Data *    name_dat;          /* ELF data for new section name */
  69     Elf_Scn *     new_scn;           /* new ELF section descriptor */
  70     void *        new_shdr;          /* new ELF section header */
  71     Elf_Scn *     scn;               /* ELF section descriptor */
  72     void *        shdr;              /* ELF section header */
  73 
  74     if (argc != 3) {
  75         (void) fprintf(stderr, "Usage: %s debug_info_path elf_obj\n", argv[0]);
  76         exit(2);
  77     }
  78 
  79     debug_info_path = argv[1];  /* save for later */
  80     if ((fd = open(debug_info_path, O_RDONLY)) == -1) {
  81         (void) fprintf(stderr, "%s: cannot open file.\n", debug_info_path);
  82         exit(3);
  83     }
  84 
  85     (void) printf("Computing CRC for '%s'\n", debug_info_path);
  86     (void) fflush(stdout);
  87     /* compute CRC for the debug info file */
  88     for (;;) {
  89         int len = read(fd, buffer, sizeof buffer);
  90         if (len <= 0) {
  91             break;
  92         }
  93         file_crc = gnu_debuglink_crc32(file_crc, buffer, len);
  94     }
  95     (void) close(fd);
  96 
  97     /* open the elf_obj */
  98     elf_obj = argv[2];
  99     if ((fd = open(elf_obj, O_RDWR)) == -1) {
 100         (void) fprintf(stderr, "%s: cannot open file.\n", elf_obj);
 101         exit(4);
 102     }
 103 
 104     (void) printf("Opening '%s' for update\n", elf_obj);
 105     (void) fflush(stdout);
 106     (void) elf_version(EV_CURRENT);  /* coordinate ELF versions */
 107 
 108     /* obtain the ELF descriptors from the input file */
 109     if ((elf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL) {
 110         failure();
 111     }
 112 
 113     /* determine if ELFCLASS64 or not? */
 114     elf_ident = elf_getident(elf, NULL);
 115     is_elfclass64 = (elf_ident[EI_CLASS] == ELFCLASS64);
 116 
 117     /* get the ELF header */
 118     if (is_elfclass64) {
 119         ehdr = elf64_getehdr(elf);
 120     } else {
 121         ehdr = elf32_getehdr(elf);
 122     }
 123     if (ehdr == NULL) {
 124         failure();
 125     }
 126 
 127     /* get the ELF section descriptor */
 128     if (is_elfclass64) {
 129         scn = elf_getscn(elf, ((Elf64_Ehdr *) ehdr)->e_shstrndx);
 130     } else {
 131         scn = elf_getscn(elf, ((Elf32_Ehdr *) ehdr)->e_shstrndx);
 132     }
 133     if (scn == NULL) {
 134         failure();
 135     }
 136 
 137     /* get the section header */
 138     if (is_elfclass64) {
 139         shdr = elf64_getshdr(scn);
 140     } else {
 141         shdr = elf32_getshdr(scn);
 142     }
 143     if (shdr == NULL) {
 144         failure();
 145     }
 146 
 147     (void) printf("Adding ELF data for new section name\n");
 148     (void) fflush(stdout);
 149     name_dat = elf_newdata(scn);
 150     name_dat->d_buf = (void *) SEC_NAME;
 151     if (is_elfclass64) {
 152         name_dat->d_off = ((Elf64_Shdr *) shdr)->sh_size + 1;
 153     } else {
 154         name_dat->d_off = ((Elf32_Shdr *) shdr)->sh_size + 1;
 155     }
 156     name_dat->d_align = 1;
 157     name_dat->d_size = strlen(SEC_NAME) + 1;
 158 
 159     new_scn = elf_newscn(elf);
 160 
 161     if (is_elfclass64) {
 162         new_shdr = elf64_getshdr(new_scn);
 163         ((Elf64_Shdr *) new_shdr)->sh_flags = SHF_EXCLUDE;
 164         ((Elf64_Shdr *) new_shdr)->sh_type = SHT_PROGBITS;
 165         ((Elf64_Shdr *) new_shdr)->sh_name = ((Elf64_Shdr *) shdr)->sh_size;
 166         ((Elf64_Shdr *) new_shdr)->sh_addralign = 1;
 167         ((Elf64_Shdr *) shdr)->sh_size += (strlen(SEC_NAME) + 1);
 168     } else {
 169         new_shdr = elf32_getshdr(new_scn);
 170         ((Elf32_Shdr *) new_shdr)->sh_flags = SHF_EXCLUDE;
 171         ((Elf32_Shdr *) new_shdr)->sh_type = SHT_PROGBITS;
 172         ((Elf32_Shdr *) new_shdr)->sh_name = ((Elf32_Shdr *) shdr)->sh_size;
 173         ((Elf32_Shdr *) new_shdr)->sh_addralign = 1;
 174         ((Elf32_Shdr *) shdr)->sh_size += (strlen(SEC_NAME) + 1);
 175     }
 176 
 177     (void) printf("Adding ELF data for debug_info_path value\n");
 178     (void) fflush(stdout);
 179     (void) memset(buffer, 0, sizeof buffer);
 180     buffer_len = strlen(debug_info_path) + 1;  /* +1 for NUL */
 181     (void) strncpy((char *) buffer, debug_info_path, buffer_len);
 182     if (buffer_len % 4 != 0) {
 183         /* not on a 4 byte boundary so pad to the next one */
 184         buffer_len += (4 - buffer_len % 4);
 185     }
 186     /* save the CRC */
 187     (void) memcpy(&buffer[buffer_len], &file_crc, sizeof file_crc);
 188     buffer_len += sizeof file_crc;
 189 
 190     link_dat = elf_newdata(new_scn);
 191     link_dat->d_type = ELF_T_BYTE;
 192     link_dat->d_size = buffer_len;
 193     link_dat->d_buf = buffer;
 194     link_dat->d_align = 1;
 195 
 196     (void) printf("Saving updates to '%s'\n", elf_obj);
 197     (void) fflush(stdout);
 198     (void) elf_update(elf, ELF_C_NULL);   /* recalc ELF memory structures */
 199     (void) elf_update(elf, ELF_C_WRITE);  /* write out changes to ELF obj */
 200     (void) elf_end(elf);                  /* done with ELF obj */
 201     (void) close(fd);
 202 
 203     (void) printf("Done updating '%s'\n", elf_obj);
 204     (void) fflush(stdout);
 205     exit(0);
 206 }  /* end main */
 207 
 208 
 209 static void
 210 failure() {
 211     (void) fprintf(stderr, "%s\n", elf_errmsg(elf_errno()));
 212     exit(5);
 213 }
 214 
 215 
 216 /*
 217  * The CRC used in gnu_debuglink, retrieved from
 218  * http://sourceware.org/gdb/current/onlinedocs/gdb/Separate-Debug-Files.html#Separate-Debug-Files.
 219  */
 220 
 221 static unsigned int
 222 gnu_debuglink_crc32(unsigned int crc, unsigned char *buf, size_t len) {
 223     static const unsigned int crc32_table[256] = {
 224         0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
 225         0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
 226         0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
 227         0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
 228         0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
 229         0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
 230         0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
 231         0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
 232         0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
 233         0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
 234         0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
 235         0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
 236         0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
 237         0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
 238         0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
 239         0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
 240         0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
 241         0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
 242         0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
 243         0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
 244         0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
 245         0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
 246         0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
 247         0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
 248         0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
 249         0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
 250         0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
 251         0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
 252         0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
 253         0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
 254         0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
 255         0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
 256         0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
 257         0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
 258         0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
 259         0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
 260         0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
 261         0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
 262         0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
 263         0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
 264         0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
 265         0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
 266         0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
 267         0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
 268         0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
 269         0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
 270         0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
 271         0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
 272         0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
 273         0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
 274         0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
 275         0x2d02ef8d
 276     };
 277 
 278     unsigned char *end;
 279 
 280     crc = ~crc & 0xffffffff;
 281     for (end = buf + len; buf < end; ++buf) {
 282         crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
 283     }
 284     return ~crc & 0xffffffff;
 285 }