1*7fd79137SRobert Mustacchi /* 2*7fd79137SRobert Mustacchi * This file and its contents are supplied under the terms of the 3*7fd79137SRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0. 4*7fd79137SRobert Mustacchi * You may only use this file in accordance with the terms of version 5*7fd79137SRobert Mustacchi * 1.0 of the CDDL. 6*7fd79137SRobert Mustacchi * 7*7fd79137SRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this 8*7fd79137SRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at 9*7fd79137SRobert Mustacchi * http://www.illumos.org/license/CDDL. 10*7fd79137SRobert Mustacchi */ 11*7fd79137SRobert Mustacchi 12*7fd79137SRobert Mustacchi /* 13*7fd79137SRobert Mustacchi * Copyright (c) 2017, Joyent, Inc. 14*7fd79137SRobert Mustacchi */ 15*7fd79137SRobert Mustacchi 16*7fd79137SRobert Mustacchi /* 17*7fd79137SRobert Mustacchi * merge CTF containers 18*7fd79137SRobert Mustacchi */ 19*7fd79137SRobert Mustacchi 20*7fd79137SRobert Mustacchi #include <stdio.h> 21*7fd79137SRobert Mustacchi #include <libctf.h> 22*7fd79137SRobert Mustacchi #include <sys/stat.h> 23*7fd79137SRobert Mustacchi #include <sys/types.h> 24*7fd79137SRobert Mustacchi #include <fcntl.h> 25*7fd79137SRobert Mustacchi #include <errno.h> 26*7fd79137SRobert Mustacchi #include <strings.h> 27*7fd79137SRobert Mustacchi #include <assert.h> 28*7fd79137SRobert Mustacchi #include <unistd.h> 29*7fd79137SRobert Mustacchi #include <sys/fcntl.h> 30*7fd79137SRobert Mustacchi #include <stdlib.h> 31*7fd79137SRobert Mustacchi #include <libelf.h> 32*7fd79137SRobert Mustacchi #include <gelf.h> 33*7fd79137SRobert Mustacchi #include <sys/mman.h> 34*7fd79137SRobert Mustacchi #include <libgen.h> 35*7fd79137SRobert Mustacchi #include <stdarg.h> 36*7fd79137SRobert Mustacchi #include <limits.h> 37*7fd79137SRobert Mustacchi 38*7fd79137SRobert Mustacchi static char *g_progname; 39*7fd79137SRobert Mustacchi static char *g_unique; 40*7fd79137SRobert Mustacchi static char *g_outfile; 41*7fd79137SRobert Mustacchi static boolean_t g_req; 42*7fd79137SRobert Mustacchi static uint_t g_nctf; 43*7fd79137SRobert Mustacchi 44*7fd79137SRobert Mustacchi #define CTFMERGE_OK 0 45*7fd79137SRobert Mustacchi #define CTFMERGE_FATAL 1 46*7fd79137SRobert Mustacchi #define CTFMERGE_USAGE 2 47*7fd79137SRobert Mustacchi 48*7fd79137SRobert Mustacchi #define CTFMERGE_DEFAULT_NTHREADS 8 49*7fd79137SRobert Mustacchi #define CTFMERGE_ALTEXEC "CTFMERGE_ALTEXEC" 50*7fd79137SRobert Mustacchi 51*7fd79137SRobert Mustacchi static void 52*7fd79137SRobert Mustacchi ctfmerge_fatal(const char *fmt, ...) 53*7fd79137SRobert Mustacchi { 54*7fd79137SRobert Mustacchi va_list ap; 55*7fd79137SRobert Mustacchi 56*7fd79137SRobert Mustacchi (void) fprintf(stderr, "%s: ", g_progname); 57*7fd79137SRobert Mustacchi va_start(ap, fmt); 58*7fd79137SRobert Mustacchi (void) vfprintf(stderr, fmt, ap); 59*7fd79137SRobert Mustacchi va_end(ap); 60*7fd79137SRobert Mustacchi 61*7fd79137SRobert Mustacchi if (g_outfile != NULL) 62*7fd79137SRobert Mustacchi (void) unlink(g_outfile); 63*7fd79137SRobert Mustacchi 64*7fd79137SRobert Mustacchi exit(CTFMERGE_FATAL); 65*7fd79137SRobert Mustacchi } 66*7fd79137SRobert Mustacchi 67*7fd79137SRobert Mustacchi static boolean_t 68*7fd79137SRobert Mustacchi ctfmerge_expect_ctf(const char *name, Elf *elf) 69*7fd79137SRobert Mustacchi { 70*7fd79137SRobert Mustacchi Elf_Scn *scn, *strscn; 71*7fd79137SRobert Mustacchi Elf_Data *data, *strdata; 72*7fd79137SRobert Mustacchi GElf_Shdr shdr; 73*7fd79137SRobert Mustacchi ulong_t i; 74*7fd79137SRobert Mustacchi 75*7fd79137SRobert Mustacchi if (g_req == B_FALSE) 76*7fd79137SRobert Mustacchi return (B_FALSE); 77*7fd79137SRobert Mustacchi 78*7fd79137SRobert Mustacchi scn = NULL; 79*7fd79137SRobert Mustacchi while ((scn = elf_nextscn(elf, scn)) != NULL) { 80*7fd79137SRobert Mustacchi if (gelf_getshdr(scn, &shdr) == NULL) { 81*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to get section header for file " 82*7fd79137SRobert Mustacchi "%s: %s\n", name, elf_errmsg(elf_errno())); 83*7fd79137SRobert Mustacchi } 84*7fd79137SRobert Mustacchi 85*7fd79137SRobert Mustacchi if (shdr.sh_type == SHT_SYMTAB) 86*7fd79137SRobert Mustacchi break; 87*7fd79137SRobert Mustacchi } 88*7fd79137SRobert Mustacchi 89*7fd79137SRobert Mustacchi if (scn == NULL) 90*7fd79137SRobert Mustacchi return (B_FALSE); 91*7fd79137SRobert Mustacchi 92*7fd79137SRobert Mustacchi if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL) 93*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to get section header for file %s: %s\n", 94*7fd79137SRobert Mustacchi name, elf_errmsg(elf_errno())); 95*7fd79137SRobert Mustacchi 96*7fd79137SRobert Mustacchi if ((data = elf_getdata(scn, NULL)) == NULL) 97*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to read symbol table for %s: %s\n", 98*7fd79137SRobert Mustacchi name, elf_errmsg(elf_errno())); 99*7fd79137SRobert Mustacchi 100*7fd79137SRobert Mustacchi if ((strdata = elf_getdata(strscn, NULL)) == NULL) 101*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to read string table for %s: %s\n", 102*7fd79137SRobert Mustacchi name, elf_errmsg(elf_errno())); 103*7fd79137SRobert Mustacchi 104*7fd79137SRobert Mustacchi for (i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) { 105*7fd79137SRobert Mustacchi GElf_Sym sym; 106*7fd79137SRobert Mustacchi const char *file; 107*7fd79137SRobert Mustacchi size_t len; 108*7fd79137SRobert Mustacchi 109*7fd79137SRobert Mustacchi if (gelf_getsym(data, i, &sym) == NULL) 110*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to read symbol table entry %lu " 111*7fd79137SRobert Mustacchi "for %s: %s\n", i, name, elf_errmsg(elf_errno())); 112*7fd79137SRobert Mustacchi 113*7fd79137SRobert Mustacchi if (GELF_ST_TYPE(sym.st_info) != STT_FILE) 114*7fd79137SRobert Mustacchi continue; 115*7fd79137SRobert Mustacchi 116*7fd79137SRobert Mustacchi file = (const char *)((uintptr_t)strdata->d_buf + sym.st_name); 117*7fd79137SRobert Mustacchi len = strlen(file); 118*7fd79137SRobert Mustacchi if (len < 2 || name[len - 2] != '.') 119*7fd79137SRobert Mustacchi continue; 120*7fd79137SRobert Mustacchi 121*7fd79137SRobert Mustacchi if (name[len - 1] == 'c') 122*7fd79137SRobert Mustacchi return (B_TRUE); 123*7fd79137SRobert Mustacchi } 124*7fd79137SRobert Mustacchi 125*7fd79137SRobert Mustacchi return (B_FALSE); 126*7fd79137SRobert Mustacchi } 127*7fd79137SRobert Mustacchi 128*7fd79137SRobert Mustacchi /* 129*7fd79137SRobert Mustacchi * Go through and construct enough information for this Elf Object to try and do 130*7fd79137SRobert Mustacchi * a ctf_bufopen(). 131*7fd79137SRobert Mustacchi */ 132*7fd79137SRobert Mustacchi static void 133*7fd79137SRobert Mustacchi ctfmerge_elfopen(const char *name, Elf *elf, ctf_merge_t *cmh) 134*7fd79137SRobert Mustacchi { 135*7fd79137SRobert Mustacchi GElf_Ehdr ehdr; 136*7fd79137SRobert Mustacchi GElf_Shdr shdr; 137*7fd79137SRobert Mustacchi Elf_Scn *scn; 138*7fd79137SRobert Mustacchi Elf_Data *ctf_data, *str_data, *sym_data; 139*7fd79137SRobert Mustacchi ctf_sect_t ctfsect, symsect, strsect; 140*7fd79137SRobert Mustacchi ctf_file_t *fp; 141*7fd79137SRobert Mustacchi int err; 142*7fd79137SRobert Mustacchi 143*7fd79137SRobert Mustacchi if (gelf_getehdr(elf, &ehdr) == NULL) 144*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to get ELF header for %s: %s\n", 145*7fd79137SRobert Mustacchi name, elf_errmsg(elf_errno())); 146*7fd79137SRobert Mustacchi 147*7fd79137SRobert Mustacchi bzero(&ctfsect, sizeof (ctf_sect_t)); 148*7fd79137SRobert Mustacchi bzero(&symsect, sizeof (ctf_sect_t)); 149*7fd79137SRobert Mustacchi bzero(&strsect, sizeof (ctf_sect_t)); 150*7fd79137SRobert Mustacchi 151*7fd79137SRobert Mustacchi scn = NULL; 152*7fd79137SRobert Mustacchi while ((scn = elf_nextscn(elf, scn)) != NULL) { 153*7fd79137SRobert Mustacchi const char *sname; 154*7fd79137SRobert Mustacchi 155*7fd79137SRobert Mustacchi if (gelf_getshdr(scn, &shdr) == NULL) 156*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to get section header for " 157*7fd79137SRobert Mustacchi "file %s: %s\n", name, elf_errmsg(elf_errno())); 158*7fd79137SRobert Mustacchi 159*7fd79137SRobert Mustacchi sname = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name); 160*7fd79137SRobert Mustacchi if (shdr.sh_type == SHT_PROGBITS && 161*7fd79137SRobert Mustacchi strcmp(sname, ".SUNW_ctf") == 0) { 162*7fd79137SRobert Mustacchi ctfsect.cts_name = sname; 163*7fd79137SRobert Mustacchi ctfsect.cts_type = shdr.sh_type; 164*7fd79137SRobert Mustacchi ctfsect.cts_flags = shdr.sh_flags; 165*7fd79137SRobert Mustacchi ctfsect.cts_size = shdr.sh_size; 166*7fd79137SRobert Mustacchi ctfsect.cts_entsize = shdr.sh_entsize; 167*7fd79137SRobert Mustacchi ctfsect.cts_offset = (off64_t)shdr.sh_offset; 168*7fd79137SRobert Mustacchi 169*7fd79137SRobert Mustacchi ctf_data = elf_getdata(scn, NULL); 170*7fd79137SRobert Mustacchi if (ctf_data == NULL) 171*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to get ELF CTF " 172*7fd79137SRobert Mustacchi "data section for %s: %s\n", name, 173*7fd79137SRobert Mustacchi elf_errmsg(elf_errno())); 174*7fd79137SRobert Mustacchi ctfsect.cts_data = ctf_data->d_buf; 175*7fd79137SRobert Mustacchi } else if (shdr.sh_type == SHT_SYMTAB) { 176*7fd79137SRobert Mustacchi Elf_Scn *strscn; 177*7fd79137SRobert Mustacchi GElf_Shdr strhdr; 178*7fd79137SRobert Mustacchi 179*7fd79137SRobert Mustacchi symsect.cts_name = sname; 180*7fd79137SRobert Mustacchi symsect.cts_type = shdr.sh_type; 181*7fd79137SRobert Mustacchi symsect.cts_flags = shdr.sh_flags; 182*7fd79137SRobert Mustacchi symsect.cts_size = shdr.sh_size; 183*7fd79137SRobert Mustacchi symsect.cts_entsize = shdr.sh_entsize; 184*7fd79137SRobert Mustacchi symsect.cts_offset = (off64_t)shdr.sh_offset; 185*7fd79137SRobert Mustacchi 186*7fd79137SRobert Mustacchi if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL || 187*7fd79137SRobert Mustacchi gelf_getshdr(strscn, &strhdr) == NULL) 188*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to get " 189*7fd79137SRobert Mustacchi "string table for file %s: %s\n", name, 190*7fd79137SRobert Mustacchi elf_errmsg(elf_errno())); 191*7fd79137SRobert Mustacchi 192*7fd79137SRobert Mustacchi strsect.cts_name = elf_strptr(elf, ehdr.e_shstrndx, 193*7fd79137SRobert Mustacchi strhdr.sh_name); 194*7fd79137SRobert Mustacchi strsect.cts_type = strhdr.sh_type; 195*7fd79137SRobert Mustacchi strsect.cts_flags = strhdr.sh_flags; 196*7fd79137SRobert Mustacchi strsect.cts_size = strhdr.sh_size; 197*7fd79137SRobert Mustacchi strsect.cts_entsize = strhdr.sh_entsize; 198*7fd79137SRobert Mustacchi strsect.cts_offset = (off64_t)strhdr.sh_offset; 199*7fd79137SRobert Mustacchi 200*7fd79137SRobert Mustacchi sym_data = elf_getdata(scn, NULL); 201*7fd79137SRobert Mustacchi if (sym_data == NULL) 202*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to get ELF CTF " 203*7fd79137SRobert Mustacchi "data section for %s: %s\n", name, 204*7fd79137SRobert Mustacchi elf_errmsg(elf_errno())); 205*7fd79137SRobert Mustacchi symsect.cts_data = sym_data->d_buf; 206*7fd79137SRobert Mustacchi 207*7fd79137SRobert Mustacchi str_data = elf_getdata(strscn, NULL); 208*7fd79137SRobert Mustacchi if (str_data == NULL) 209*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to get ELF CTF " 210*7fd79137SRobert Mustacchi "data section for %s: %s\n", name, 211*7fd79137SRobert Mustacchi elf_errmsg(elf_errno())); 212*7fd79137SRobert Mustacchi strsect.cts_data = str_data->d_buf; 213*7fd79137SRobert Mustacchi } 214*7fd79137SRobert Mustacchi } 215*7fd79137SRobert Mustacchi 216*7fd79137SRobert Mustacchi if (ctfsect.cts_type == SHT_NULL) { 217*7fd79137SRobert Mustacchi if (ctfmerge_expect_ctf(name, elf) == B_FALSE) 218*7fd79137SRobert Mustacchi return; 219*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to open %s: %s\n", name, 220*7fd79137SRobert Mustacchi ctf_errmsg(ECTF_NOCTFDATA)); 221*7fd79137SRobert Mustacchi } 222*7fd79137SRobert Mustacchi 223*7fd79137SRobert Mustacchi if (symsect.cts_type != SHT_NULL && strsect.cts_type != SHT_NULL) { 224*7fd79137SRobert Mustacchi fp = ctf_bufopen(&ctfsect, &symsect, &strsect, &err); 225*7fd79137SRobert Mustacchi } else { 226*7fd79137SRobert Mustacchi fp = ctf_bufopen(&ctfsect, NULL, NULL, &err); 227*7fd79137SRobert Mustacchi } 228*7fd79137SRobert Mustacchi 229*7fd79137SRobert Mustacchi if (fp == NULL) { 230*7fd79137SRobert Mustacchi if (ctfmerge_expect_ctf(name, elf) == B_TRUE) { 231*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to open file %s: %s\n", 232*7fd79137SRobert Mustacchi name, ctf_errmsg(err)); 233*7fd79137SRobert Mustacchi } 234*7fd79137SRobert Mustacchi } else { 235*7fd79137SRobert Mustacchi if ((err = ctf_merge_add(cmh, fp)) != 0) { 236*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to add input %s: %s\n", 237*7fd79137SRobert Mustacchi name, ctf_errmsg(err)); 238*7fd79137SRobert Mustacchi } 239*7fd79137SRobert Mustacchi g_nctf++; 240*7fd79137SRobert Mustacchi } 241*7fd79137SRobert Mustacchi } 242*7fd79137SRobert Mustacchi 243*7fd79137SRobert Mustacchi static void 244*7fd79137SRobert Mustacchi ctfmerge_read_archive(const char *name, int fd, Elf *elf, 245*7fd79137SRobert Mustacchi ctf_merge_t *cmh) 246*7fd79137SRobert Mustacchi { 247*7fd79137SRobert Mustacchi Elf *aelf; 248*7fd79137SRobert Mustacchi Elf_Cmd cmd = ELF_C_READ; 249*7fd79137SRobert Mustacchi int cursec = 1; 250*7fd79137SRobert Mustacchi char *nname; 251*7fd79137SRobert Mustacchi 252*7fd79137SRobert Mustacchi while ((aelf = elf_begin(fd, cmd, elf)) != NULL) { 253*7fd79137SRobert Mustacchi Elf_Arhdr *arhdr; 254*7fd79137SRobert Mustacchi boolean_t leakelf = B_FALSE; 255*7fd79137SRobert Mustacchi 256*7fd79137SRobert Mustacchi if ((arhdr = elf_getarhdr(aelf)) == NULL) 257*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to get archive header %d for " 258*7fd79137SRobert Mustacchi "%s: %s\n", cursec, name, elf_errmsg(elf_errno())); 259*7fd79137SRobert Mustacchi 260*7fd79137SRobert Mustacchi if (*(arhdr->ar_name) == '/') 261*7fd79137SRobert Mustacchi goto next; 262*7fd79137SRobert Mustacchi 263*7fd79137SRobert Mustacchi if (asprintf(&nname, "%s.%s.%d", name, arhdr->ar_name, 264*7fd79137SRobert Mustacchi cursec) < 0) 265*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to allocate memory for archive " 266*7fd79137SRobert Mustacchi "%d of file %s\n", cursec, name); 267*7fd79137SRobert Mustacchi 268*7fd79137SRobert Mustacchi switch (elf_kind(aelf)) { 269*7fd79137SRobert Mustacchi case ELF_K_AR: 270*7fd79137SRobert Mustacchi ctfmerge_read_archive(nname, fd, aelf, cmh); 271*7fd79137SRobert Mustacchi free(nname); 272*7fd79137SRobert Mustacchi break; 273*7fd79137SRobert Mustacchi case ELF_K_ELF: 274*7fd79137SRobert Mustacchi ctfmerge_elfopen(nname, aelf, cmh); 275*7fd79137SRobert Mustacchi free(nname); 276*7fd79137SRobert Mustacchi leakelf = B_TRUE; 277*7fd79137SRobert Mustacchi break; 278*7fd79137SRobert Mustacchi default: 279*7fd79137SRobert Mustacchi ctfmerge_fatal("unknown elf kind (%d) in archive %d " 280*7fd79137SRobert Mustacchi "for %s\n", elf_kind(aelf), cursec, name); 281*7fd79137SRobert Mustacchi } 282*7fd79137SRobert Mustacchi 283*7fd79137SRobert Mustacchi next: 284*7fd79137SRobert Mustacchi cmd = elf_next(aelf); 285*7fd79137SRobert Mustacchi if (leakelf == B_FALSE) 286*7fd79137SRobert Mustacchi (void) elf_end(aelf); 287*7fd79137SRobert Mustacchi cursec++; 288*7fd79137SRobert Mustacchi } 289*7fd79137SRobert Mustacchi } 290*7fd79137SRobert Mustacchi 291*7fd79137SRobert Mustacchi static void 292*7fd79137SRobert Mustacchi ctfmerge_usage(const char *fmt, ...) 293*7fd79137SRobert Mustacchi { 294*7fd79137SRobert Mustacchi if (fmt != NULL) { 295*7fd79137SRobert Mustacchi va_list ap; 296*7fd79137SRobert Mustacchi 297*7fd79137SRobert Mustacchi (void) fprintf(stderr, "%s: ", g_progname); 298*7fd79137SRobert Mustacchi va_start(ap, fmt); 299*7fd79137SRobert Mustacchi (void) vfprintf(stderr, fmt, ap); 300*7fd79137SRobert Mustacchi va_end(ap); 301*7fd79137SRobert Mustacchi } 302*7fd79137SRobert Mustacchi 303*7fd79137SRobert Mustacchi (void) fprintf(stderr, "Usage: %s [-t] [-d uniqfile] [-l label] " 304*7fd79137SRobert Mustacchi "[-L labelenv] [-j nthrs] -o outfile file ...\n" 305*7fd79137SRobert Mustacchi "\n" 306*7fd79137SRobert Mustacchi "\t-d uniquify merged output against uniqfile\n" 307*7fd79137SRobert Mustacchi "\t-j use nthrs threads to perform the merge\n" 308*7fd79137SRobert Mustacchi "\t-l set output container's label to specified value\n" 309*7fd79137SRobert Mustacchi "\t-L set output container's label to value from environment\n" 310*7fd79137SRobert Mustacchi "\t-o file to add CTF data to\n" 311*7fd79137SRobert Mustacchi "\t-t require CTF data from all inputs built from C sources\n", 312*7fd79137SRobert Mustacchi g_progname); 313*7fd79137SRobert Mustacchi } 314*7fd79137SRobert Mustacchi 315*7fd79137SRobert Mustacchi static void 316*7fd79137SRobert Mustacchi ctfmerge_altexec(char **argv) 317*7fd79137SRobert Mustacchi { 318*7fd79137SRobert Mustacchi const char *alt; 319*7fd79137SRobert Mustacchi char *altexec; 320*7fd79137SRobert Mustacchi 321*7fd79137SRobert Mustacchi alt = getenv(CTFMERGE_ALTEXEC); 322*7fd79137SRobert Mustacchi if (alt == NULL || *alt == '\0') 323*7fd79137SRobert Mustacchi return; 324*7fd79137SRobert Mustacchi 325*7fd79137SRobert Mustacchi altexec = strdup(alt); 326*7fd79137SRobert Mustacchi if (altexec == NULL) 327*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to allocate memory for altexec\n"); 328*7fd79137SRobert Mustacchi if (unsetenv(CTFMERGE_ALTEXEC) != 0) 329*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to unset %s from environment: %s\n", 330*7fd79137SRobert Mustacchi CTFMERGE_ALTEXEC, strerror(errno)); 331*7fd79137SRobert Mustacchi 332*7fd79137SRobert Mustacchi (void) execv(altexec, argv); 333*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to execute alternate program %s: %s", 334*7fd79137SRobert Mustacchi altexec, strerror(errno)); 335*7fd79137SRobert Mustacchi } 336*7fd79137SRobert Mustacchi 337*7fd79137SRobert Mustacchi int 338*7fd79137SRobert Mustacchi main(int argc, char *argv[]) 339*7fd79137SRobert Mustacchi { 340*7fd79137SRobert Mustacchi int err, i, c, ofd; 341*7fd79137SRobert Mustacchi uint_t nthreads = CTFMERGE_DEFAULT_NTHREADS; 342*7fd79137SRobert Mustacchi char *tmpfile = NULL, *label = NULL; 343*7fd79137SRobert Mustacchi int wflags = CTF_ELFWRITE_F_COMPRESS; 344*7fd79137SRobert Mustacchi ctf_file_t *ofp; 345*7fd79137SRobert Mustacchi ctf_merge_t *cmh; 346*7fd79137SRobert Mustacchi long argj; 347*7fd79137SRobert Mustacchi char *eptr; 348*7fd79137SRobert Mustacchi 349*7fd79137SRobert Mustacchi g_progname = basename(argv[0]); 350*7fd79137SRobert Mustacchi 351*7fd79137SRobert Mustacchi ctfmerge_altexec(argv); 352*7fd79137SRobert Mustacchi 353*7fd79137SRobert Mustacchi /* 354*7fd79137SRobert Mustacchi * We support a subset of the old CTF merge flags, mostly for 355*7fd79137SRobert Mustacchi * compatability. 356*7fd79137SRobert Mustacchi */ 357*7fd79137SRobert Mustacchi while ((c = getopt(argc, argv, ":d:fgj:l:L:o:t")) != -1) { 358*7fd79137SRobert Mustacchi switch (c) { 359*7fd79137SRobert Mustacchi case 'd': 360*7fd79137SRobert Mustacchi g_unique = optarg; 361*7fd79137SRobert Mustacchi break; 362*7fd79137SRobert Mustacchi case 'f': 363*7fd79137SRobert Mustacchi /* Silently ignored for compatibility */ 364*7fd79137SRobert Mustacchi break; 365*7fd79137SRobert Mustacchi case 'g': 366*7fd79137SRobert Mustacchi /* Silently ignored for compatibility */ 367*7fd79137SRobert Mustacchi break; 368*7fd79137SRobert Mustacchi case 'j': 369*7fd79137SRobert Mustacchi errno = 0; 370*7fd79137SRobert Mustacchi argj = strtol(optarg, &eptr, 10); 371*7fd79137SRobert Mustacchi if (errno != 0 || argj == LONG_MAX || 372*7fd79137SRobert Mustacchi argj > 1024 || *eptr != '\0') { 373*7fd79137SRobert Mustacchi ctfmerge_fatal("invalid argument for -j: %s\n", 374*7fd79137SRobert Mustacchi optarg); 375*7fd79137SRobert Mustacchi } 376*7fd79137SRobert Mustacchi nthreads = (uint_t)argj; 377*7fd79137SRobert Mustacchi break; 378*7fd79137SRobert Mustacchi case 'l': 379*7fd79137SRobert Mustacchi label = optarg; 380*7fd79137SRobert Mustacchi break; 381*7fd79137SRobert Mustacchi case 'L': 382*7fd79137SRobert Mustacchi label = getenv(optarg); 383*7fd79137SRobert Mustacchi break; 384*7fd79137SRobert Mustacchi case 'o': 385*7fd79137SRobert Mustacchi g_outfile = optarg; 386*7fd79137SRobert Mustacchi break; 387*7fd79137SRobert Mustacchi case 't': 388*7fd79137SRobert Mustacchi g_req = B_TRUE; 389*7fd79137SRobert Mustacchi break; 390*7fd79137SRobert Mustacchi case ':': 391*7fd79137SRobert Mustacchi ctfmerge_usage("Option -%c requires an operand\n", 392*7fd79137SRobert Mustacchi optopt); 393*7fd79137SRobert Mustacchi return (CTFMERGE_USAGE); 394*7fd79137SRobert Mustacchi case '?': 395*7fd79137SRobert Mustacchi ctfmerge_usage("Unknown option: -%c\n", optopt); 396*7fd79137SRobert Mustacchi return (CTFMERGE_USAGE); 397*7fd79137SRobert Mustacchi } 398*7fd79137SRobert Mustacchi } 399*7fd79137SRobert Mustacchi 400*7fd79137SRobert Mustacchi if (g_outfile == NULL) { 401*7fd79137SRobert Mustacchi ctfmerge_usage("missing required -o output file\n"); 402*7fd79137SRobert Mustacchi return (CTFMERGE_USAGE); 403*7fd79137SRobert Mustacchi } 404*7fd79137SRobert Mustacchi 405*7fd79137SRobert Mustacchi (void) elf_version(EV_CURRENT); 406*7fd79137SRobert Mustacchi 407*7fd79137SRobert Mustacchi /* 408*7fd79137SRobert Mustacchi * Obviously this isn't atomic, but at least gives us a good starting 409*7fd79137SRobert Mustacchi * point. 410*7fd79137SRobert Mustacchi */ 411*7fd79137SRobert Mustacchi if ((ofd = open(g_outfile, O_RDWR)) < 0) 412*7fd79137SRobert Mustacchi ctfmerge_fatal("cannot open output file %s: %s\n", g_outfile, 413*7fd79137SRobert Mustacchi strerror(errno)); 414*7fd79137SRobert Mustacchi 415*7fd79137SRobert Mustacchi argc -= optind; 416*7fd79137SRobert Mustacchi argv += optind; 417*7fd79137SRobert Mustacchi 418*7fd79137SRobert Mustacchi if (argc < 1) { 419*7fd79137SRobert Mustacchi ctfmerge_usage("no input files specified"); 420*7fd79137SRobert Mustacchi return (CTFMERGE_USAGE); 421*7fd79137SRobert Mustacchi } 422*7fd79137SRobert Mustacchi 423*7fd79137SRobert Mustacchi cmh = ctf_merge_init(ofd, &err); 424*7fd79137SRobert Mustacchi if (cmh == NULL) 425*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to create merge handle: %s\n", 426*7fd79137SRobert Mustacchi ctf_errmsg(err)); 427*7fd79137SRobert Mustacchi 428*7fd79137SRobert Mustacchi if ((err = ctf_merge_set_nthreads(cmh, nthreads)) != 0) 429*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to set parallelism to %u: %s\n", 430*7fd79137SRobert Mustacchi nthreads, ctf_errmsg(err)); 431*7fd79137SRobert Mustacchi 432*7fd79137SRobert Mustacchi for (i = 0; i < argc; i++) { 433*7fd79137SRobert Mustacchi ctf_file_t *ifp; 434*7fd79137SRobert Mustacchi int fd; 435*7fd79137SRobert Mustacchi 436*7fd79137SRobert Mustacchi if ((fd = open(argv[i], O_RDONLY)) < 0) 437*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to open file %s: %s\n", 438*7fd79137SRobert Mustacchi argv[i], strerror(errno)); 439*7fd79137SRobert Mustacchi ifp = ctf_fdopen(fd, &err); 440*7fd79137SRobert Mustacchi if (ifp == NULL) { 441*7fd79137SRobert Mustacchi Elf *e; 442*7fd79137SRobert Mustacchi 443*7fd79137SRobert Mustacchi if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 444*7fd79137SRobert Mustacchi (void) close(fd); 445*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to open %s: %s\n", 446*7fd79137SRobert Mustacchi argv[i], ctf_errmsg(err)); 447*7fd79137SRobert Mustacchi } 448*7fd79137SRobert Mustacchi 449*7fd79137SRobert Mustacchi /* 450*7fd79137SRobert Mustacchi * It's an ELF file, check if we have an archive or if 451*7fd79137SRobert Mustacchi * we're expecting CTF here. 452*7fd79137SRobert Mustacchi */ 453*7fd79137SRobert Mustacchi switch (elf_kind(e)) { 454*7fd79137SRobert Mustacchi case ELF_K_AR: 455*7fd79137SRobert Mustacchi break; 456*7fd79137SRobert Mustacchi case ELF_K_ELF: 457*7fd79137SRobert Mustacchi if (ctfmerge_expect_ctf(argv[i], e) == B_TRUE) { 458*7fd79137SRobert Mustacchi (void) elf_end(e); 459*7fd79137SRobert Mustacchi (void) close(fd); 460*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to " 461*7fd79137SRobert Mustacchi "open %s: file was built from C " 462*7fd79137SRobert Mustacchi "sources, but missing CTF\n", 463*7fd79137SRobert Mustacchi argv[i]); 464*7fd79137SRobert Mustacchi } 465*7fd79137SRobert Mustacchi (void) elf_end(e); 466*7fd79137SRobert Mustacchi (void) close(fd); 467*7fd79137SRobert Mustacchi continue; 468*7fd79137SRobert Mustacchi default: 469*7fd79137SRobert Mustacchi (void) elf_end(e); 470*7fd79137SRobert Mustacchi (void) close(fd); 471*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to open %s: " 472*7fd79137SRobert Mustacchi "unsupported ELF file type", argv[i]); 473*7fd79137SRobert Mustacchi } 474*7fd79137SRobert Mustacchi 475*7fd79137SRobert Mustacchi ctfmerge_read_archive(argv[i], fd, e, cmh); 476*7fd79137SRobert Mustacchi (void) elf_end(e); 477*7fd79137SRobert Mustacchi (void) close(fd); 478*7fd79137SRobert Mustacchi continue; 479*7fd79137SRobert Mustacchi } 480*7fd79137SRobert Mustacchi (void) close(fd); 481*7fd79137SRobert Mustacchi if ((err = ctf_merge_add(cmh, ifp)) != 0) 482*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to add input %s: %s\n", 483*7fd79137SRobert Mustacchi argv[i], ctf_errmsg(err)); 484*7fd79137SRobert Mustacchi g_nctf++; 485*7fd79137SRobert Mustacchi } 486*7fd79137SRobert Mustacchi 487*7fd79137SRobert Mustacchi if (g_nctf == 0) { 488*7fd79137SRobert Mustacchi ctf_merge_fini(cmh); 489*7fd79137SRobert Mustacchi return (0); 490*7fd79137SRobert Mustacchi } 491*7fd79137SRobert Mustacchi 492*7fd79137SRobert Mustacchi if (g_unique != NULL) { 493*7fd79137SRobert Mustacchi ctf_file_t *ufp; 494*7fd79137SRobert Mustacchi char *base; 495*7fd79137SRobert Mustacchi 496*7fd79137SRobert Mustacchi ufp = ctf_open(g_unique, &err); 497*7fd79137SRobert Mustacchi if (ufp == NULL) { 498*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to open uniquify file %s: %s\n", 499*7fd79137SRobert Mustacchi g_unique, ctf_errmsg(err)); 500*7fd79137SRobert Mustacchi } 501*7fd79137SRobert Mustacchi 502*7fd79137SRobert Mustacchi base = basename(g_unique); 503*7fd79137SRobert Mustacchi (void) ctf_merge_uniquify(cmh, ufp, base); 504*7fd79137SRobert Mustacchi } 505*7fd79137SRobert Mustacchi 506*7fd79137SRobert Mustacchi if (label != NULL) { 507*7fd79137SRobert Mustacchi if ((err = ctf_merge_label(cmh, label)) != 0) 508*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to add label %s: %s\n", label, 509*7fd79137SRobert Mustacchi ctf_errmsg(err)); 510*7fd79137SRobert Mustacchi } 511*7fd79137SRobert Mustacchi 512*7fd79137SRobert Mustacchi err = ctf_merge_merge(cmh, &ofp); 513*7fd79137SRobert Mustacchi if (err != 0) 514*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to merge types: %s\n", ctf_errmsg(err)); 515*7fd79137SRobert Mustacchi ctf_merge_fini(cmh); 516*7fd79137SRobert Mustacchi 517*7fd79137SRobert Mustacchi if (asprintf(&tmpfile, "%s.ctf", g_outfile) == -1) 518*7fd79137SRobert Mustacchi ctfmerge_fatal("ran out of memory for temporary file name\n"); 519*7fd79137SRobert Mustacchi err = ctf_elfwrite(ofp, g_outfile, tmpfile, wflags); 520*7fd79137SRobert Mustacchi if (err == CTF_ERR) { 521*7fd79137SRobert Mustacchi (void) unlink(tmpfile); 522*7fd79137SRobert Mustacchi free(tmpfile); 523*7fd79137SRobert Mustacchi ctfmerge_fatal("encountered a libctf error: %s!\n", 524*7fd79137SRobert Mustacchi ctf_errmsg(ctf_errno(ofp))); 525*7fd79137SRobert Mustacchi } 526*7fd79137SRobert Mustacchi 527*7fd79137SRobert Mustacchi if (rename(tmpfile, g_outfile) != 0) { 528*7fd79137SRobert Mustacchi (void) unlink(tmpfile); 529*7fd79137SRobert Mustacchi free(tmpfile); 530*7fd79137SRobert Mustacchi ctfmerge_fatal("failed to rename temporary file: %s\n", 531*7fd79137SRobert Mustacchi strerror(errno)); 532*7fd79137SRobert Mustacchi } 533*7fd79137SRobert Mustacchi free(tmpfile); 534*7fd79137SRobert Mustacchi 535*7fd79137SRobert Mustacchi return (CTFMERGE_OK); 536*7fd79137SRobert Mustacchi } 537