~ubuntu-branches/ubuntu/trusty/ctfutils/trusty-proposed

« back to all changes in this revision

Viewing changes to cddl/contrib/opensolaris/tools/ctf/cvt/output.c

  • Committer: Package Import Robot
  • Author(s): Robert Millan
  • Date: 2013-11-09 17:07:06 UTC
  • Revision ID: package-import@ubuntu.com-20131109170706-kacr6nvpkbhxsk81
Tags: upstream-9.2
ImportĀ upstreamĀ versionĀ 9.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 
23
 * Use is subject to license terms.
 
24
 */
 
25
 
 
26
#pragma ident   "%Z%%M% %I%     %E% SMI"
 
27
 
 
28
/*
 
29
 * Routines for preparing tdata trees for conversion into CTF data, and
 
30
 * for placing the resulting data into an output file.
 
31
 */
 
32
 
 
33
#include <stdio.h>
 
34
#include <stdlib.h>
 
35
#include <strings.h>
 
36
#include <sys/types.h>
 
37
#include <sys/stat.h>
 
38
#include <fcntl.h>
 
39
#include <libelf.h>
 
40
#include <gelf.h>
 
41
#include <unistd.h>
 
42
 
 
43
#include "ctftools.h"
 
44
#include "list.h"
 
45
#include "memory.h"
 
46
#include "traverse.h"
 
47
#include "symbol.h"
 
48
 
 
49
typedef struct iidesc_match {
 
50
        int iim_fuzzy;
 
51
        iidesc_t *iim_ret;
 
52
        char *iim_name;
 
53
        char *iim_file;
 
54
        uchar_t iim_bind;
 
55
} iidesc_match_t;
 
56
 
 
57
static int
 
58
burst_iitypes(void *data, void *arg)
 
59
{
 
60
        iidesc_t *ii = data;
 
61
        iiburst_t *iiburst = arg;
 
62
 
 
63
        switch (ii->ii_type) {
 
64
        case II_GFUN:
 
65
        case II_SFUN:
 
66
        case II_GVAR:
 
67
        case II_SVAR:
 
68
                if (!(ii->ii_flags & IIDESC_F_USED))
 
69
                        return (0);
 
70
                break;
 
71
        default:
 
72
                break;
 
73
        }
 
74
 
 
75
        ii->ii_dtype->t_flags |= TDESC_F_ISROOT;
 
76
        (void) iitraverse_td(ii, iiburst->iib_tdtd);
 
77
        return (1);
 
78
}
 
79
 
 
80
/*ARGSUSED1*/
 
81
static int
 
82
save_type_by_id(tdesc_t *tdp, tdesc_t **tdpp __unused, void *private)
 
83
{
 
84
        iiburst_t *iiburst = private;
 
85
 
 
86
        /*
 
87
         * Doing this on every node is horribly inefficient, but given that
 
88
         * we may be suppressing some types, we can't trust nextid in the
 
89
         * tdata_t.
 
90
         */
 
91
        if (tdp->t_id > iiburst->iib_maxtypeid)
 
92
                iiburst->iib_maxtypeid = tdp->t_id;
 
93
 
 
94
        slist_add(&iiburst->iib_types, tdp, tdesc_idcmp);
 
95
 
 
96
        return (1);
 
97
}
 
98
 
 
99
static tdtrav_cb_f burst_types_cbs[] = {
 
100
        NULL,
 
101
        save_type_by_id,        /* intrinsic */
 
102
        save_type_by_id,        /* pointer */
 
103
        save_type_by_id,        /* array */
 
104
        save_type_by_id,        /* function */
 
105
        save_type_by_id,        /* struct */
 
106
        save_type_by_id,        /* union */
 
107
        save_type_by_id,        /* enum */
 
108
        save_type_by_id,        /* forward */
 
109
        save_type_by_id,        /* typedef */
 
110
        tdtrav_assert,          /* typedef_unres */
 
111
        save_type_by_id,        /* volatile */
 
112
        save_type_by_id,        /* const */
 
113
        save_type_by_id         /* restrict */
 
114
};
 
115
 
 
116
 
 
117
static iiburst_t *
 
118
iiburst_new(tdata_t *td, int max)
 
119
{
 
120
        iiburst_t *iiburst = xcalloc(sizeof (iiburst_t));
 
121
        iiburst->iib_td = td;
 
122
        iiburst->iib_funcs = xcalloc(sizeof (iidesc_t *) * max);
 
123
        iiburst->iib_nfuncs = 0;
 
124
        iiburst->iib_objts = xcalloc(sizeof (iidesc_t *) * max);
 
125
        iiburst->iib_nobjts = 0;
 
126
        return (iiburst);
 
127
}
 
128
 
 
129
static void
 
130
iiburst_types(iiburst_t *iiburst)
 
131
{
 
132
        tdtrav_data_t tdtd;
 
133
 
 
134
        tdtrav_init(&tdtd, &iiburst->iib_td->td_curvgen, NULL, burst_types_cbs,
 
135
            NULL, (void *)iiburst);
 
136
 
 
137
        iiburst->iib_tdtd = &tdtd;
 
138
 
 
139
        (void) hash_iter(iiburst->iib_td->td_iihash, burst_iitypes, iiburst);
 
140
}
 
141
 
 
142
static void
 
143
iiburst_free(iiburst_t *iiburst)
 
144
{
 
145
        free(iiburst->iib_funcs);
 
146
        free(iiburst->iib_objts);
 
147
        list_free(iiburst->iib_types, NULL, NULL);
 
148
        free(iiburst);
 
149
}
 
150
 
 
151
/*
 
152
 * See if this iidesc matches the ELF symbol data we pass in.
 
153
 *
 
154
 * A fuzzy match is where we have a local symbol matching the name of a
 
155
 * global type description. This is common when a mapfile is used for a
 
156
 * DSO, but we don't accept it by default.
 
157
 *
 
158
 * A weak fuzzy match is when a weak symbol was resolved and matched to
 
159
 * a global type description.
 
160
 */
 
161
static int
 
162
matching_iidesc(void *arg1, void *arg2)
 
163
{
 
164
        iidesc_t *iidesc = arg1;
 
165
        iidesc_match_t *match = arg2;
 
166
        if (streq(iidesc->ii_name, match->iim_name) == 0)
 
167
                return (0);
 
168
 
 
169
        switch (iidesc->ii_type) {
 
170
        case II_GFUN:
 
171
        case II_GVAR:
 
172
                if (match->iim_bind == STB_GLOBAL) {
 
173
                        match->iim_ret = iidesc;
 
174
                        return (-1);
 
175
                } else if (match->iim_fuzzy && match->iim_ret == NULL) {
 
176
                        match->iim_ret = iidesc;
 
177
                        /* continue to look for strong match */
 
178
                        return (0);
 
179
                }
 
180
                break;
 
181
        case II_SFUN:
 
182
        case II_SVAR:
 
183
                if (match->iim_bind == STB_LOCAL &&
 
184
                    match->iim_file != NULL &&
 
185
                    streq(iidesc->ii_owner, match->iim_file)) {
 
186
                        match->iim_ret = iidesc;
 
187
                        return (-1);
 
188
                }
 
189
                break;
 
190
        default:
 
191
                break;
 
192
        }
 
193
        return (0);
 
194
}
 
195
 
 
196
static iidesc_t *
 
197
find_iidesc(tdata_t *td, iidesc_match_t *match)
 
198
{
 
199
        match->iim_ret = NULL;
 
200
        iter_iidescs_by_name(td, match->iim_name,
 
201
            matching_iidesc, match);
 
202
        return (match->iim_ret);
 
203
}
 
204
 
 
205
/*
 
206
 * If we have a weak symbol, attempt to find the strong symbol it will
 
207
 * resolve to.  Note: the code where this actually happens is in
 
208
 * sym_process() in cmd/sgs/libld/common/syms.c
 
209
 *
 
210
 * Finding the matching symbol is unfortunately not trivial.  For a
 
211
 * symbol to be a candidate, it must:
 
212
 *
 
213
 * - have the same type (function, object)
 
214
 * - have the same value (address)
 
215
 * - have the same size
 
216
 * - not be another weak symbol
 
217
 * - belong to the same section (checked via section index)
 
218
 *
 
219
 * If such a candidate is global, then we assume we've found it.  The
 
220
 * linker generates the symbol table such that the curfile might be
 
221
 * incorrect; this is OK for global symbols, since find_iidesc() doesn't
 
222
 * need to check for the source file for the symbol.
 
223
 *
 
224
 * We might have found a strong local symbol, where the curfile is
 
225
 * accurate and matches that of the weak symbol.  We assume this is a
 
226
 * reasonable match.
 
227
 *
 
228
 * If we've got a local symbol with a non-matching curfile, there are
 
229
 * two possibilities.  Either this is a completely different symbol, or
 
230
 * it's a once-global symbol that was scoped to local via a mapfile.  In
 
231
 * the latter case, curfile is likely inaccurate since the linker does
 
232
 * not preserve the needed curfile in the order of the symbol table (see
 
233
 * the comments about locally scoped symbols in libld's update_osym()).
 
234
 * As we can't tell this case from the former one, we use this symbol
 
235
 * iff no other matching symbol is found.
 
236
 *
 
237
 * What we really need here is a SUNW section containing weak<->strong
 
238
 * mappings that we can consume.
 
239
 */
 
240
static int
 
241
check_for_weak(GElf_Sym *weak, char const *weakfile,
 
242
    Elf_Data *data, int nent, Elf_Data *strdata,
 
243
    GElf_Sym *retsym, char **curfilep)
 
244
{
 
245
        char *curfile = NULL;
 
246
        char *tmpfile1 = NULL;
 
247
        GElf_Sym tmpsym;
 
248
        int candidate = 0;
 
249
        int i;
 
250
        tmpsym.st_info = 0;
 
251
        tmpsym.st_name = 0;
 
252
 
 
253
        if (GELF_ST_BIND(weak->st_info) != STB_WEAK)
 
254
                return (0);
 
255
 
 
256
        for (i = 0; i < nent; i++) {
 
257
                GElf_Sym sym;
 
258
                uchar_t type;
 
259
 
 
260
                if (gelf_getsym(data, i, &sym) == NULL)
 
261
                        continue;
 
262
 
 
263
                type = GELF_ST_TYPE(sym.st_info);
 
264
 
 
265
                if (type == STT_FILE)
 
266
                        curfile = (char *)strdata->d_buf + sym.st_name;
 
267
 
 
268
                if (GELF_ST_TYPE(weak->st_info) != type ||
 
269
                    weak->st_value != sym.st_value)
 
270
                        continue;
 
271
 
 
272
                if (weak->st_size != sym.st_size)
 
273
                        continue;
 
274
 
 
275
                if (GELF_ST_BIND(sym.st_info) == STB_WEAK)
 
276
                        continue;
 
277
 
 
278
                if (sym.st_shndx != weak->st_shndx)
 
279
                        continue;
 
280
 
 
281
                if (GELF_ST_BIND(sym.st_info) == STB_LOCAL &&
 
282
                    (curfile == NULL || weakfile == NULL ||
 
283
                    strcmp(curfile, weakfile) != 0)) {
 
284
                        candidate = 1;
 
285
                        tmpfile1 = curfile;
 
286
                        tmpsym = sym;
 
287
                        continue;
 
288
                }
 
289
 
 
290
                *curfilep = curfile;
 
291
                *retsym = sym;
 
292
                return (1);
 
293
        }
 
294
 
 
295
        if (candidate) {
 
296
                *curfilep = tmpfile1;
 
297
                *retsym = tmpsym;
 
298
                return (1);
 
299
        }
 
300
 
 
301
        return (0);
 
302
}
 
303
 
 
304
/*
 
305
 * When we've found the underlying symbol's type description
 
306
 * for a weak symbol, we need to copy it and rename it to match
 
307
 * the weak symbol. We also need to add it to the td so it's
 
308
 * handled along with the others later.
 
309
 */
 
310
static iidesc_t *
 
311
copy_from_strong(tdata_t *td, GElf_Sym *sym, iidesc_t *strongdesc,
 
312
    const char *weakname, const char *weakfile)
 
313
{
 
314
        iidesc_t *new = iidesc_dup_rename(strongdesc, weakname, weakfile);
 
315
        uchar_t type = GELF_ST_TYPE(sym->st_info);
 
316
 
 
317
        switch (type) {
 
318
        case STT_OBJECT:
 
319
                new->ii_type = II_GVAR;
 
320
                break;
 
321
        case STT_FUNC:
 
322
                new->ii_type = II_GFUN;
 
323
                break;
 
324
        }
 
325
 
 
326
        hash_add(td->td_iihash, new);
 
327
 
 
328
        return (new);
 
329
}
 
330
 
 
331
/*
 
332
 * Process the symbol table of the output file, associating each symbol
 
333
 * with a type description if possible, and sorting them into functions
 
334
 * and data, maintaining symbol table order.
 
335
 */
 
336
static iiburst_t *
 
337
sort_iidescs(Elf *elf, const char *file, tdata_t *td, int fuzzymatch,
 
338
    int dynsym)
 
339
{
 
340
        iiburst_t *iiburst;
 
341
        Elf_Scn *scn;
 
342
        GElf_Shdr shdr;
 
343
        Elf_Data *data, *strdata;
 
344
        int i, stidx;
 
345
        int nent;
 
346
        iidesc_match_t match;
 
347
 
 
348
        match.iim_fuzzy = fuzzymatch;
 
349
        match.iim_file = NULL;
 
350
 
 
351
        if ((stidx = findelfsecidx(elf, file,
 
352
            dynsym ? ".dynsym" : ".symtab")) < 0)
 
353
                terminate("%s: Can't open symbol table\n", file);
 
354
        scn = elf_getscn(elf, stidx);
 
355
        data = elf_getdata(scn, NULL);
 
356
        gelf_getshdr(scn, &shdr);
 
357
        nent = shdr.sh_size / shdr.sh_entsize;
 
358
 
 
359
        scn = elf_getscn(elf, shdr.sh_link);
 
360
        strdata = elf_getdata(scn, NULL);
 
361
 
 
362
        iiburst = iiburst_new(td, nent);
 
363
 
 
364
        for (i = 0; i < nent; i++) {
 
365
                GElf_Sym sym;
 
366
                char *bname;
 
367
                iidesc_t **tolist;
 
368
                GElf_Sym ssym;
 
369
                iidesc_match_t smatch;
 
370
                int *curr;
 
371
                iidesc_t *iidesc;
 
372
 
 
373
                if (gelf_getsym(data, i, &sym) == NULL)
 
374
                        elfterminate(file, "Couldn't read symbol %d", i);
 
375
 
 
376
                match.iim_name = (char *)strdata->d_buf + sym.st_name;
 
377
                match.iim_bind = GELF_ST_BIND(sym.st_info);
 
378
 
 
379
                switch (GELF_ST_TYPE(sym.st_info)) {
 
380
                case STT_FILE:
 
381
                        bname = strrchr(match.iim_name, '/');
 
382
                        match.iim_file = bname == NULL ? match.iim_name : bname + 1;
 
383
                        continue;
 
384
                case STT_OBJECT:
 
385
                        tolist = iiburst->iib_objts;
 
386
                        curr = &iiburst->iib_nobjts;
 
387
                        break;
 
388
                case STT_FUNC:
 
389
                        tolist = iiburst->iib_funcs;
 
390
                        curr = &iiburst->iib_nfuncs;
 
391
                        break;
 
392
                default:
 
393
                        continue;
 
394
                }
 
395
 
 
396
                if (ignore_symbol(&sym, match.iim_name))
 
397
                        continue;
 
398
 
 
399
                iidesc = find_iidesc(td, &match);
 
400
 
 
401
                if (iidesc != NULL) {
 
402
                        tolist[*curr] = iidesc;
 
403
                        iidesc->ii_flags |= IIDESC_F_USED;
 
404
                        (*curr)++;
 
405
                        continue;
 
406
                }
 
407
 
 
408
                if (!check_for_weak(&sym, match.iim_file, data, nent, strdata,
 
409
                    &ssym, &smatch.iim_file)) {
 
410
                        (*curr)++;
 
411
                        continue;
 
412
                }
 
413
 
 
414
                smatch.iim_fuzzy = fuzzymatch;
 
415
                smatch.iim_name = (char *)strdata->d_buf + ssym.st_name;
 
416
                smatch.iim_bind = GELF_ST_BIND(ssym.st_info);
 
417
 
 
418
                debug(3, "Weak symbol %s resolved to %s\n", match.iim_name,
 
419
                    smatch.iim_name);
 
420
 
 
421
                iidesc = find_iidesc(td, &smatch);
 
422
 
 
423
                if (iidesc != NULL) {
 
424
                        tolist[*curr] = copy_from_strong(td, &sym,
 
425
                            iidesc, match.iim_name, match.iim_file);
 
426
                        tolist[*curr]->ii_flags |= IIDESC_F_USED;
 
427
                }
 
428
 
 
429
                (*curr)++;
 
430
        }
 
431
 
 
432
        /*
 
433
         * Stabs are generated for every function declared in a given C source
 
434
         * file.  When converting an object file, we may encounter a stab that
 
435
         * has no symbol table entry because the optimizer has decided to omit
 
436
         * that item (for example, an unreferenced static function).  We may
 
437
         * see iidescs that do not have an associated symtab entry, and so
 
438
         * we do not write records for those functions into the CTF data.
 
439
         * All others get marked as a root by this function.
 
440
         */
 
441
        iiburst_types(iiburst);
 
442
 
 
443
        /*
 
444
         * By not adding some of the functions and/or objects, we may have
 
445
         * caused some types that were referenced solely by those
 
446
         * functions/objects to be suppressed.  This could cause a label,
 
447
         * generated prior to the evisceration, to be incorrect.  Find the
 
448
         * highest type index, and change the label indicies to be no higher
 
449
         * than this value.
 
450
         */
 
451
        tdata_label_newmax(td, iiburst->iib_maxtypeid);
 
452
 
 
453
        return (iiburst);
 
454
}
 
455
 
 
456
static void
 
457
write_file(Elf *src, const char *srcname, Elf *dst, const char *dstname,
 
458
    caddr_t ctfdata, size_t ctfsize, int flags)
 
459
{
 
460
        GElf_Ehdr sehdr, dehdr;
 
461
        Elf_Scn *sscn, *dscn;
 
462
        Elf_Data *sdata, *ddata;
 
463
        GElf_Shdr shdr;
 
464
        GElf_Word symtab_type;
 
465
        int symtab_idx = -1;
 
466
        off_t new_offset = 0;
 
467
        off_t ctfnameoff = 0;
 
468
        int dynsym = (flags & CTF_USE_DYNSYM);
 
469
        int keep_stabs = (flags & CTF_KEEP_STABS);
 
470
        int *secxlate;
 
471
        int srcidx, dstidx;
 
472
        int curnmoff = 0;
 
473
        int changing = 0;
 
474
        int pad;
 
475
        int i;
 
476
 
 
477
        if (gelf_newehdr(dst, gelf_getclass(src)) == NULL)
 
478
                elfterminate(dstname, "Cannot copy ehdr to temp file");
 
479
        gelf_getehdr(src, &sehdr);
 
480
        memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr));
 
481
        gelf_update_ehdr(dst, &dehdr);
 
482
 
 
483
        symtab_type = dynsym ? SHT_DYNSYM : SHT_SYMTAB;
 
484
 
 
485
        /*
 
486
         * Neither the existing stab sections nor the SUNW_ctf sections (new or
 
487
         * existing) are SHF_ALLOC'd, so they won't be in areas referenced by
 
488
         * program headers.  As such, we can just blindly copy the program
 
489
         * headers from the existing file to the new file.
 
490
         */
 
491
        if (sehdr.e_phnum != 0) {
 
492
                (void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT);
 
493
                if (gelf_newphdr(dst, sehdr.e_phnum) == NULL)
 
494
                        elfterminate(dstname, "Cannot make phdrs in temp file");
 
495
 
 
496
                for (i = 0; i < sehdr.e_phnum; i++) {
 
497
                        GElf_Phdr phdr;
 
498
 
 
499
                        gelf_getphdr(src, i, &phdr);
 
500
                        gelf_update_phdr(dst, i, &phdr);
 
501
                }
 
502
        }
 
503
 
 
504
        secxlate = xmalloc(sizeof (int) * sehdr.e_shnum);
 
505
        for (srcidx = dstidx = 0; srcidx < sehdr.e_shnum; srcidx++) {
 
506
                Elf_Scn *scn = elf_getscn(src, srcidx);
 
507
                GElf_Shdr shdr1;
 
508
                char *sname;
 
509
 
 
510
                gelf_getshdr(scn, &shdr1);
 
511
                sname = elf_strptr(src, sehdr.e_shstrndx, shdr1.sh_name);
 
512
                if (sname == NULL) {
 
513
                        elfterminate(srcname, "Can't find string at %u",
 
514
                            shdr1.sh_name);
 
515
                }
 
516
 
 
517
                if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) {
 
518
                        secxlate[srcidx] = -1;
 
519
                } else if (!keep_stabs &&
 
520
                    (strncmp(sname, ".stab", 5) == 0 ||
 
521
                    strncmp(sname, ".debug", 6) == 0 ||
 
522
                    strncmp(sname, ".rel.debug", 10) == 0 ||
 
523
                    strncmp(sname, ".rela.debug", 11) == 0)) {
 
524
                        secxlate[srcidx] = -1;
 
525
                } else if (dynsym && shdr1.sh_type == SHT_SYMTAB) {
 
526
                        /*
 
527
                         * If we're building CTF against the dynsym,
 
528
                         * we'll rip out the symtab so debuggers aren't
 
529
                         * confused.
 
530
                         */
 
531
                        secxlate[srcidx] = -1;
 
532
                } else {
 
533
                        secxlate[srcidx] = dstidx++;
 
534
                        curnmoff += strlen(sname) + 1;
 
535
                }
 
536
 
 
537
                new_offset = (off_t)dehdr.e_phoff;
 
538
        }
 
539
 
 
540
        for (srcidx = 1; srcidx < sehdr.e_shnum; srcidx++) {
 
541
                char *sname;
 
542
 
 
543
                sscn = elf_getscn(src, srcidx);
 
544
                gelf_getshdr(sscn, &shdr);
 
545
 
 
546
                if (secxlate[srcidx] == -1) {
 
547
                        changing = 1;
 
548
                        continue;
 
549
                }
 
550
 
 
551
                dscn = elf_newscn(dst);
 
552
 
 
553
                /*
 
554
                 * If this file has program headers, we need to explicitly lay
 
555
                 * out sections.  If none of the sections prior to this one have
 
556
                 * been removed, then we can just use the existing location.  If
 
557
                 * one or more sections have been changed, then we need to
 
558
                 * adjust this one to avoid holes.
 
559
                 */
 
560
                if (changing && sehdr.e_phnum != 0) {
 
561
                        pad = new_offset % shdr.sh_addralign;
 
562
 
 
563
                        if (pad)
 
564
                                new_offset += shdr.sh_addralign - pad;
 
565
                        shdr.sh_offset = new_offset;
 
566
                }
 
567
 
 
568
                shdr.sh_link = secxlate[shdr.sh_link];
 
569
 
 
570
                if (shdr.sh_type == SHT_REL || shdr.sh_type == SHT_RELA)
 
571
                        shdr.sh_info = secxlate[shdr.sh_info];
 
572
 
 
573
                sname = elf_strptr(src, sehdr.e_shstrndx, shdr.sh_name);
 
574
                if (sname == NULL) {
 
575
                        elfterminate(srcname, "Can't find string at %u",
 
576
                            shdr.sh_name);
 
577
                }
 
578
 
 
579
#if !defined(sun)
 
580
                if (gelf_update_shdr(dscn, &shdr) == 0)
 
581
                        elfterminate(dstname, "Cannot update sect %s", sname);
 
582
#endif
 
583
 
 
584
                if ((sdata = elf_getdata(sscn, NULL)) == NULL)
 
585
                        elfterminate(srcname, "Cannot get sect %s data", sname);
 
586
                if ((ddata = elf_newdata(dscn)) == NULL)
 
587
                        elfterminate(dstname, "Can't make sect %s data", sname);
 
588
#if defined(sun)
 
589
                bcopy(sdata, ddata, sizeof (Elf_Data));
 
590
#else
 
591
                /*
 
592
                 * FreeBSD's Elf_Data has private fields which the
 
593
                 * elf_* routines manage. Simply copying the 
 
594
                 * entire structure corrupts the data. So we need
 
595
                 * to copy the public fields explictly.
 
596
                 */
 
597
                ddata->d_align = sdata->d_align;
 
598
                ddata->d_off = sdata->d_off;
 
599
                ddata->d_size = sdata->d_size;
 
600
                ddata->d_type = sdata->d_type;
 
601
                ddata->d_version = sdata->d_version;
 
602
#endif
 
603
 
 
604
                if (srcidx == sehdr.e_shstrndx) {
 
605
                        char seclen = strlen(CTF_ELF_SCN_NAME);
 
606
 
 
607
                        ddata->d_buf = xmalloc(ddata->d_size + shdr.sh_size +
 
608
                            seclen + 1);
 
609
                        bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
 
610
                        strcpy((caddr_t)ddata->d_buf + shdr.sh_size,
 
611
                            CTF_ELF_SCN_NAME);
 
612
                        ctfnameoff = (off_t)shdr.sh_size;
 
613
                        shdr.sh_size += seclen + 1;
 
614
                        ddata->d_size += seclen + 1;
 
615
 
 
616
                        if (sehdr.e_phnum != 0)
 
617
                                changing = 1;
 
618
                }
 
619
 
 
620
                if (shdr.sh_type == symtab_type && shdr.sh_entsize != 0) {
 
621
                        int nsym = shdr.sh_size / shdr.sh_entsize;
 
622
 
 
623
                        symtab_idx = secxlate[srcidx];
 
624
 
 
625
                        ddata->d_buf = xmalloc(shdr.sh_size);
 
626
                        bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
 
627
 
 
628
                        for (i = 0; i < nsym; i++) {
 
629
                                GElf_Sym sym;
 
630
                                short newscn;
 
631
 
 
632
                                if (gelf_getsym(ddata, i, &sym) == NULL)
 
633
                                        printf("Could not get symbol %d\n",i);
 
634
 
 
635
                                if (sym.st_shndx >= SHN_LORESERVE)
 
636
                                        continue;
 
637
 
 
638
                                if ((newscn = secxlate[sym.st_shndx]) !=
 
639
                                    sym.st_shndx) {
 
640
                                        sym.st_shndx =
 
641
                                            (newscn == -1 ? 1 : newscn);
 
642
 
 
643
                                        gelf_update_sym(ddata, i, &sym);
 
644
                                }
 
645
                        }
 
646
                }
 
647
 
 
648
#if !defined(sun)
 
649
                if (ddata->d_buf == NULL && sdata->d_buf != NULL) {
 
650
                        ddata->d_buf = xmalloc(shdr.sh_size);
 
651
                        bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
 
652
                }
 
653
#endif
 
654
 
 
655
                if (gelf_update_shdr(dscn, &shdr) == 0)
 
656
                        elfterminate(dstname, "Cannot update sect %s", sname);
 
657
 
 
658
                new_offset = (off_t)shdr.sh_offset;
 
659
                if (shdr.sh_type != SHT_NOBITS)
 
660
                        new_offset += shdr.sh_size;
 
661
        }
 
662
 
 
663
        if (symtab_idx == -1) {
 
664
                terminate("%s: Cannot find %s section\n", srcname,
 
665
                    dynsym ? "SHT_DYNSYM" : "SHT_SYMTAB");
 
666
        }
 
667
 
 
668
        /* Add the ctf section */
 
669
        dscn = elf_newscn(dst);
 
670
        gelf_getshdr(dscn, &shdr);
 
671
        shdr.sh_name = ctfnameoff;
 
672
        shdr.sh_type = SHT_PROGBITS;
 
673
        shdr.sh_size = ctfsize;
 
674
        shdr.sh_link = symtab_idx;
 
675
        shdr.sh_addralign = 4;
 
676
        if (changing && sehdr.e_phnum != 0) {
 
677
                pad = new_offset % shdr.sh_addralign;
 
678
 
 
679
                if (pad)
 
680
                        new_offset += shdr.sh_addralign - pad;
 
681
 
 
682
                shdr.sh_offset = new_offset;
 
683
                new_offset += shdr.sh_size;
 
684
        }
 
685
 
 
686
        ddata = elf_newdata(dscn);
 
687
        ddata->d_buf = ctfdata;
 
688
        ddata->d_size = ctfsize;
 
689
        ddata->d_align = shdr.sh_addralign;
 
690
        ddata->d_off = 0;
 
691
 
 
692
        gelf_update_shdr(dscn, &shdr);
 
693
 
 
694
        /* update the section header location */
 
695
        if (sehdr.e_phnum != 0) {
 
696
                size_t align = gelf_fsize(dst, ELF_T_ADDR, 1, EV_CURRENT);
 
697
                size_t r = new_offset % align;
 
698
 
 
699
                if (r)
 
700
                        new_offset += align - r;
 
701
 
 
702
                dehdr.e_shoff = new_offset;
 
703
        }
 
704
 
 
705
        /* commit to disk */
 
706
        dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx];
 
707
        gelf_update_ehdr(dst, &dehdr);
 
708
        if (elf_update(dst, ELF_C_WRITE) < 0)
 
709
                elfterminate(dstname, "Cannot finalize temp file");
 
710
 
 
711
        free(secxlate);
 
712
}
 
713
 
 
714
static caddr_t
 
715
make_ctf_data(tdata_t *td, Elf *elf, const char *file, size_t *lenp, int flags)
 
716
{
 
717
        iiburst_t *iiburst;
 
718
        caddr_t data;
 
719
 
 
720
        iiburst = sort_iidescs(elf, file, td, flags & CTF_FUZZY_MATCH,
 
721
            flags & CTF_USE_DYNSYM);
 
722
        data = ctf_gen(iiburst, lenp, flags & CTF_COMPRESS);
 
723
 
 
724
        iiburst_free(iiburst);
 
725
 
 
726
        return (data);
 
727
}
 
728
 
 
729
void
 
730
write_ctf(tdata_t *td, const char *curname, const char *newname, int flags)
 
731
{
 
732
        struct stat st;
 
733
        Elf *elf = NULL;
 
734
        Elf *telf = NULL;
 
735
        caddr_t data;
 
736
        size_t len;
 
737
        int fd = -1;
 
738
        int tfd = -1;
 
739
 
 
740
        (void) elf_version(EV_CURRENT);
 
741
        if ((fd = open(curname, O_RDONLY)) < 0 || fstat(fd, &st) < 0)
 
742
                terminate("%s: Cannot open for re-reading", curname);
 
743
        if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
 
744
                elfterminate(curname, "Cannot re-read");
 
745
 
 
746
        if ((tfd = open(newname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0)
 
747
                terminate("Cannot open temp file %s for writing", newname);
 
748
        if ((telf = elf_begin(tfd, ELF_C_WRITE, NULL)) == NULL)
 
749
                elfterminate(curname, "Cannot write");
 
750
 
 
751
        data = make_ctf_data(td, elf, curname, &len, flags);
 
752
        write_file(elf, curname, telf, newname, data, len, flags);
 
753
        free(data);
 
754
 
 
755
        elf_end(telf);
 
756
        elf_end(elf);
 
757
        (void) close(fd);
 
758
        (void) close(tfd);
 
759
}