diff options
author | John Levon <john.levon@joyent.com> | 2019-09-04 06:01:25 -0700 |
---|---|---|
committer | John Levon <john.levon@joyent.com> | 2019-09-12 04:40:11 -0700 |
commit | ce115d25b7c5f8cff5a9444c4d0d1ea9d31c2056 (patch) | |
tree | 7a01d000c16bb1782f1bf2db41ad8ae5136f9057 /usr/src/tools/ctf | |
parent | 8eb8717cc9dc99bdd784b74c994bea7ef5e60f92 (diff) | |
download | illumos-gate-ce115d25b7c5f8cff5a9444c4d0d1ea9d31c2056.tar.gz |
11657 Remove old ctf tools
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Dan McDonald <danmcd@joyent.com>
Diffstat (limited to 'usr/src/tools/ctf')
37 files changed, 3 insertions, 12312 deletions
diff --git a/usr/src/tools/ctf/Makefile b/usr/src/tools/ctf/Makefile index 3ea3da7ca1..172509dc2f 100644 --- a/usr/src/tools/ctf/Makefile +++ b/usr/src/tools/ctf/Makefile @@ -23,12 +23,12 @@ # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # +# Copyright 2019 Joyent, Inc. +# include ../Makefile.tools -SUBDIRS = stabs ctfstrip libctf ctfdiff ctfdump -$(BUILD_OLD_CTF_TOOLS)SUBDIRS += cvt -$(BUILD_NEW_CTF_TOOLS)SUBDIRS += ctfmerge ctfconvert +SUBDIRS = stabs ctfstrip libctf ctfdiff ctfdump ctfmerge ctfconvert .PARALLEL: $(SUBDIRS) diff --git a/usr/src/tools/ctf/cvt/Makefile b/usr/src/tools/ctf/cvt/Makefile deleted file mode 100644 index 16d8280cdd..0000000000 --- a/usr/src/tools/ctf/cvt/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright (c) 2001 by Sun Microsystems, Inc. -# All rights reserved. -# -#ident "%Z%%M% %I% %E% SMI" - -include ../../Makefile.tools - -SUBDIRS = $(MACH) - -all := TARGET= all -install := TARGET= install -clean := TARGET= clean -clobber := TARGET= clobber -lint := TARGET= lint - -.KEEP_STATE: - -install all clean clobber lint: $(SUBDIRS) - -$(SUBDIRS): FRC - @cd $@; pwd; $(MAKE) $(TARGET) - -FRC: diff --git a/usr/src/tools/ctf/cvt/Makefile.com b/usr/src/tools/ctf/cvt/Makefile.com deleted file mode 100644 index 1771505c9e..0000000000 --- a/usr/src/tools/ctf/cvt/Makefile.com +++ /dev/null @@ -1,91 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -include ../../Makefile.ctf - -.KEEP_STATE: -.PARALLEL: - -PROG=ctfconvert ctfmerge - -GENSRCS= \ - alist.c \ - altexec.c \ - barrier.c \ - ctf.c \ - fifo.c \ - hash.c \ - iidesc.c \ - input.c \ - list.c \ - memory.c \ - merge.c \ - output.c \ - stack.c \ - strtab.c \ - symbol.c \ - tdata.c \ - traverse.c \ - util.c - -CVTSRCS=$(GENSRCS) \ - ctfconvert.c \ - dwarf.c \ - stabs.c \ - fixup_tdescs.c \ - st_parse.c -CVTOBJS=$(CVTSRCS:%.c=%.o) -CVTLINTFILES = $(CVTSRCS:%.c=%.ln) - -MRGSRCS=$(GENSRCS) \ - ctfmerge.c -MRGOBJS=$(MRGSRCS:%.c=%.o) -MRGLINTFILES = $(MRGSRCS:%.c=%.ln) - -SRCS=$(CVTSRCS) $(MRGSRCS) $(CMPSRCS) -OBJS=$(SRCS:%.c=%.o) -LINTFILES=$(SRCS:%.c=%.ln) - -DWARFLDFLAGS = \ - -L$(ROOTONBLDLIBMACH) \ - '-R$$ORIGIN/../../lib/$(MACH)' \ - -ldwarf -DWARFCPPFLAGS = -I$(SRC)/lib/libdwarf/common - -LDFLAGS += -L$(NATIVE_ADJUNCT)/lib -LDLIBS += -lz -lelf -CPPFLAGS += -D_REENTRANT -CFLAGS += $(CTF_FLAGS) -LINTFLAGS += -mnux - -CERRWARN += -_gcc=-Wno-unused -CERRWARN += $(CNOWARN_UNINIT) -CERRWARN += -_gcc=-Wno-switch - -CSTD = $(CSTD_GNU99) - -ctfconvert := LDFLAGS += $(DWARFLDFLAGS) - -dwarf.o dwarf.ln := CPPFLAGS += $(DWARFCPPFLAGS) diff --git a/usr/src/tools/ctf/cvt/Makefile.targ b/usr/src/tools/ctf/cvt/Makefile.targ deleted file mode 100644 index fba7b168e9..0000000000 --- a/usr/src/tools/ctf/cvt/Makefile.targ +++ /dev/null @@ -1,75 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -all: $(PROG) - -ctfconvert: $(CVTOBJS) - $(LINK.c) -o $@ $(CVTOBJS) $(LDLIBS) - $(POST_PROCESS) - -ctfmerge: $(MRGOBJS) - $(LINK.c) -o $@ $(MRGOBJS) $(LDLIBS) - $(POST_PROCESS) - -%.o: ../%.c - $(COMPILE.c) $< - -%.ln: ../%.c - $(LINT.c) -c $< - -$(ROOTONBLDMACHPROG): $(SELFTEST) -$(SELFTEST): $(PROG) - -install: $(PROG) $(SELFTEST) .WAIT $(ROOTONBLDMACHPROG) - -lint: $(LINTFILES) - $(LINT) $(LINTFLAGS) $(CVTLINTFILES) - $(LINT) $(LINTFLAGS) $(MRGLINTFILES) - -clean: - $(RM) $(OBJS) - -CLOBBERFILES=$(LINTFILES) - -# -# After we've built ctfconvert and ctfmerge, let's use them on ourselves. The -# RPATH in the built ctfconvert will only know how to find libdwarf if we invoke -# the one in $(ROOT). We haven't installed it there yet, though, so we have to -# invoke the one in $(SRC). We'll manually tell it where libdwarf is. -# -selftest: ctf_o ctfconvert_merge ctfmerge_merge - -ctf_o: $(OBJS:%.o=%_ctf) - -%_ctf: %.o ctfconvert - LD_LIBRARY_PATH=$(DWARFSRCLIBDIR)/$(MACH) ./ctfconvert -l $@ $< - -ctfconvert_merge: ctf_o ctfmerge - ./ctfmerge -l $@ -o ctfconvert $(CVTOBJS) - -ctfmerge_merge: ctf_o ctfmerge - ./ctfmerge -l $@ -o ctfmerge $(MRGOBJS) - -include ../../Makefile.ctf.targ diff --git a/usr/src/tools/ctf/cvt/alist.c b/usr/src/tools/ctf/cvt/alist.c deleted file mode 100644 index 415a6cd333..0000000000 --- a/usr/src/tools/ctf/cvt/alist.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Create, manage, and destroy association lists. alists are arrays with - * arbitrary index types, and are also commonly known as associative arrays. - */ - -#include <stdio.h> -#include <stdlib.h> - -#include "alist.h" -#include "memory.h" -#include "hash.h" - -#define ALIST_HASH_SIZE 997 - -struct alist { - hash_t *al_elements; - void (*al_namefree)(void *); - void (*al_valfree)(void *); -}; - -typedef struct alist_el { - void *ale_name; - void *ale_value; -} alist_el_t; - -static int -alist_hash(int nbuckets, alist_el_t *el) -{ - uintptr_t num = (uintptr_t)el->ale_name; - - return (num % nbuckets); -} - -static int -alist_cmp(alist_el_t *el1, alist_el_t *el2) -{ - return ((uintptr_t)el1->ale_name != (uintptr_t)el2->ale_name); -} - -alist_t * -alist_xnew(int nbuckets, void (*namefree)(void *), - void (*valfree)(void *), int (*hashfn)(int, void *), - int (*cmpfn)(void *, void *)) -{ - alist_t *alist; - - alist = xcalloc(sizeof (alist_t)); - alist->al_elements = hash_new(nbuckets, hashfn, cmpfn); - alist->al_namefree = namefree; - alist->al_valfree = valfree; - - return (alist); -} - -alist_t * -alist_new(void (*namefree)(void *), void (*valfree)(void *)) -{ - return (alist_xnew(ALIST_HASH_SIZE, namefree, valfree, - (int (*)())alist_hash, (int (*)())alist_cmp)); -} - -static void -alist_free_cb(alist_el_t *el, alist_t *alist) -{ - if (alist->al_namefree) - alist->al_namefree(el->ale_name); - if (alist->al_valfree) - alist->al_valfree(el->ale_name); - free(el); -} - -void -alist_free(alist_t *alist) -{ - hash_free(alist->al_elements, (void (*)())alist_free_cb, alist); - free(alist); -} - -void -alist_add(alist_t *alist, void *name, void *value) -{ - alist_el_t *el; - - el = xmalloc(sizeof (alist_el_t)); - el->ale_name = name; - el->ale_value = value; - hash_add(alist->al_elements, el); -} - -int -alist_find(alist_t *alist, void *name, void **value) -{ - alist_el_t template, *ret; - - template.ale_name = name; - if (!hash_find(alist->al_elements, &template, (void **)&ret)) - return (0); - - if (value) - *value = ret->ale_value; - - return (1); -} - -typedef struct alist_iter_data { - int (*aid_func)(void *, void *, void *); - void *aid_priv; -} alist_iter_data_t; - -static int -alist_iter_cb(alist_el_t *el, alist_iter_data_t *aid) -{ - return (aid->aid_func(el->ale_name, el->ale_value, aid->aid_priv)); -} - -int -alist_iter(alist_t *alist, int (*func)(void *, void *, void *), void *private) -{ - alist_iter_data_t aid; - - aid.aid_func = func; - aid.aid_priv = private; - - return (hash_iter(alist->al_elements, (int (*)())alist_iter_cb, &aid)); -} - -/* - * Debugging support. Used to print the contents of an alist. - */ - -void -alist_stats(alist_t *alist, int verbose) -{ - printf("Alist statistics\n"); - hash_stats(alist->al_elements, verbose); -} - -static int alist_def_print_cb_key_int = 1; -static int alist_def_print_cb_value_int = 1; - -static int -alist_def_print_cb(void *key, void *value) -{ - printf("Key: "); - if (alist_def_print_cb_key_int == 1) - printf("%5d ", (int)key); - else - printf("%s\n", (char *)key); - - printf("Value: "); - if (alist_def_print_cb_value_int == 1) - printf("%5d\n", (int)value); - else - printf("%s\n", (char *)key); - - return (1); -} - -static int -alist_dump_cb(void *node, void *private) -{ - int (*printer)(void *, void *) = (int (*)())private; - alist_el_t *el = node; - - printer(el->ale_name, el->ale_value); - - return (1); -} - -int -alist_dump(alist_t *alist, int (*printer)(void *, void *)) -{ - if (!printer) - printer = alist_def_print_cb; - - return (hash_iter(alist->al_elements, alist_dump_cb, (void *)printer)); -} diff --git a/usr/src/tools/ctf/cvt/alist.h b/usr/src/tools/ctf/cvt/alist.h deleted file mode 100644 index ec49df1a35..0000000000 --- a/usr/src/tools/ctf/cvt/alist.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _ASSOC_H -#define _ASSOC_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Create, manage, and destroy association lists. alists are arrays with - * arbitrary index types. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct alist alist_t; - -alist_t *alist_new(void (*)(void *), void (*)(void *)); -alist_t *alist_xnew(int, void (*)(void *), void (*)(void *), - int (*)(int, void *), int (*)(void *, void *)); -void alist_free(alist_t *); -void alist_add(alist_t *, void *, void *); -int alist_find(alist_t *, void *, void **); -int alist_iter(alist_t *, int (*)(void *, void *, void *), void *); -void alist_stats(alist_t *, int); - -#ifdef __cplusplus -} -#endif - -#endif /* _ASSOC_H */ diff --git a/usr/src/tools/ctf/cvt/altexec.c b/usr/src/tools/ctf/cvt/altexec.c deleted file mode 100644 index c986c0731a..0000000000 --- a/usr/src/tools/ctf/cvt/altexec.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ - -/* - * Copyright (c) 2015, Joyent, Inc. - */ - -/* - * Alternate execution engine for CTF tools - */ - -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "ctftools.h" - -void -ctf_altexec(const char *env, int argc, char **argv) -{ - const char *alt; - char *altexec; - - alt = getenv(env); - if (alt == NULL || *alt == '\0') - return; - - altexec = strdup(alt); - if (altexec == NULL) - terminate("failed to allocate memory for altexec\n"); - - if (unsetenv(env) != 0) - aborterr("failed to remove %s from environment", env); - - (void) execv(altexec, argv); - terminate("failed to altexec %s", altexec); -} diff --git a/usr/src/tools/ctf/cvt/barrier.c b/usr/src/tools/ctf/cvt/barrier.c deleted file mode 100644 index d91fbf44db..0000000000 --- a/usr/src/tools/ctf/cvt/barrier.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2002 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * This file implements a barrier, a synchronization primitive designed to allow - * threads to wait for each other at given points. Barriers are initialized - * with a given number of threads, n, using barrier_init(). When a thread calls - * barrier_wait(), that thread blocks until n - 1 other threads reach the - * barrier_wait() call using the same barrier_t. When n threads have reached - * the barrier, they are all awakened and sent on their way. One of the threads - * returns from barrier_wait() with a return code of 1; the remaining threads - * get a return code of 0. - */ - -#include <pthread.h> -#include <synch.h> -#include <stdio.h> - -#include "barrier.h" - -void -barrier_init(barrier_t *bar, int nthreads) -{ - pthread_mutex_init(&bar->bar_lock, NULL); - sema_init(&bar->bar_sem, 0, USYNC_THREAD, NULL); - - bar->bar_numin = 0; - bar->bar_nthr = nthreads; -} - -int -barrier_wait(barrier_t *bar) -{ - pthread_mutex_lock(&bar->bar_lock); - - if (++bar->bar_numin < bar->bar_nthr) { - pthread_mutex_unlock(&bar->bar_lock); - sema_wait(&bar->bar_sem); - - return (0); - - } else { - int i; - - /* reset for next use */ - bar->bar_numin = 0; - for (i = 1; i < bar->bar_nthr; i++) - sema_post(&bar->bar_sem); - pthread_mutex_unlock(&bar->bar_lock); - - return (1); - } -} diff --git a/usr/src/tools/ctf/cvt/barrier.h b/usr/src/tools/ctf/cvt/barrier.h deleted file mode 100644 index 3a62f3082e..0000000000 --- a/usr/src/tools/ctf/cvt/barrier.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2002 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _BARRIER_H -#define _BARRIER_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * APIs for the barrier synchronization primitive. - */ - -#include <synch.h> - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct barrier { - pthread_mutex_t bar_lock; /* protects bar_numin */ - int bar_numin; /* current number of waiters */ - - sema_t bar_sem; /* where everyone waits */ - int bar_nthr; /* # of waiters to trigger release */ -} barrier_t; - -extern void barrier_init(barrier_t *, int); -extern int barrier_wait(barrier_t *); - -#ifdef __cplusplus -} -#endif - -#endif /* _BARRIER_H */ diff --git a/usr/src/tools/ctf/cvt/compare.c b/usr/src/tools/ctf/cvt/compare.c deleted file mode 100644 index 26037f8a53..0000000000 --- a/usr/src/tools/ctf/cvt/compare.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * This is a test program designed to catch mismerges and mistranslations from - * stabs to CTF. - * - * Given a file with stabs data and a file with CTF data, determine whether - * or not all of the data structures and objects described by the stabs data - * are present in the CTF data. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> - -#include "ctftools.h" - -char *progname; -int debug_level = DEBUG_LEVEL; - -static void -usage(void) -{ - fprintf(stderr, "Usage: %s ctf_file stab_file\n", progname); -} - -int -main(int argc, char **argv) -{ - tdata_t *ctftd, *stabrtd, *stabtd, *difftd; - char *ctfname, *stabname; - int new; - - progname = argv[0]; - - if (argc != 3) { - usage(); - exit(2); - } - - ctfname = argv[1]; - stabname = argv[2]; - - stabrtd = tdata_new(); - stabtd = tdata_new(); - difftd = tdata_new(); - - if (read_stabs(stabrtd, stabname, 0) != 0) - merge_into_master(stabrtd, stabtd, NULL, 1); - else if (read_ctf(&stabname, 1, NULL, read_ctf_save_cb, &stabtd, 0) - == 0) - terminate("%s doesn't have stabs or CTF\n", stabname); - - if (read_ctf(&ctfname, 1, NULL, read_ctf_save_cb, &ctftd, 0) == 0) - terminate("%s doesn't contain CTF data\n", ctfname); - - merge_into_master(stabtd, ctftd, difftd, 0); - - if ((new = hash_count(difftd->td_iihash)) != 0) { - (void) hash_iter(difftd->td_iihash, (int (*)())iidesc_dump, - NULL); - terminate("%s grew by %d\n", stabname, new); - } - - return (0); -} diff --git a/usr/src/tools/ctf/cvt/ctf.c b/usr/src/tools/ctf/cvt/ctf.c deleted file mode 100644 index 83f09cb43e..0000000000 --- a/usr/src/tools/ctf/cvt/ctf.c +++ /dev/null @@ -1,1282 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * Create and parse buffers containing CTF data. - */ - -#include <sys/types.h> -#include <stdio.h> -#include <stdlib.h> -#include <strings.h> -#include <ctype.h> -#include <zlib.h> -#include <elf.h> - -#include "ctf_headers.h" -#include "ctftools.h" -#include "strtab.h" -#include "memory.h" - -/* - * Name of the file currently being read, used to print error messages. We - * assume that only one file will be read at a time, and thus make no attempt - * to allow curfile to be used simultaneously by multiple threads. - * - * The value is only valid during a call to ctf_load. - */ -char *curfile; - -#define CTF_BUF_CHUNK_SIZE (64 * 1024) -#define RES_BUF_CHUNK_SIZE (64 * 1024) - -struct ctf_buf { - strtab_t ctb_strtab; /* string table */ - caddr_t ctb_base; /* pointer to base of buffer */ - caddr_t ctb_end; /* pointer to end of buffer */ - caddr_t ctb_ptr; /* pointer to empty buffer space */ - size_t ctb_size; /* size of buffer */ - int nptent; /* number of processed types */ - int ntholes; /* number of type holes */ -}; - -/*PRINTFLIKE1*/ -static void -parseterminate(char *fmt, ...) -{ - static char msgbuf[1024]; /* sigh */ - va_list ap; - - va_start(ap, fmt); - vsnprintf(msgbuf, sizeof (msgbuf), fmt, ap); - va_end(ap); - - terminate("%s: %s\n", curfile, msgbuf); -} - -void -ctf_buf_grow(ctf_buf_t *b) -{ - off_t ptroff = b->ctb_ptr - b->ctb_base; - - b->ctb_size += CTF_BUF_CHUNK_SIZE; - b->ctb_base = xrealloc(b->ctb_base, b->ctb_size); - b->ctb_end = b->ctb_base + b->ctb_size; - b->ctb_ptr = b->ctb_base + ptroff; -} - -ctf_buf_t * -ctf_buf_new(void) -{ - ctf_buf_t *b = xcalloc(sizeof (ctf_buf_t)); - - strtab_create(&b->ctb_strtab); - ctf_buf_grow(b); - - return (b); -} - -void -ctf_buf_free(ctf_buf_t *b) -{ - strtab_destroy(&b->ctb_strtab); - free(b->ctb_base); - free(b); -} - -uint_t -ctf_buf_cur(ctf_buf_t *b) -{ - return (b->ctb_ptr - b->ctb_base); -} - -void -ctf_buf_write(ctf_buf_t *b, const void *p, size_t n) -{ - size_t len; - - while (n != 0) { - if (b->ctb_ptr == b->ctb_end) - ctf_buf_grow(b); - - len = MIN((size_t)(b->ctb_end - b->ctb_ptr), n); - bcopy(p, b->ctb_ptr, len); - b->ctb_ptr += len; - - p = (char *)p + len; - n -= len; - } -} - -static int -write_label(labelent_t *le, ctf_buf_t *b) -{ - ctf_lblent_t ctl; - - ctl.ctl_label = strtab_insert(&b->ctb_strtab, le->le_name); - ctl.ctl_typeidx = le->le_idx; - - ctf_buf_write(b, &ctl, sizeof (ctl)); - - return (1); -} - -static void -write_objects(iidesc_t *idp, ctf_buf_t *b) -{ - ushort_t id = (idp ? idp->ii_dtype->t_id : 0); - - ctf_buf_write(b, &id, sizeof (id)); - - debug(3, "Wrote object %s (%d)\n", (idp ? idp->ii_name : "(null)"), id); -} - -static void -write_functions(iidesc_t *idp, ctf_buf_t *b) -{ - ushort_t fdata[2]; - ushort_t id; - int nargs; - int i; - - if (!idp) { - fdata[0] = 0; - ctf_buf_write(b, &fdata[0], sizeof (fdata[0])); - - debug(3, "Wrote function (null)\n"); - return; - } - - nargs = idp->ii_nargs + (idp->ii_vargs != 0); - - if (nargs > CTF_MAX_VLEN) { - terminate("function %s has too many args: %d > %d\n", - idp->ii_name, nargs, CTF_MAX_VLEN); - } - - fdata[0] = CTF_TYPE_INFO(CTF_K_FUNCTION, 1, nargs); - fdata[1] = idp->ii_dtype->t_id; - ctf_buf_write(b, fdata, sizeof (fdata)); - - for (i = 0; i < idp->ii_nargs; i++) { - id = idp->ii_args[i]->t_id; - ctf_buf_write(b, &id, sizeof (id)); - } - - if (idp->ii_vargs) { - id = 0; - ctf_buf_write(b, &id, sizeof (id)); - } - - debug(3, "Wrote function %s (%d args)\n", idp->ii_name, nargs); -} - -/* - * Depending on the size of the type being described, either a ctf_stype_t (for - * types with size < CTF_LSTRUCT_THRESH) or a ctf_type_t (all others) will be - * written. We isolate the determination here so the rest of the writer code - * doesn't need to care. - */ -static void -write_sized_type_rec(ctf_buf_t *b, ctf_type_t *ctt, size_t size) -{ - if (size > CTF_MAX_SIZE) { - ctt->ctt_size = CTF_LSIZE_SENT; - ctt->ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(size); - ctt->ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(size); - ctf_buf_write(b, ctt, sizeof (*ctt)); - } else { - ctf_stype_t *cts = (ctf_stype_t *)ctt; - - cts->ctt_size = (ushort_t)size; - ctf_buf_write(b, cts, sizeof (*cts)); - } -} - -static void -write_unsized_type_rec(ctf_buf_t *b, ctf_type_t *ctt) -{ - ctf_stype_t *cts = (ctf_stype_t *)ctt; - - ctf_buf_write(b, cts, sizeof (*cts)); -} - -static int -write_type(tdesc_t *tp, ctf_buf_t *b) -{ - elist_t *ep; - mlist_t *mp; - intr_t *ip; - - size_t offset; - uint_t encoding; - uint_t data; - int isroot = tp->t_flags & TDESC_F_ISROOT; - int i; - - ctf_type_t ctt; - ctf_array_t cta; - ctf_member_t ctm; - ctf_lmember_t ctlm; - ctf_enum_t cte; - ushort_t id; - - ctlm.ctlm_pad = 0; - - /* - * There shouldn't be any holes in the type list (where a hole is - * defined as two consecutive tdescs without consecutive ids), but - * check for them just in case. If we do find holes, we need to make - * fake entries to fill the holes, or we won't be able to reconstruct - * the tree from the written data. - */ - if (++b->nptent < CTF_TYPE_TO_INDEX(tp->t_id)) { - debug(2, "genctf: type hole from %d < x < %d\n", - b->nptent - 1, CTF_TYPE_TO_INDEX(tp->t_id)); - - ctt.ctt_name = CTF_TYPE_NAME(CTF_STRTAB_0, 0); - ctt.ctt_info = CTF_TYPE_INFO(0, 0, 0); - while (b->nptent < CTF_TYPE_TO_INDEX(tp->t_id)) { - write_sized_type_rec(b, &ctt, 0); - b->nptent++; - } - } - - offset = strtab_insert(&b->ctb_strtab, tp->t_name); - ctt.ctt_name = CTF_TYPE_NAME(CTF_STRTAB_0, offset); - - switch (tp->t_type) { - case INTRINSIC: - ip = tp->t_intr; - if (ip->intr_type == INTR_INT) - ctt.ctt_info = CTF_TYPE_INFO(CTF_K_INTEGER, - isroot, 1); - else - ctt.ctt_info = CTF_TYPE_INFO(CTF_K_FLOAT, isroot, 1); - write_sized_type_rec(b, &ctt, tp->t_size); - - encoding = 0; - - if (ip->intr_type == INTR_INT) { - if (ip->intr_signed) - encoding |= CTF_INT_SIGNED; - if (ip->intr_iformat == 'c') - encoding |= CTF_INT_CHAR; - else if (ip->intr_iformat == 'b') - encoding |= CTF_INT_BOOL; - else if (ip->intr_iformat == 'v') - encoding |= CTF_INT_VARARGS; - } else - encoding = ip->intr_fformat; - - data = CTF_INT_DATA(encoding, ip->intr_offset, ip->intr_nbits); - ctf_buf_write(b, &data, sizeof (data)); - break; - - case POINTER: - ctt.ctt_info = CTF_TYPE_INFO(CTF_K_POINTER, isroot, 0); - ctt.ctt_type = tp->t_tdesc->t_id; - write_unsized_type_rec(b, &ctt); - break; - - case ARRAY: - ctt.ctt_info = CTF_TYPE_INFO(CTF_K_ARRAY, isroot, 1); - write_sized_type_rec(b, &ctt, tp->t_size); - - cta.cta_contents = tp->t_ardef->ad_contents->t_id; - cta.cta_index = tp->t_ardef->ad_idxtype->t_id; - cta.cta_nelems = tp->t_ardef->ad_nelems; - ctf_buf_write(b, &cta, sizeof (cta)); - break; - - case STRUCT: - case UNION: - for (i = 0, mp = tp->t_members; mp != NULL; mp = mp->ml_next) - i++; /* count up struct or union members */ - - if (i > CTF_MAX_VLEN) { - terminate("sou %s has too many members: %d > %d\n", - tdesc_name(tp), i, CTF_MAX_VLEN); - } - - if (tp->t_type == STRUCT) - ctt.ctt_info = CTF_TYPE_INFO(CTF_K_STRUCT, isroot, i); - else - ctt.ctt_info = CTF_TYPE_INFO(CTF_K_UNION, isroot, i); - - write_sized_type_rec(b, &ctt, tp->t_size); - - if (tp->t_size < CTF_LSTRUCT_THRESH) { - for (mp = tp->t_members; mp != NULL; mp = mp->ml_next) { - offset = strtab_insert(&b->ctb_strtab, - mp->ml_name); - - ctm.ctm_name = CTF_TYPE_NAME(CTF_STRTAB_0, - offset); - ctm.ctm_type = mp->ml_type->t_id; - ctm.ctm_offset = mp->ml_offset; - ctf_buf_write(b, &ctm, sizeof (ctm)); - } - } else { - for (mp = tp->t_members; mp != NULL; mp = mp->ml_next) { - offset = strtab_insert(&b->ctb_strtab, - mp->ml_name); - - ctlm.ctlm_name = CTF_TYPE_NAME(CTF_STRTAB_0, - offset); - ctlm.ctlm_type = mp->ml_type->t_id; - ctlm.ctlm_offsethi = - CTF_OFFSET_TO_LMEMHI(mp->ml_offset); - ctlm.ctlm_offsetlo = - CTF_OFFSET_TO_LMEMLO(mp->ml_offset); - ctf_buf_write(b, &ctlm, sizeof (ctlm)); - } - } - break; - - case ENUM: - for (i = 0, ep = tp->t_emem; ep != NULL; ep = ep->el_next) - i++; /* count up enum members */ - - if (i > CTF_MAX_VLEN) { - terminate("enum %s has too many values: %d > %d\n", - tdesc_name(tp), i, CTF_MAX_VLEN); - } - - ctt.ctt_info = CTF_TYPE_INFO(CTF_K_ENUM, isroot, i); - write_sized_type_rec(b, &ctt, tp->t_size); - - for (ep = tp->t_emem; ep != NULL; ep = ep->el_next) { - offset = strtab_insert(&b->ctb_strtab, ep->el_name); - cte.cte_name = CTF_TYPE_NAME(CTF_STRTAB_0, offset); - cte.cte_value = ep->el_number; - ctf_buf_write(b, &cte, sizeof (cte)); - } - break; - - case FORWARD: - ctt.ctt_info = CTF_TYPE_INFO(CTF_K_FORWARD, isroot, 0); - ctt.ctt_type = 0; - write_unsized_type_rec(b, &ctt); - break; - - case TYPEDEF: - ctt.ctt_info = CTF_TYPE_INFO(CTF_K_TYPEDEF, isroot, 0); - ctt.ctt_type = tp->t_tdesc->t_id; - write_unsized_type_rec(b, &ctt); - break; - - case VOLATILE: - ctt.ctt_info = CTF_TYPE_INFO(CTF_K_VOLATILE, isroot, 0); - ctt.ctt_type = tp->t_tdesc->t_id; - write_unsized_type_rec(b, &ctt); - break; - - case CONST: - ctt.ctt_info = CTF_TYPE_INFO(CTF_K_CONST, isroot, 0); - ctt.ctt_type = tp->t_tdesc->t_id; - write_unsized_type_rec(b, &ctt); - break; - - case FUNCTION: - i = tp->t_fndef->fn_nargs + tp->t_fndef->fn_vargs; - - if (i > CTF_MAX_VLEN) { - terminate("function %s has too many args: %d > %d\n", - i, CTF_MAX_VLEN); - } - - ctt.ctt_info = CTF_TYPE_INFO(CTF_K_FUNCTION, isroot, i); - ctt.ctt_type = tp->t_fndef->fn_ret->t_id; - write_unsized_type_rec(b, &ctt); - - for (i = 0; i < tp->t_fndef->fn_nargs; i++) { - id = tp->t_fndef->fn_args[i]->t_id; - ctf_buf_write(b, &id, sizeof (id)); - } - - if (tp->t_fndef->fn_vargs) { - id = 0; - ctf_buf_write(b, &id, sizeof (id)); - i++; - } - - if (i & 1) { - id = 0; - ctf_buf_write(b, &id, sizeof (id)); - } - break; - - case RESTRICT: - ctt.ctt_info = CTF_TYPE_INFO(CTF_K_RESTRICT, isroot, 0); - ctt.ctt_type = tp->t_tdesc->t_id; - write_unsized_type_rec(b, &ctt); - break; - - default: - warning("Can't write unknown type %d\n", tp->t_type); - } - - debug(3, "Wrote type %d %s\n", tp->t_id, tdesc_name(tp)); - - return (1); -} - -typedef struct resbuf { - caddr_t rb_base; - caddr_t rb_ptr; - size_t rb_size; - z_stream rb_zstr; -} resbuf_t; - -static void -rbzs_grow(resbuf_t *rb) -{ - off_t ptroff = (caddr_t)rb->rb_zstr.next_out - rb->rb_base; - - rb->rb_size += RES_BUF_CHUNK_SIZE; - rb->rb_base = xrealloc(rb->rb_base, rb->rb_size); - rb->rb_ptr = rb->rb_base + ptroff; - rb->rb_zstr.next_out = (Bytef *)(rb->rb_ptr); - rb->rb_zstr.avail_out += RES_BUF_CHUNK_SIZE; -} - -static void -compress_start(resbuf_t *rb) -{ - int rc; - - rb->rb_zstr.zalloc = (alloc_func)0; - rb->rb_zstr.zfree = (free_func)0; - rb->rb_zstr.opaque = (voidpf)0; - - if ((rc = deflateInit(&rb->rb_zstr, Z_BEST_COMPRESSION)) != Z_OK) - parseterminate("zlib start failed: %s", zError(rc)); -} - -static ssize_t -compress_buffer(const void *buf, size_t n, void *data) -{ - resbuf_t *rb = (resbuf_t *)data; - int rc; - - rb->rb_zstr.next_out = (Bytef *)rb->rb_ptr; - rb->rb_zstr.avail_out = rb->rb_size - (rb->rb_ptr - rb->rb_base); - rb->rb_zstr.next_in = (Bytef *)buf; - rb->rb_zstr.avail_in = n; - - while (rb->rb_zstr.avail_in) { - if (rb->rb_zstr.avail_out == 0) - rbzs_grow(rb); - - if ((rc = deflate(&rb->rb_zstr, Z_NO_FLUSH)) != Z_OK) - parseterminate("zlib deflate failed: %s", zError(rc)); - } - rb->rb_ptr = (caddr_t)rb->rb_zstr.next_out; - - return (n); -} - -static void -compress_flush(resbuf_t *rb, int type) -{ - int rc; - - for (;;) { - if (rb->rb_zstr.avail_out == 0) - rbzs_grow(rb); - - rc = deflate(&rb->rb_zstr, type); - if ((type == Z_FULL_FLUSH && rc == Z_BUF_ERROR) || - (type == Z_FINISH && rc == Z_STREAM_END)) - break; - else if (rc != Z_OK) - parseterminate("zlib finish failed: %s", zError(rc)); - } - rb->rb_ptr = (caddr_t)rb->rb_zstr.next_out; -} - -static void -compress_end(resbuf_t *rb) -{ - int rc; - - compress_flush(rb, Z_FINISH); - - if ((rc = deflateEnd(&rb->rb_zstr)) != Z_OK) - parseterminate("zlib end failed: %s", zError(rc)); -} - -/* - * Pad the buffer to a power-of-2 boundary - */ -static void -pad_buffer(ctf_buf_t *buf, int align) -{ - uint_t cur = ctf_buf_cur(buf); - ssize_t topad = (align - (cur % align)) % align; - static const char pad[8] = { 0 }; - - while (topad > 0) { - ctf_buf_write(buf, pad, (topad > 8 ? 8 : topad)); - topad -= 8; - } -} - -static ssize_t -bcopy_data(const void *buf, size_t n, void *data) -{ - caddr_t *posp = (caddr_t *)data; - bcopy(buf, *posp, n); - *posp += n; - return (n); -} - -static caddr_t -write_buffer(ctf_header_t *h, ctf_buf_t *buf, size_t *resszp) -{ - caddr_t outbuf; - caddr_t bufpos; - - outbuf = xmalloc(sizeof (ctf_header_t) + (buf->ctb_ptr - buf->ctb_base) - + buf->ctb_strtab.str_size); - - bufpos = outbuf; - (void) bcopy_data(h, sizeof (ctf_header_t), &bufpos); - (void) bcopy_data(buf->ctb_base, buf->ctb_ptr - buf->ctb_base, - &bufpos); - (void) strtab_write(&buf->ctb_strtab, bcopy_data, &bufpos); - *resszp = bufpos - outbuf; - return (outbuf); -} - -/* - * Create the compression buffer, and fill it with the CTF and string - * table data. We flush the compression state between the two so the - * dictionary used for the string tables won't be polluted with values - * that made sense for the CTF data. - */ -static caddr_t -write_compressed_buffer(ctf_header_t *h, ctf_buf_t *buf, size_t *resszp) -{ - resbuf_t resbuf; - resbuf.rb_size = RES_BUF_CHUNK_SIZE; - resbuf.rb_base = xmalloc(resbuf.rb_size); - bcopy(h, resbuf.rb_base, sizeof (ctf_header_t)); - resbuf.rb_ptr = resbuf.rb_base + sizeof (ctf_header_t); - - compress_start(&resbuf); - (void) compress_buffer(buf->ctb_base, buf->ctb_ptr - buf->ctb_base, - &resbuf); - compress_flush(&resbuf, Z_FULL_FLUSH); - (void) strtab_write(&buf->ctb_strtab, compress_buffer, &resbuf); - compress_end(&resbuf); - - *resszp = (resbuf.rb_ptr - resbuf.rb_base); - return (resbuf.rb_base); -} - -caddr_t -ctf_gen(iiburst_t *iiburst, size_t *resszp, int do_compress) -{ - ctf_buf_t *buf = ctf_buf_new(); - ctf_header_t h; - caddr_t outbuf; - - int i; - - /* - * Prepare the header, and create the CTF output buffers. The data - * object section and function section are both lists of 2-byte - * integers; we pad these out to the next 4-byte boundary if needed. - */ - h.cth_magic = CTF_MAGIC; - h.cth_version = CTF_VERSION; - h.cth_flags = do_compress ? CTF_F_COMPRESS : 0; - h.cth_parlabel = strtab_insert(&buf->ctb_strtab, - iiburst->iib_td->td_parlabel); - h.cth_parname = strtab_insert(&buf->ctb_strtab, - iiburst->iib_td->td_parname); - - h.cth_lbloff = 0; - (void) list_iter(iiburst->iib_td->td_labels, (int (*)())write_label, - buf); - - pad_buffer(buf, 2); - h.cth_objtoff = ctf_buf_cur(buf); - for (i = 0; i < iiburst->iib_nobjts; i++) - write_objects(iiburst->iib_objts[i], buf); - - pad_buffer(buf, 2); - h.cth_funcoff = ctf_buf_cur(buf); - for (i = 0; i < iiburst->iib_nfuncs; i++) - write_functions(iiburst->iib_funcs[i], buf); - - pad_buffer(buf, 4); - h.cth_typeoff = ctf_buf_cur(buf); - (void) list_iter(iiburst->iib_types, (int (*)())write_type, buf); - - debug(2, "CTF wrote %d types\n", list_count(iiburst->iib_types)); - - h.cth_stroff = ctf_buf_cur(buf); - h.cth_strlen = strtab_size(&buf->ctb_strtab); - - /* - * We only do compression for ctfmerge, as ctfconvert is only - * supposed to be used on intermediary build objects. This is - * significantly faster. - */ - if (do_compress) - outbuf = write_compressed_buffer(&h, buf, resszp); - else - outbuf = write_buffer(&h, buf, resszp); - - ctf_buf_free(buf); - return (outbuf); -} - -void -get_ctt_size(ctf_type_t *ctt, size_t *sizep, size_t *incrementp) -{ - if (ctt->ctt_size == CTF_LSIZE_SENT) { - *sizep = (size_t)CTF_TYPE_LSIZE(ctt); - *incrementp = sizeof (ctf_type_t); - } else { - *sizep = ctt->ctt_size; - *incrementp = sizeof (ctf_stype_t); - } -} - -static int -count_types(ctf_header_t *h, caddr_t data) -{ - caddr_t dptr = data + h->cth_typeoff; - int count = 0; - - dptr = data + h->cth_typeoff; - while (dptr < data + h->cth_stroff) { - /* LINTED - pointer alignment */ - ctf_type_t *ctt = (ctf_type_t *)dptr; - size_t vlen = CTF_INFO_VLEN(ctt->ctt_info); - size_t size, increment; - - get_ctt_size(ctt, &size, &increment); - - switch (CTF_INFO_KIND(ctt->ctt_info)) { - case CTF_K_INTEGER: - case CTF_K_FLOAT: - dptr += 4; - break; - case CTF_K_POINTER: - case CTF_K_FORWARD: - case CTF_K_TYPEDEF: - case CTF_K_VOLATILE: - case CTF_K_CONST: - case CTF_K_RESTRICT: - case CTF_K_FUNCTION: - dptr += sizeof (ushort_t) * (vlen + (vlen & 1)); - break; - case CTF_K_ARRAY: - dptr += sizeof (ctf_array_t); - break; - case CTF_K_STRUCT: - case CTF_K_UNION: - if (size < CTF_LSTRUCT_THRESH) - dptr += sizeof (ctf_member_t) * vlen; - else - dptr += sizeof (ctf_lmember_t) * vlen; - break; - case CTF_K_ENUM: - dptr += sizeof (ctf_enum_t) * vlen; - break; - case CTF_K_UNKNOWN: - break; - default: - parseterminate("Unknown CTF type %d (#%d) at %#x", - CTF_INFO_KIND(ctt->ctt_info), count, dptr - data); - } - - dptr += increment; - count++; - } - - debug(3, "CTF read %d types\n", count); - - return (count); -} - -/* - * Resurrect the labels stored in the CTF data, returning the index associated - * with a label provided by the caller. There are several cases, outlined - * below. Note that, given two labels, the one associated with the lesser type - * index is considered to be older than the other. - * - * 1. matchlbl == NULL - return the index of the most recent label. - * 2. matchlbl == "BASE" - return the index of the oldest label. - * 3. matchlbl != NULL, but doesn't match any labels in the section - warn - * the user, and proceed as if matchlbl == "BASE" (for safety). - * 4. matchlbl != NULL, and matches one of the labels in the section - return - * the type index associated with the label. - */ -static int -resurrect_labels(ctf_header_t *h, tdata_t *td, caddr_t ctfdata, char *matchlbl) -{ - caddr_t buf = ctfdata + h->cth_lbloff; - caddr_t sbuf = ctfdata + h->cth_stroff; - size_t bufsz = h->cth_objtoff - h->cth_lbloff; - int lastidx = 0, baseidx = -1; - char *baselabel; - ctf_lblent_t *ctl; - - /* LINTED - pointer alignment */ - for (ctl = (ctf_lblent_t *)buf; (caddr_t)ctl < buf + bufsz; ctl++) { - char *label = sbuf + ctl->ctl_label; - - lastidx = ctl->ctl_typeidx; - - debug(3, "Resurrected label %s type idx %d\n", label, lastidx); - - tdata_label_add(td, label, lastidx); - - if (baseidx == -1) { - baseidx = lastidx; - baselabel = label; - if (matchlbl != NULL && streq(matchlbl, "BASE")) - return (lastidx); - } - - if (matchlbl != NULL && streq(label, matchlbl)) - return (lastidx); - } - - if (matchlbl != NULL) { - /* User provided a label that didn't match */ - warning("%s: Cannot find label `%s' - using base (%s)\n", - curfile, matchlbl, (baselabel ? baselabel : "NONE")); - - tdata_label_free(td); - tdata_label_add(td, baselabel, baseidx); - - return (baseidx); - } - - return (lastidx); -} - -static void -resurrect_objects(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize, - caddr_t ctfdata, symit_data_t *si) -{ - caddr_t buf = ctfdata + h->cth_objtoff; - size_t bufsz = h->cth_funcoff - h->cth_objtoff; - caddr_t dptr; - - symit_reset(si); - for (dptr = buf; dptr < buf + bufsz; dptr += 2) { - /* LINTED - pointer alignment */ - ushort_t id = *((ushort_t *)dptr); - iidesc_t *ii; - GElf_Sym *sym; - - if (!(sym = symit_next(si, STT_OBJECT)) && id != 0) { - parseterminate( - "Unexpected end of object symbols at %x of %x", - dptr - buf, bufsz); - } - - if (id == 0) { - debug(3, "Skipping null object\n"); - continue; - } else if (id >= tdsize) { - parseterminate("Reference to invalid type %d", id); - } - - ii = iidesc_new(symit_name(si)); - ii->ii_dtype = tdarr[id]; - if (GELF_ST_BIND(sym->st_info) == STB_LOCAL) { - ii->ii_type = II_SVAR; - ii->ii_owner = xstrdup(symit_curfile(si)); - } else - ii->ii_type = II_GVAR; - hash_add(td->td_iihash, ii); - - debug(3, "Resurrected %s object %s (%d) from %s\n", - (ii->ii_type == II_GVAR ? "global" : "static"), - ii->ii_name, id, (ii->ii_owner ? ii->ii_owner : "(none)")); - } -} - -static void -resurrect_functions(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize, - caddr_t ctfdata, symit_data_t *si) -{ - caddr_t buf = ctfdata + h->cth_funcoff; - size_t bufsz = h->cth_typeoff - h->cth_funcoff; - caddr_t dptr = buf; - iidesc_t *ii; - ushort_t info; - ushort_t retid; - GElf_Sym *sym; - int i; - - symit_reset(si); - while (dptr < buf + bufsz) { - /* LINTED - pointer alignment */ - info = *((ushort_t *)dptr); - dptr += 2; - - if (!(sym = symit_next(si, STT_FUNC)) && info != 0) - parseterminate("Unexpected end of function symbols"); - - if (info == 0) { - debug(3, "Skipping null function (%s)\n", - symit_name(si)); - continue; - } - - /* LINTED - pointer alignment */ - retid = *((ushort_t *)dptr); - dptr += 2; - - if (retid >= tdsize) - parseterminate("Reference to invalid type %d", retid); - - ii = iidesc_new(symit_name(si)); - ii->ii_dtype = tdarr[retid]; - if (GELF_ST_BIND(sym->st_info) == STB_LOCAL) { - ii->ii_type = II_SFUN; - ii->ii_owner = xstrdup(symit_curfile(si)); - } else - ii->ii_type = II_GFUN; - ii->ii_nargs = CTF_INFO_VLEN(info); - if (ii->ii_nargs) - ii->ii_args = - xmalloc(sizeof (tdesc_t *) * ii->ii_nargs); - - for (i = 0; i < ii->ii_nargs; i++, dptr += 2) { - /* LINTED - pointer alignment */ - ushort_t id = *((ushort_t *)dptr); - if (id >= tdsize) - parseterminate("Reference to invalid type %d", - id); - ii->ii_args[i] = tdarr[id]; - } - - if (ii->ii_nargs && ii->ii_args[ii->ii_nargs - 1] == NULL) { - ii->ii_nargs--; - ii->ii_vargs = 1; - } - - hash_add(td->td_iihash, ii); - - debug(3, "Resurrected %s function %s (%d, %d args)\n", - (ii->ii_type == II_GFUN ? "global" : "static"), - ii->ii_name, retid, ii->ii_nargs); - } -} - -static void -resurrect_types(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize, - caddr_t ctfdata, int maxid) -{ - caddr_t buf = ctfdata + h->cth_typeoff; - size_t bufsz = h->cth_stroff - h->cth_typeoff; - caddr_t sbuf = ctfdata + h->cth_stroff; - caddr_t dptr = buf; - tdesc_t *tdp; - uint_t data; - uint_t encoding; - size_t size, increment; - int tcnt; - int iicnt = 0; - tid_t tid, argid; - int kind, vlen; - int i; - - elist_t **epp; - mlist_t **mpp; - intr_t *ip; - - ctf_type_t *ctt; - ctf_array_t *cta; - ctf_enum_t *cte; - - /* - * A maxid of zero indicates a request to resurrect all types, so reset - * maxid to the maximum type id. - */ - if (maxid == 0) - maxid = CTF_MAX_TYPE; - - for (dptr = buf, tcnt = 0, tid = 1; dptr < buf + bufsz; tcnt++, tid++) { - if (tid > maxid) - break; - - if (tid >= tdsize) - parseterminate("Reference to invalid type %d", tid); - - /* LINTED - pointer alignment */ - ctt = (ctf_type_t *)dptr; - - get_ctt_size(ctt, &size, &increment); - dptr += increment; - - tdp = tdarr[tid]; - - if (CTF_NAME_STID(ctt->ctt_name) != CTF_STRTAB_0) - parseterminate( - "Unable to cope with non-zero strtab id"); - if (CTF_NAME_OFFSET(ctt->ctt_name) != 0) { - tdp->t_name = - xstrdup(sbuf + CTF_NAME_OFFSET(ctt->ctt_name)); - } else - tdp->t_name = NULL; - - kind = CTF_INFO_KIND(ctt->ctt_info); - vlen = CTF_INFO_VLEN(ctt->ctt_info); - - switch (kind) { - case CTF_K_INTEGER: - tdp->t_type = INTRINSIC; - tdp->t_size = size; - - /* LINTED - pointer alignment */ - data = *((uint_t *)dptr); - dptr += sizeof (uint_t); - encoding = CTF_INT_ENCODING(data); - - ip = xmalloc(sizeof (intr_t)); - ip->intr_type = INTR_INT; - ip->intr_signed = (encoding & CTF_INT_SIGNED) ? 1 : 0; - - if (encoding & CTF_INT_CHAR) - ip->intr_iformat = 'c'; - else if (encoding & CTF_INT_BOOL) - ip->intr_iformat = 'b'; - else if (encoding & CTF_INT_VARARGS) - ip->intr_iformat = 'v'; - else - ip->intr_iformat = '\0'; - - ip->intr_offset = CTF_INT_OFFSET(data); - ip->intr_nbits = CTF_INT_BITS(data); - tdp->t_intr = ip; - break; - - case CTF_K_FLOAT: - tdp->t_type = INTRINSIC; - tdp->t_size = size; - - /* LINTED - pointer alignment */ - data = *((uint_t *)dptr); - dptr += sizeof (uint_t); - - ip = xcalloc(sizeof (intr_t)); - ip->intr_type = INTR_REAL; - ip->intr_fformat = CTF_FP_ENCODING(data); - ip->intr_offset = CTF_FP_OFFSET(data); - ip->intr_nbits = CTF_FP_BITS(data); - tdp->t_intr = ip; - break; - - case CTF_K_POINTER: - tdp->t_type = POINTER; - tdp->t_tdesc = tdarr[ctt->ctt_type]; - break; - - case CTF_K_ARRAY: - tdp->t_type = ARRAY; - tdp->t_size = size; - - /* LINTED - pointer alignment */ - cta = (ctf_array_t *)dptr; - dptr += sizeof (ctf_array_t); - - tdp->t_ardef = xmalloc(sizeof (ardef_t)); - tdp->t_ardef->ad_contents = tdarr[cta->cta_contents]; - tdp->t_ardef->ad_idxtype = tdarr[cta->cta_index]; - tdp->t_ardef->ad_nelems = cta->cta_nelems; - break; - - case CTF_K_STRUCT: - case CTF_K_UNION: - tdp->t_type = (kind == CTF_K_STRUCT ? STRUCT : UNION); - tdp->t_size = size; - - if (size < CTF_LSTRUCT_THRESH) { - for (i = 0, mpp = &tdp->t_members; i < vlen; - i++, mpp = &((*mpp)->ml_next)) { - /* LINTED - pointer alignment */ - ctf_member_t *ctm = (ctf_member_t *) - dptr; - dptr += sizeof (ctf_member_t); - - *mpp = xmalloc(sizeof (mlist_t)); - (*mpp)->ml_name = xstrdup(sbuf + - ctm->ctm_name); - (*mpp)->ml_type = tdarr[ctm->ctm_type]; - (*mpp)->ml_offset = ctm->ctm_offset; - (*mpp)->ml_size = 0; - } - } else { - for (i = 0, mpp = &tdp->t_members; i < vlen; - i++, mpp = &((*mpp)->ml_next)) { - /* LINTED - pointer alignment */ - ctf_lmember_t *ctlm = (ctf_lmember_t *) - dptr; - dptr += sizeof (ctf_lmember_t); - - *mpp = xmalloc(sizeof (mlist_t)); - (*mpp)->ml_name = xstrdup(sbuf + - ctlm->ctlm_name); - (*mpp)->ml_type = - tdarr[ctlm->ctlm_type]; - (*mpp)->ml_offset = - (int)CTF_LMEM_OFFSET(ctlm); - (*mpp)->ml_size = 0; - } - } - - *mpp = NULL; - break; - - case CTF_K_ENUM: - tdp->t_type = ENUM; - tdp->t_size = size; - - for (i = 0, epp = &tdp->t_emem; i < vlen; - i++, epp = &((*epp)->el_next)) { - /* LINTED - pointer alignment */ - cte = (ctf_enum_t *)dptr; - dptr += sizeof (ctf_enum_t); - - *epp = xmalloc(sizeof (elist_t)); - (*epp)->el_name = xstrdup(sbuf + cte->cte_name); - (*epp)->el_number = cte->cte_value; - } - *epp = NULL; - break; - - case CTF_K_FORWARD: - tdp->t_type = FORWARD; - list_add(&td->td_fwdlist, tdp); - break; - - case CTF_K_TYPEDEF: - tdp->t_type = TYPEDEF; - tdp->t_tdesc = tdarr[ctt->ctt_type]; - break; - - case CTF_K_VOLATILE: - tdp->t_type = VOLATILE; - tdp->t_tdesc = tdarr[ctt->ctt_type]; - break; - - case CTF_K_CONST: - tdp->t_type = CONST; - tdp->t_tdesc = tdarr[ctt->ctt_type]; - break; - - case CTF_K_FUNCTION: - tdp->t_type = FUNCTION; - tdp->t_fndef = xcalloc(sizeof (fndef_t)); - tdp->t_fndef->fn_ret = tdarr[ctt->ctt_type]; - - /* LINTED - pointer alignment */ - if (vlen > 0 && *(ushort_t *)(dptr + - (sizeof (ushort_t) * (vlen - 1))) == 0) - tdp->t_fndef->fn_vargs = 1; - - tdp->t_fndef->fn_nargs = vlen - tdp->t_fndef->fn_vargs; - tdp->t_fndef->fn_args = xcalloc(sizeof (tdesc_t) * - vlen - tdp->t_fndef->fn_vargs); - - for (i = 0; i < vlen; i++) { - /* LINTED - pointer alignment */ - argid = *(ushort_t *)dptr; - dptr += sizeof (ushort_t); - - if (argid != 0) - tdp->t_fndef->fn_args[i] = tdarr[argid]; - } - - if (vlen & 1) - dptr += sizeof (ushort_t); - break; - - case CTF_K_RESTRICT: - tdp->t_type = RESTRICT; - tdp->t_tdesc = tdarr[ctt->ctt_type]; - break; - - case CTF_K_UNKNOWN: - break; - - default: - warning("Can't parse unknown CTF type %d\n", kind); - } - - if (CTF_INFO_ISROOT(ctt->ctt_info)) { - iidesc_t *ii = iidesc_new(tdp->t_name); - if (tdp->t_type == STRUCT || tdp->t_type == UNION || - tdp->t_type == ENUM) - ii->ii_type = II_SOU; - else - ii->ii_type = II_TYPE; - ii->ii_dtype = tdp; - hash_add(td->td_iihash, ii); - - iicnt++; - } - - debug(3, "Resurrected %d %stype %s (%d)\n", tdp->t_type, - (CTF_INFO_ISROOT(ctt->ctt_info) ? "root " : ""), - tdesc_name(tdp), tdp->t_id); - } - - debug(3, "Resurrected %d types (%d were roots)\n", tcnt, iicnt); -} - -/* - * For lack of other inspiration, we're going to take the boring route. We - * count the number of types. This lets us malloc that many tdesc structs - * before we start filling them in. This has the advantage of allowing us to - * avoid a merge-esque remap step. - */ -static tdata_t * -ctf_parse(ctf_header_t *h, caddr_t buf, symit_data_t *si, char *label) -{ - tdata_t *td = tdata_new(); - tdesc_t **tdarr; - int ntypes = count_types(h, buf); - int idx, i; - - /* shudder */ - tdarr = xcalloc(sizeof (tdesc_t *) * (ntypes + 1)); - tdarr[0] = NULL; - for (i = 1; i <= ntypes; i++) { - tdarr[i] = xcalloc(sizeof (tdesc_t)); - tdarr[i]->t_id = i; - } - - td->td_parlabel = xstrdup(buf + h->cth_stroff + h->cth_parlabel); - - /* we have the technology - we can rebuild them */ - idx = resurrect_labels(h, td, buf, label); - - resurrect_objects(h, td, tdarr, ntypes + 1, buf, si); - resurrect_functions(h, td, tdarr, ntypes + 1, buf, si); - resurrect_types(h, td, tdarr, ntypes + 1, buf, idx); - - free(tdarr); - - td->td_nextid = ntypes + 1; - - return (td); -} - -static size_t -decompress_ctf(caddr_t cbuf, size_t cbufsz, caddr_t dbuf, size_t dbufsz) -{ - z_stream zstr; - int rc; - - zstr.zalloc = (alloc_func)0; - zstr.zfree = (free_func)0; - zstr.opaque = (voidpf)0; - - zstr.next_in = (Bytef *)cbuf; - zstr.avail_in = cbufsz; - zstr.next_out = (Bytef *)dbuf; - zstr.avail_out = dbufsz; - - if ((rc = inflateInit(&zstr)) != Z_OK || - (rc = inflate(&zstr, Z_NO_FLUSH)) != Z_STREAM_END || - (rc = inflateEnd(&zstr)) != Z_OK) { - warning("CTF decompress zlib error %s\n", zError(rc)); - return (0); - } - - debug(3, "reflated %lu bytes to %lu, pointer at %d\n", - zstr.total_in, zstr.total_out, (caddr_t)zstr.next_in - cbuf); - - return (zstr.total_out); -} - -/* - * Reconstruct the type tree from a given buffer of CTF data. Only the types - * up to the type associated with the provided label, inclusive, will be - * reconstructed. If a NULL label is provided, all types will be reconstructed. - * - * This function won't work on files that have been uniquified. - */ -tdata_t * -ctf_load(char *file, caddr_t buf, size_t bufsz, symit_data_t *si, char *label) -{ - ctf_header_t *h; - caddr_t ctfdata; - size_t ctfdatasz; - tdata_t *td; - - curfile = file; - - if (bufsz < sizeof (ctf_header_t)) - parseterminate("Corrupt CTF - short header"); - - /* LINTED - pointer alignment */ - h = (ctf_header_t *)buf; - buf += sizeof (ctf_header_t); - bufsz -= sizeof (ctf_header_t); - - if (h->cth_magic != CTF_MAGIC) - parseterminate("Corrupt CTF - bad magic 0x%x", h->cth_magic); - - if (h->cth_version != CTF_VERSION) - parseterminate("Unknown CTF version %d", h->cth_version); - - ctfdatasz = h->cth_stroff + h->cth_strlen; - if (h->cth_flags & CTF_F_COMPRESS) { - size_t actual; - - ctfdata = xmalloc(ctfdatasz); - if ((actual = decompress_ctf(buf, bufsz, ctfdata, ctfdatasz)) != - ctfdatasz) { - parseterminate("Corrupt CTF - short decompression " - "(was %d, expecting %d)", actual, ctfdatasz); - } - } else { - ctfdata = buf; - ctfdatasz = bufsz; - } - - td = ctf_parse(h, ctfdata, si, label); - - if (h->cth_flags & CTF_F_COMPRESS) - free(ctfdata); - - curfile = NULL; - - return (td); -} diff --git a/usr/src/tools/ctf/cvt/ctfconvert.c b/usr/src/tools/ctf/cvt/ctfconvert.c deleted file mode 100644 index af005e1934..0000000000 --- a/usr/src/tools/ctf/cvt/ctfconvert.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * Given a file containing sections with stabs data, convert the stabs data to - * CTF data, and replace the stabs sections with a CTF section. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <signal.h> -#include <string.h> -#include <fcntl.h> -#include <libgen.h> -#include <errno.h> -#include <assert.h> - -#include "ctftools.h" -#include "memory.h" - -const char *progname; -int debug_level = DEBUG_LEVEL; - -static const char *infile = NULL; -static const char *outfile = NULL; -static int dynsym; - -static void -usage(void) -{ - (void) fprintf(stderr, - "Usage: %s [-is] -l label | -L labelenv [-o outfile] object_file\n" - "\n" - " Note: if -L labelenv is specified and labelenv is not set in\n" - " the environment, a default value is used.\n", - progname); -} - -static void -terminate_cleanup(void) -{ - if (!outfile) { - fprintf(stderr, "Removing %s\n", infile); - unlink(infile); - } -} - -static void -handle_sig(int sig) -{ - terminate("Caught signal %d - exiting\n", sig); -} - -static int -file_read(tdata_t *td, const char *filename, int ignore_non_c) -{ - typedef int (*reader_f)(tdata_t *, Elf *, const char *); - static const reader_f readers[] = { - stabs_read, - dw_read, - NULL - }; - - source_types_t source_types; - Elf *elf; - int i, rc, fd; - - if ((fd = open(filename, O_RDONLY)) < 0) - terminate("failed to open %s", filename); - - (void) elf_version(EV_CURRENT); - - if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { - close(fd); - terminate("failed to read %s: %s\n", filename, - elf_errmsg(-1)); - } - - source_types = built_source_types(elf, filename); - - if ((source_types == SOURCE_NONE || (source_types & SOURCE_UNKNOWN)) && - ignore_non_c) { - debug(1, "Ignoring file %s from unknown sources\n", filename); - exit(0); - } - - for (i = 0; readers[i] != NULL; i++) { - if ((rc = readers[i](td, elf, filename)) == 0) - break; - - assert(rc < 0 && errno == ENOENT); - } - - if (readers[i] == NULL) { - /* - * None of the readers found compatible type data. - */ - - if (findelfsecidx(elf, filename, ".debug") >= 0) { - terminate("%s: DWARF version 1 is not supported\n", - filename); - } - - if (!(source_types & SOURCE_C) && ignore_non_c) { - debug(1, "Ignoring file %s not built from C sources\n", - filename); - exit(0); - } - - rc = 0; - } else { - rc = 1; - } - - (void) elf_end(elf); - (void) close(fd); - - return (rc); -} - -int -main(int argc, char **argv) -{ - tdata_t *filetd, *mstrtd; - char *label = NULL; - char *altexec; - int verbose = 0; - int ignore_non_c = 0; - int c; - - sighold(SIGINT); - sighold(SIGQUIT); - sighold(SIGTERM); - - progname = basename(argv[0]); - - ctf_altexec("CTFCONVERT_ALTEXEC", argc, argv); - - if (getenv("CTFCONVERT_DEBUG_LEVEL")) - debug_level = atoi(getenv("CTFCONVERT_DEBUG_LEVEL")); - if (getenv("CTFCONVERT_DEBUG_PARSE")) - debug_parse = atoi(getenv("CTFCONVERT_DEBUG_PARSE")); - - if ((altexec = getenv("CTFCONVERT_ALTEXEC")) != NULL) { - (void) unsetenv("CTFCONVERT_ALTEXEC"); - (void) execv(altexec, argv); - (void) fprintf(stderr, "ctfconvert altexec failed to " - "run %s: %s\n", altexec, strerror(errno)); - } - - while ((c = getopt(argc, argv, ":l:L:o:givs")) != EOF) { - switch (c) { - case 'l': - label = optarg; - break; - case 'L': - if ((label = getenv(optarg)) == NULL) - label = CTF_DEFAULT_LABEL; - break; - case 'o': - outfile = optarg; - break; - case 's': - dynsym = CTF_USE_DYNSYM; - break; - case 'i': - ignore_non_c = 1; - break; - case 'v': - verbose = 1; - break; - default: - usage(); - exit(2); - } - } - - if (argc - optind != 1 || label == NULL) { - usage(); - exit(2); - } - - infile = argv[optind]; - if (access(infile, R_OK) != 0) - terminate("Can't access %s", infile); - - /* - * Upon receipt of a signal, we want to clean up and exit. Our - * primary goal during cleanup is to restore the system to a state - * such that a subsequent make will eventually cause this command to - * be re-run. If we remove the input file (which we do if we get a - * signal and the user didn't specify a separate output file), make - * will need to rebuild the input file, and will then need to re-run - * ctfconvert, which is what we want. - */ - set_terminate_cleanup(terminate_cleanup); - - sigset(SIGINT, handle_sig); - sigset(SIGQUIT, handle_sig); - sigset(SIGTERM, handle_sig); - - filetd = tdata_new(); - - if (!file_read(filetd, infile, ignore_non_c)) - terminate("%s doesn't have type data to convert\n", infile); - - if (verbose) - iidesc_stats(filetd->td_iihash); - - mstrtd = tdata_new(); - merge_into_master(filetd, mstrtd, NULL, 1); - - tdata_label_add(mstrtd, label, CTF_LABEL_LASTIDX); - - /* - * If the user supplied an output file that is different from the - * input file, write directly to the output file. Otherwise, write - * to a temporary file, and replace the input file when we're done. - */ - if (outfile && strcmp(infile, outfile) != 0) { - write_ctf(mstrtd, infile, outfile, dynsym); - } else { - char *tmpname = mktmpname(infile, ".ctf"); - - write_ctf(mstrtd, infile, tmpname, dynsym); - if (rename(tmpname, infile) != 0) - terminate("Couldn't rename temp file %s", tmpname); - free(tmpname); - } - - return (0); -} diff --git a/usr/src/tools/ctf/cvt/ctfmerge.c b/usr/src/tools/ctf/cvt/ctfmerge.c deleted file mode 100644 index d2db789e5f..0000000000 --- a/usr/src/tools/ctf/cvt/ctfmerge.c +++ /dev/null @@ -1,1004 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * Given several files containing CTF data, merge and uniquify that data into - * a single CTF section in an output file. - * - * Merges can proceed independently. As such, we perform the merges in parallel - * using a worker thread model. A given glob of CTF data (either all of the CTF - * data from a single input file, or the result of one or more merges) can only - * be involved in a single merge at any given time, so the process decreases in - * parallelism, especially towards the end, as more and more files are - * consolidated, finally resulting in a single merge of two large CTF graphs. - * Unfortunately, the last merge is also the slowest, as the two graphs being - * merged are each the product of merges of half of the input files. - * - * The algorithm consists of two phases, described in detail below. The first - * phase entails the merging of CTF data in groups of eight. The second phase - * takes the results of Phase I, and merges them two at a time. This disparity - * is due to an observation that the merge time increases at least quadratically - * with the size of the CTF data being merged. As such, merges of CTF graphs - * newly read from input files are much faster than merges of CTF graphs that - * are themselves the results of prior merges. - * - * A further complication is the need to ensure the repeatability of CTF merges. - * That is, a merge should produce the same output every time, given the same - * input. In both phases, this consistency requirement is met by imposing an - * ordering on the merge process, thus ensuring that a given set of input files - * are merged in the same order every time. - * - * Phase I - * - * The main thread reads the input files one by one, transforming the CTF - * data they contain into tdata structures. When a given file has been read - * and parsed, it is placed on the work queue for retrieval by worker threads. - * - * Central to Phase I is the Work In Progress (wip) array, which is used to - * merge batches of files in a predictable order. Files are read by the main - * thread, and are merged into wip array elements in round-robin order. When - * the number of files merged into a given array slot equals the batch size, - * the merged CTF graph in that array is added to the done slot in order by - * array slot. - * - * For example, consider a case where we have five input files, a batch size - * of two, a wip array size of two, and two worker threads (T1 and T2). - * - * 1. The wip array elements are assigned initial batch numbers 0 and 1. - * 2. T1 reads an input file from the input queue (wq_queue). This is the - * first input file, so it is placed into wip[0]. The second file is - * similarly read and placed into wip[1]. The wip array slots now contain - * one file each (wip_nmerged == 1). - * 3. T1 reads the third input file, which it merges into wip[0]. The - * number of files in wip[0] is equal to the batch size. - * 4. T2 reads the fourth input file, which it merges into wip[1]. wip[1] - * is now full too. - * 5. T2 attempts to place the contents of wip[1] on the done queue - * (wq_done_queue), but it can't, since the batch ID for wip[1] is 1. - * Batch 0 needs to be on the done queue before batch 1 can be added, so - * T2 blocks on wip[1]'s cv. - * 6. T1 attempts to place the contents of wip[0] on the done queue, and - * succeeds, updating wq_lastdonebatch to 0. It clears wip[0], and sets - * its batch ID to 2. T1 then signals wip[1]'s cv to awaken T2. - * 7. T2 wakes up, notices that wq_lastdonebatch is 0, which means that - * batch 1 can now be added. It adds wip[1] to the done queue, clears - * wip[1], and sets its batch ID to 3. It signals wip[0]'s cv, and - * restarts. - * - * The above process continues until all input files have been consumed. At - * this point, a pair of barriers are used to allow a single thread to move - * any partial batches from the wip array to the done array in batch ID order. - * When this is complete, wq_done_queue is moved to wq_queue, and Phase II - * begins. - * - * Locking Semantics (Phase I) - * - * The input queue (wq_queue) and the done queue (wq_done_queue) are - * protected by separate mutexes - wq_queue_lock and wq_done_queue. wip - * array slots are protected by their own mutexes, which must be grabbed - * before releasing the input queue lock. The wip array lock is dropped - * when the thread restarts the loop. If the array slot was full, the - * array lock will be held while the slot contents are added to the done - * queue. The done queue lock is used to protect the wip slot cv's. - * - * The pow number is protected by the queue lock. The master batch ID - * and last completed batch (wq_lastdonebatch) counters are protected *in - * Phase I* by the done queue lock. - * - * Phase II - * - * When Phase II begins, the queue consists of the merged batches from the - * first phase. Assume we have five batches: - * - * Q: a b c d e - * - * Using the same batch ID mechanism we used in Phase I, but without the wip - * array, worker threads remove two entries at a time from the beginning of - * the queue. These two entries are merged, and are added back to the tail - * of the queue, as follows: - * - * Q: a b c d e # start - * Q: c d e ab # a, b removed, merged, added to end - * Q: e ab cd # c, d removed, merged, added to end - * Q: cd eab # e, ab removed, merged, added to end - * Q: cdeab # cd, eab removed, merged, added to end - * - * When one entry remains on the queue, with no merges outstanding, Phase II - * finishes. We pre-determine the stopping point by pre-calculating the - * number of nodes that will appear on the list. In the example above, the - * number (wq_ninqueue) is 9. When ninqueue is 1, we conclude Phase II by - * signaling the main thread via wq_done_cv. - * - * Locking Semantics (Phase II) - * - * The queue (wq_queue), ninqueue, and the master batch ID and last - * completed batch counters are protected by wq_queue_lock. The done - * queue and corresponding lock are unused in Phase II as is the wip array. - * - * Uniquification - * - * We want the CTF data that goes into a given module to be as small as - * possible. For example, we don't want it to contain any type data that may - * be present in another common module. As such, after creating the master - * tdata_t for a given module, we can, if requested by the user, uniquify it - * against the tdata_t from another module (genunix in the case of the SunOS - * kernel). We perform a merge between the tdata_t for this module and the - * tdata_t from genunix. Nodes found in this module that are not present in - * genunix are added to a third tdata_t - the uniquified tdata_t. - * - * Additive Merges - * - * In some cases, for example if we are issuing a new version of a common - * module in a patch, we need to make sure that the CTF data already present - * in that module does not change. Changes to this data would void the CTF - * data in any module that uniquified against the common module. To preserve - * the existing data, we can perform what is known as an additive merge. In - * this case, a final uniquification is performed against the CTF data in the - * previous version of the module. The result will be the placement of new - * and changed data after the existing data, thus preserving the existing type - * ID space. - * - * Saving the result - * - * When the merges are complete, the resulting tdata_t is placed into the - * output file, replacing the .SUNW_ctf section (if any) already in that file. - * - * The person who changes the merging thread code in this file without updating - * this comment will not live to see the stock hit five. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <pthread.h> -#include <assert.h> -#include <synch.h> -#include <signal.h> -#include <libgen.h> -#include <string.h> -#include <errno.h> -#include <alloca.h> -#include <sys/param.h> -#include <sys/types.h> -#include <sys/mman.h> -#include <sys/sysconf.h> - -#include "ctf_headers.h" -#include "ctftools.h" -#include "ctfmerge.h" -#include "traverse.h" -#include "memory.h" -#include "fifo.h" -#include "barrier.h" - -#pragma init(bigheap) - -#define MERGE_PHASE1_BATCH_SIZE 8 -#define MERGE_PHASE1_MAX_SLOTS 5 -#define MERGE_INPUT_THROTTLE_LEN 10 - -const char *progname; -static char *outfile = NULL; -static char *tmpname = NULL; -static int dynsym; -int debug_level = DEBUG_LEVEL; -static size_t maxpgsize = 0x400000; - - -void -usage(void) -{ - (void) fprintf(stderr, - "Usage: %s [-fstv] -l label | -L labelenv -o outfile file ...\n" - " %s [-fstv] -l label | -L labelenv -o outfile -d uniqfile\n" - " %*s [-D uniqlabel] file ...\n" - " %s [-fstv] -l label | -L labelenv -o outfile -w withfile " - "file ...\n" - " %s -c srcfile destfile\n" - "\n" - " Note: if -L labelenv is specified and labelenv is not set in\n" - " the environment, a default value is used.\n", - progname, progname, strlen(progname), " ", - progname, progname); -} - -static void -bigheap(void) -{ - size_t big, *size; - int sizes; - struct memcntl_mha mha; - - /* - * First, get the available pagesizes. - */ - if ((sizes = getpagesizes(NULL, 0)) == -1) - return; - - if (sizes == 1 || (size = alloca(sizeof (size_t) * sizes)) == NULL) - return; - - if (getpagesizes(size, sizes) == -1) - return; - - while (size[sizes - 1] > maxpgsize) - sizes--; - - /* set big to the largest allowed page size */ - big = size[sizes - 1]; - if (big & (big - 1)) { - /* - * The largest page size is not a power of two for some - * inexplicable reason; return. - */ - return; - } - - /* - * Now, align our break to the largest page size. - */ - if (brk((void *)((((uintptr_t)sbrk(0) - 1) & ~(big - 1)) + big)) != 0) - return; - - /* - * set the preferred page size for the heap - */ - mha.mha_cmd = MHA_MAPSIZE_BSSBRK; - mha.mha_flags = 0; - mha.mha_pagesize = big; - - (void) memcntl(NULL, 0, MC_HAT_ADVISE, (caddr_t)&mha, 0, 0); -} - -static void -finalize_phase_one(workqueue_t *wq) -{ - int startslot, i; - - /* - * wip slots are cleared out only when maxbatchsz td's have been merged - * into them. We're not guaranteed that the number of files we're - * merging is a multiple of maxbatchsz, so there will be some partial - * groups in the wip array. Move them to the done queue in batch ID - * order, starting with the slot containing the next batch that would - * have been placed on the done queue, followed by the others. - * One thread will be doing this while the others wait at the barrier - * back in worker_thread(), so we don't need to worry about pesky things - * like locks. - */ - - for (startslot = -1, i = 0; i < wq->wq_nwipslots; i++) { - if (wq->wq_wip[i].wip_batchid == wq->wq_lastdonebatch + 1) { - startslot = i; - break; - } - } - - assert(startslot != -1); - - for (i = startslot; i < startslot + wq->wq_nwipslots; i++) { - int slotnum = i % wq->wq_nwipslots; - wip_t *wipslot = &wq->wq_wip[slotnum]; - - if (wipslot->wip_td != NULL) { - debug(2, "clearing slot %d (%d) (saving %d)\n", - slotnum, i, wipslot->wip_nmerged); - } else - debug(2, "clearing slot %d (%d)\n", slotnum, i); - - if (wipslot->wip_td != NULL) { - fifo_add(wq->wq_donequeue, wipslot->wip_td); - wq->wq_wip[slotnum].wip_td = NULL; - } - } - - wq->wq_lastdonebatch = wq->wq_next_batchid++; - - debug(2, "phase one done: donequeue has %d items\n", - fifo_len(wq->wq_donequeue)); -} - -static void -init_phase_two(workqueue_t *wq) -{ - int num; - - /* - * We're going to continually merge the first two entries on the queue, - * placing the result on the end, until there's nothing left to merge. - * At that point, everything will have been merged into one. The - * initial value of ninqueue needs to be equal to the total number of - * entries that will show up on the queue, both at the start of the - * phase and as generated by merges during the phase. - */ - wq->wq_ninqueue = num = fifo_len(wq->wq_donequeue); - while (num != 1) { - wq->wq_ninqueue += num / 2; - num = num / 2 + num % 2; - } - - /* - * Move the done queue to the work queue. We won't be using the done - * queue in phase 2. - */ - assert(fifo_len(wq->wq_queue) == 0); - fifo_free(wq->wq_queue, NULL); - wq->wq_queue = wq->wq_donequeue; -} - -static void -wip_save_work(workqueue_t *wq, wip_t *slot, int slotnum) -{ - pthread_mutex_lock(&wq->wq_donequeue_lock); - - while (wq->wq_lastdonebatch + 1 < slot->wip_batchid) - pthread_cond_wait(&slot->wip_cv, &wq->wq_donequeue_lock); - assert(wq->wq_lastdonebatch + 1 == slot->wip_batchid); - - fifo_add(wq->wq_donequeue, slot->wip_td); - wq->wq_lastdonebatch++; - pthread_cond_signal(&wq->wq_wip[(slotnum + 1) % - wq->wq_nwipslots].wip_cv); - - /* reset the slot for next use */ - slot->wip_td = NULL; - slot->wip_batchid = wq->wq_next_batchid++; - - pthread_mutex_unlock(&wq->wq_donequeue_lock); -} - -static void -wip_add_work(wip_t *slot, tdata_t *pow) -{ - if (slot->wip_td == NULL) { - slot->wip_td = pow; - slot->wip_nmerged = 1; - } else { - debug(2, "%d: merging %p into %p\n", pthread_self(), - (void *)pow, (void *)slot->wip_td); - - merge_into_master(pow, slot->wip_td, NULL, 0); - tdata_free(pow); - - slot->wip_nmerged++; - } -} - -static void -worker_runphase1(workqueue_t *wq) -{ - wip_t *wipslot; - tdata_t *pow; - int wipslotnum, pownum; - - for (;;) { - pthread_mutex_lock(&wq->wq_queue_lock); - - while (fifo_empty(wq->wq_queue)) { - if (wq->wq_nomorefiles == 1) { - pthread_cond_broadcast(&wq->wq_work_avail); - pthread_mutex_unlock(&wq->wq_queue_lock); - - /* on to phase 2 ... */ - return; - } - - pthread_cond_wait(&wq->wq_work_avail, - &wq->wq_queue_lock); - } - - /* there's work to be done! */ - pow = fifo_remove(wq->wq_queue); - pownum = wq->wq_nextpownum++; - pthread_cond_broadcast(&wq->wq_work_removed); - - assert(pow != NULL); - - /* merge it into the right slot */ - wipslotnum = pownum % wq->wq_nwipslots; - wipslot = &wq->wq_wip[wipslotnum]; - - pthread_mutex_lock(&wipslot->wip_lock); - - pthread_mutex_unlock(&wq->wq_queue_lock); - - wip_add_work(wipslot, pow); - - if (wipslot->wip_nmerged == wq->wq_maxbatchsz) - wip_save_work(wq, wipslot, wipslotnum); - - pthread_mutex_unlock(&wipslot->wip_lock); - } -} - -static void -worker_runphase2(workqueue_t *wq) -{ - tdata_t *pow1, *pow2; - int batchid; - - for (;;) { - pthread_mutex_lock(&wq->wq_queue_lock); - - if (wq->wq_ninqueue == 1) { - pthread_cond_broadcast(&wq->wq_work_avail); - pthread_mutex_unlock(&wq->wq_queue_lock); - - debug(2, "%d: entering p2 completion barrier\n", - pthread_self()); - if (barrier_wait(&wq->wq_bar1)) { - pthread_mutex_lock(&wq->wq_queue_lock); - wq->wq_alldone = 1; - pthread_cond_signal(&wq->wq_alldone_cv); - pthread_mutex_unlock(&wq->wq_queue_lock); - } - - return; - } - - if (fifo_len(wq->wq_queue) < 2) { - pthread_cond_wait(&wq->wq_work_avail, - &wq->wq_queue_lock); - pthread_mutex_unlock(&wq->wq_queue_lock); - continue; - } - - /* there's work to be done! */ - pow1 = fifo_remove(wq->wq_queue); - pow2 = fifo_remove(wq->wq_queue); - wq->wq_ninqueue -= 2; - - batchid = wq->wq_next_batchid++; - - pthread_mutex_unlock(&wq->wq_queue_lock); - - debug(2, "%d: merging %p into %p\n", pthread_self(), - (void *)pow1, (void *)pow2); - merge_into_master(pow1, pow2, NULL, 0); - tdata_free(pow1); - - /* - * merging is complete. place at the tail of the queue in - * proper order. - */ - pthread_mutex_lock(&wq->wq_queue_lock); - while (wq->wq_lastdonebatch + 1 != batchid) { - pthread_cond_wait(&wq->wq_done_cv, - &wq->wq_queue_lock); - } - - wq->wq_lastdonebatch = batchid; - - fifo_add(wq->wq_queue, pow2); - debug(2, "%d: added %p to queue, len now %d, ninqueue %d\n", - pthread_self(), (void *)pow2, fifo_len(wq->wq_queue), - wq->wq_ninqueue); - pthread_cond_broadcast(&wq->wq_done_cv); - pthread_cond_signal(&wq->wq_work_avail); - pthread_mutex_unlock(&wq->wq_queue_lock); - } -} - -/* - * Main loop for worker threads. - */ -static void * -worker_thread(void *ptr) -{ - workqueue_t *wq = ptr; - - worker_runphase1(wq); - - debug(2, "%d: entering first barrier\n", pthread_self()); - - if (barrier_wait(&wq->wq_bar1)) { - - debug(2, "%d: doing work in first barrier\n", pthread_self()); - - finalize_phase_one(wq); - - init_phase_two(wq); - - debug(2, "%d: ninqueue is %d, %d on queue\n", pthread_self(), - wq->wq_ninqueue, fifo_len(wq->wq_queue)); - } - - debug(2, "%d: entering second barrier\n", pthread_self()); - - (void) barrier_wait(&wq->wq_bar2); - - debug(2, "%d: phase 1 complete\n", pthread_self()); - - worker_runphase2(wq); - return (NULL); -} - -/* - * Pass a tdata_t tree, built from an input file, off to the work queue for - * consumption by worker threads. - */ -static int -merge_ctf_cb(tdata_t *td, char *name, void *arg) -{ - workqueue_t *wq = arg; - - debug(3, "Adding tdata %p for processing\n", (void *)td); - - pthread_mutex_lock(&wq->wq_queue_lock); - while (fifo_len(wq->wq_queue) > wq->wq_ithrottle) { - debug(2, "Throttling input (len = %d, throttle = %d)\n", - fifo_len(wq->wq_queue), wq->wq_ithrottle); - pthread_cond_wait(&wq->wq_work_removed, &wq->wq_queue_lock); - } - - fifo_add(wq->wq_queue, td); - debug(1, "Thread %d announcing %s\n", pthread_self(), name); - pthread_cond_broadcast(&wq->wq_work_avail); - pthread_mutex_unlock(&wq->wq_queue_lock); - - return (1); -} - -/* - * This program is intended to be invoked from a Makefile, as part of the build. - * As such, in the event of a failure or user-initiated interrupt (^C), we need - * to ensure that a subsequent re-make will cause ctfmerge to be executed again. - * Unfortunately, ctfmerge will usually be invoked directly after (and as part - * of the same Makefile rule as) a link, and will operate on the linked file - * in place. If we merely exit upon receipt of a SIGINT, a subsequent make - * will notice that the *linked* file is newer than the object files, and thus - * will not reinvoke ctfmerge. The only way to ensure that a subsequent make - * reinvokes ctfmerge, is to remove the file to which we are adding CTF - * data (confusingly named the output file). This means that the link will need - * to happen again, but links are generally fast, and we can't allow the merge - * to be skipped. - * - * Another possibility would be to block SIGINT entirely - to always run to - * completion. The run time of ctfmerge can, however, be measured in minutes - * in some cases, so this is not a valid option. - */ -static void -handle_sig(int sig) -{ - terminate("Caught signal %d - exiting\n", sig); -} - -static void -terminate_cleanup(void) -{ - int dounlink = getenv("CTFMERGE_TERMINATE_NO_UNLINK") ? 0 : 1; - - if (tmpname != NULL && dounlink) - unlink(tmpname); - - if (outfile == NULL) - return; - - if (dounlink) { - fprintf(stderr, "Removing %s\n", outfile); - unlink(outfile); - } -} - -static void -copy_ctf_data(char *srcfile, char *destfile) -{ - tdata_t *srctd; - - if (read_ctf(&srcfile, 1, NULL, read_ctf_save_cb, &srctd, 1) == 0) - terminate("No CTF data found in source file %s\n", srcfile); - - tmpname = mktmpname(destfile, ".ctf"); - write_ctf(srctd, destfile, tmpname, CTF_COMPRESS); - if (rename(tmpname, destfile) != 0) { - terminate("Couldn't rename temp file %s to %s", tmpname, - destfile); - } - free(tmpname); - tdata_free(srctd); -} - -static void -wq_init(workqueue_t *wq, int nfiles) -{ - int throttle, nslots, i; - - if (getenv("CTFMERGE_MAX_SLOTS")) - nslots = atoi(getenv("CTFMERGE_MAX_SLOTS")); - else - nslots = MERGE_PHASE1_MAX_SLOTS; - - if (getenv("CTFMERGE_PHASE1_BATCH_SIZE")) - wq->wq_maxbatchsz = atoi(getenv("CTFMERGE_PHASE1_BATCH_SIZE")); - else - wq->wq_maxbatchsz = MERGE_PHASE1_BATCH_SIZE; - - nslots = MIN(nslots, (nfiles + wq->wq_maxbatchsz - 1) / - wq->wq_maxbatchsz); - - wq->wq_wip = xcalloc(sizeof (wip_t) * nslots); - wq->wq_nwipslots = nslots; - wq->wq_nthreads = MIN(sysconf(_SC_NPROCESSORS_ONLN) * 3 / 2, nslots); - wq->wq_thread = xmalloc(sizeof (pthread_t) * wq->wq_nthreads); - - if (getenv("CTFMERGE_INPUT_THROTTLE")) - throttle = atoi(getenv("CTFMERGE_INPUT_THROTTLE")); - else - throttle = MERGE_INPUT_THROTTLE_LEN; - wq->wq_ithrottle = throttle * wq->wq_nthreads; - - debug(1, "Using %d slots, %d threads\n", wq->wq_nwipslots, - wq->wq_nthreads); - - wq->wq_next_batchid = 0; - - for (i = 0; i < nslots; i++) { - pthread_mutex_init(&wq->wq_wip[i].wip_lock, NULL); - wq->wq_wip[i].wip_batchid = wq->wq_next_batchid++; - } - - pthread_mutex_init(&wq->wq_queue_lock, NULL); - wq->wq_queue = fifo_new(); - pthread_cond_init(&wq->wq_work_avail, NULL); - pthread_cond_init(&wq->wq_work_removed, NULL); - wq->wq_ninqueue = nfiles; - wq->wq_nextpownum = 0; - - pthread_mutex_init(&wq->wq_donequeue_lock, NULL); - wq->wq_donequeue = fifo_new(); - wq->wq_lastdonebatch = -1; - - pthread_cond_init(&wq->wq_done_cv, NULL); - - pthread_cond_init(&wq->wq_alldone_cv, NULL); - wq->wq_alldone = 0; - - barrier_init(&wq->wq_bar1, wq->wq_nthreads); - barrier_init(&wq->wq_bar2, wq->wq_nthreads); - - wq->wq_nomorefiles = 0; -} - -static void -start_threads(workqueue_t *wq) -{ - sigset_t sets; - int i; - - sigemptyset(&sets); - sigaddset(&sets, SIGINT); - sigaddset(&sets, SIGQUIT); - sigaddset(&sets, SIGTERM); - pthread_sigmask(SIG_BLOCK, &sets, NULL); - - for (i = 0; i < wq->wq_nthreads; i++) { - pthread_create(&wq->wq_thread[i], NULL, - worker_thread, wq); - } - - sigset(SIGINT, handle_sig); - sigset(SIGQUIT, handle_sig); - sigset(SIGTERM, handle_sig); - pthread_sigmask(SIG_UNBLOCK, &sets, NULL); -} - -static void -join_threads(workqueue_t *wq) -{ - int i; - - for (i = 0; i < wq->wq_nthreads; i++) { - pthread_join(wq->wq_thread[i], NULL); - } -} - -static int -strcompare(const void *p1, const void *p2) -{ - char *s1 = *((char **)p1); - char *s2 = *((char **)p2); - - return (strcmp(s1, s2)); -} - -/* - * Core work queue structure; passed to worker threads on thread creation - * as the main point of coordination. Allocate as a static structure; we - * could have put this into a local variable in main, but passing a pointer - * into your stack to another thread is fragile at best and leads to some - * hard-to-debug failure modes. - */ -static workqueue_t wq; - -int -main(int argc, char **argv) -{ - tdata_t *mstrtd, *savetd; - char *uniqfile = NULL, *uniqlabel = NULL; - char *withfile = NULL; - char *label = NULL; - char **ifiles, **tifiles; - int verbose = 0, docopy = 0; - int write_fuzzy_match = 0; - int require_ctf = 0; - int nifiles, nielems; - int c, i, idx, tidx, err; - - progname = basename(argv[0]); - - ctf_altexec("CTFMERGE_ALTEXEC", argc, argv); - - if (getenv("CTFMERGE_DEBUG_LEVEL")) - debug_level = atoi(getenv("CTFMERGE_DEBUG_LEVEL")); - - err = 0; - while ((c = getopt(argc, argv, ":cd:D:fl:L:o:tvw:s")) != EOF) { - switch (c) { - case 'c': - docopy = 1; - break; - case 'd': - /* Uniquify against `uniqfile' */ - uniqfile = optarg; - break; - case 'D': - /* Uniquify against label `uniqlabel' in `uniqfile' */ - uniqlabel = optarg; - break; - case 'f': - write_fuzzy_match = CTF_FUZZY_MATCH; - break; - case 'l': - /* Label merged types with `label' */ - label = optarg; - break; - case 'L': - /* Label merged types with getenv(`label`) */ - if ((label = getenv(optarg)) == NULL) - label = CTF_DEFAULT_LABEL; - break; - case 'o': - /* Place merged types in CTF section in `outfile' */ - outfile = optarg; - break; - case 't': - /* Insist *all* object files built from C have CTF */ - require_ctf = 1; - break; - case 'v': - /* More debugging information */ - verbose = 1; - break; - case 'w': - /* Additive merge with data from `withfile' */ - withfile = optarg; - break; - case 's': - /* use the dynsym rather than the symtab */ - dynsym = CTF_USE_DYNSYM; - break; - default: - usage(); - exit(2); - } - } - - /* Validate arguments */ - if (docopy) { - if (uniqfile != NULL || uniqlabel != NULL || label != NULL || - outfile != NULL || withfile != NULL || dynsym != 0) - err++; - - if (argc - optind != 2) - err++; - } else { - if (uniqfile != NULL && withfile != NULL) - err++; - - if (uniqlabel != NULL && uniqfile == NULL) - err++; - - if (outfile == NULL || label == NULL) - err++; - - if (argc - optind == 0) - err++; - } - - if (err) { - usage(); - exit(2); - } - - if (uniqfile && access(uniqfile, R_OK) != 0) { - warning("Uniquification file %s couldn't be opened and " - "will be ignored.\n", uniqfile); - uniqfile = NULL; - } - if (withfile && access(withfile, R_OK) != 0) { - warning("With file %s couldn't be opened and will be " - "ignored.\n", withfile); - withfile = NULL; - } - if (outfile && access(outfile, R_OK|W_OK) != 0) - terminate("Cannot open output file %s for r/w", outfile); - - /* - * This is ugly, but we don't want to have to have a separate tool - * (yet) just for copying an ELF section with our specific requirements, - * so we shoe-horn a copier into ctfmerge. - */ - if (docopy) { - copy_ctf_data(argv[optind], argv[optind + 1]); - - exit(0); - } - - set_terminate_cleanup(terminate_cleanup); - - /* Sort the input files and strip out duplicates */ - nifiles = argc - optind; - ifiles = xmalloc(sizeof (char *) * nifiles); - tifiles = xmalloc(sizeof (char *) * nifiles); - - for (i = 0; i < nifiles; i++) - tifiles[i] = argv[optind + i]; - qsort(tifiles, nifiles, sizeof (char *), (int (*)())strcompare); - - ifiles[0] = tifiles[0]; - for (idx = 0, tidx = 1; tidx < nifiles; tidx++) { - if (strcmp(ifiles[idx], tifiles[tidx]) != 0) - ifiles[++idx] = tifiles[tidx]; - } - nifiles = idx + 1; - - /* Make sure they all exist */ - if ((nielems = count_files(ifiles, nifiles)) < 0) - terminate("Some input files were inaccessible\n"); - - /* Prepare for the merge */ - wq_init(&wq, nielems); - - start_threads(&wq); - - /* - * Start the merge - * - * We're reading everything from each of the object files, so we - * don't need to specify labels. - */ - if (read_ctf(ifiles, nifiles, NULL, merge_ctf_cb, - &wq, require_ctf) == 0) { - /* - * If we're verifying that C files have CTF, it's safe to - * assume that in this case, we're building only from assembly - * inputs. - */ - if (require_ctf) - exit(0); - terminate("No ctf sections found to merge\n"); - } - - pthread_mutex_lock(&wq.wq_queue_lock); - wq.wq_nomorefiles = 1; - pthread_cond_broadcast(&wq.wq_work_avail); - pthread_mutex_unlock(&wq.wq_queue_lock); - - pthread_mutex_lock(&wq.wq_queue_lock); - while (wq.wq_alldone == 0) - pthread_cond_wait(&wq.wq_alldone_cv, &wq.wq_queue_lock); - pthread_mutex_unlock(&wq.wq_queue_lock); - - join_threads(&wq); - - /* - * All requested files have been merged, with the resulting tree in - * mstrtd. savetd is the tree that will be placed into the output file. - * - * Regardless of whether we're doing a normal uniquification or an - * additive merge, we need a type tree that has been uniquified - * against uniqfile or withfile, as appropriate. - * - * If we're doing a uniquification, we stuff the resulting tree into - * outfile. Otherwise, we add the tree to the tree already in withfile. - */ - assert(fifo_len(wq.wq_queue) == 1); - mstrtd = fifo_remove(wq.wq_queue); - - if (verbose || debug_level) { - debug(2, "Statistics for td %p\n", (void *)mstrtd); - - iidesc_stats(mstrtd->td_iihash); - } - - if (uniqfile != NULL || withfile != NULL) { - char *reffile, *reflabel = NULL; - tdata_t *reftd; - - if (uniqfile != NULL) { - reffile = uniqfile; - reflabel = uniqlabel; - } else - reffile = withfile; - - if (read_ctf(&reffile, 1, reflabel, read_ctf_save_cb, - &reftd, require_ctf) == 0) { - terminate("No CTF data found in reference file %s\n", - reffile); - } - - savetd = tdata_new(); - - if (CTF_TYPE_ISCHILD(reftd->td_nextid)) - terminate("No room for additional types in master\n"); - - savetd->td_nextid = withfile ? reftd->td_nextid : - CTF_INDEX_TO_TYPE(1, TRUE); - merge_into_master(mstrtd, reftd, savetd, 0); - - tdata_label_add(savetd, label, CTF_LABEL_LASTIDX); - - if (withfile) { - /* - * savetd holds the new data to be added to the withfile - */ - tdata_t *withtd = reftd; - - tdata_merge(withtd, savetd); - - savetd = withtd; - } else { - char uniqname[MAXPATHLEN]; - labelent_t *parle; - - parle = tdata_label_top(reftd); - - savetd->td_parlabel = xstrdup(parle->le_name); - - strncpy(uniqname, reffile, sizeof (uniqname)); - uniqname[MAXPATHLEN - 1] = '\0'; - savetd->td_parname = xstrdup(basename(uniqname)); - } - - } else { - /* - * No post processing. Write the merged tree as-is into the - * output file. - */ - tdata_label_free(mstrtd); - tdata_label_add(mstrtd, label, CTF_LABEL_LASTIDX); - - savetd = mstrtd; - } - - tmpname = mktmpname(outfile, ".ctf"); - write_ctf(savetd, outfile, tmpname, - CTF_COMPRESS | write_fuzzy_match | dynsym); - if (rename(tmpname, outfile) != 0) - terminate("Couldn't rename output temp file %s", tmpname); - free(tmpname); - - return (0); -} diff --git a/usr/src/tools/ctf/cvt/ctfmerge.h b/usr/src/tools/ctf/cvt/ctfmerge.h deleted file mode 100644 index ce40803d52..0000000000 --- a/usr/src/tools/ctf/cvt/ctfmerge.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _CTFMERGE_H -#define _CTFMERGE_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Merging structures used in ctfmerge. See ctfmerge.c for locking semantics. - */ - -#include <pthread.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#include "ctftools.h" -#include "barrier.h" -#include "fifo.h" - -typedef struct wip { - pthread_mutex_t wip_lock; - pthread_cond_t wip_cv; - tdata_t *wip_td; - int wip_nmerged; - int wip_batchid; -} wip_t; - -typedef struct workqueue { - int wq_next_batchid; - - int wq_maxbatchsz; - - wip_t *wq_wip; - int wq_nwipslots; - int wq_nthreads; - int wq_ithrottle; - - pthread_mutex_t wq_queue_lock; - fifo_t *wq_queue; - pthread_cond_t wq_work_avail; - pthread_cond_t wq_work_removed; - int wq_ninqueue; - int wq_nextpownum; - - pthread_mutex_t wq_donequeue_lock; - fifo_t *wq_donequeue; - int wq_lastdonebatch; - pthread_cond_t wq_done_cv; - - pthread_cond_t wq_alldone_cv; /* protected by queue_lock */ - int wq_alldone; - - int wq_nomorefiles; - - pthread_t *wq_thread; - - barrier_t wq_bar1; - barrier_t wq_bar2; -} workqueue_t; - -#ifdef __cplusplus -} -#endif - -#endif /* _CTFMERGE_H */ diff --git a/usr/src/tools/ctf/cvt/ctftools.h b/usr/src/tools/ctf/cvt/ctftools.h deleted file mode 100644 index 7547ce389f..0000000000 --- a/usr/src/tools/ctf/cvt/ctftools.h +++ /dev/null @@ -1,452 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _CTFTOOLS_H -#define _CTFTOOLS_H - -/* - * Functions and data structures used in the manipulation of stabs and CTF data - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <libelf.h> -#include <gelf.h> -#include <pthread.h> - -#include <sys/ccompile.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#include "list.h" -#include "hash.h" - -#ifndef DEBUG_LEVEL -#define DEBUG_LEVEL 0 -#endif -#ifndef DEBUG_PARSE -#define DEBUG_PARSE 0 -#endif - -#ifndef DEBUG_STREAM -#define DEBUG_STREAM stderr -#endif - -#ifndef MAX -#define MAX(a, b) ((a) < (b) ? (b) : (a)) -#endif - -#ifndef MIN -#define MIN(a, b) ((a) > (b) ? (b) : (a)) -#endif - -#define TRUE 1 -#define FALSE 0 - -#define CTF_ELF_SCN_NAME ".SUNW_ctf" - -#define CTF_LABEL_LASTIDX -1 - -#define CTF_DEFAULT_LABEL "*** No Label Provided ***" - -/* - * Default hash sizes - */ -#define TDATA_LAYOUT_HASH_SIZE 8191 /* A tdesc hash based on layout */ -#define TDATA_ID_HASH_SIZE 997 /* A tdesc hash based on type id */ -#define IIDESC_HASH_SIZE 8191 /* Hash of iidesc's */ - -/* - * The default function argument array size. We'll realloc the array larger - * if we need to, but we want a default value that will allow us to avoid - * reallocation in the common case. - */ -#define FUNCARG_DEF 5 - -extern const char *progname; -extern int debug_level; -extern int debug_parse; -extern const char *curhdr; - -/* - * This is a partial copy of the stab.h that DevPro includes with their - * compiler. - */ -typedef struct stab { - uint32_t n_strx; - uint8_t n_type; - int8_t n_other; - int16_t n_desc; - uint32_t n_value; -} stab_t; - -#define N_GSYM 0x20 /* global symbol: name,,0,type,0 */ -#define N_FUN 0x24 /* procedure: name,,0,linenumber,0 */ -#define N_STSYM 0x26 /* static symbol: name,,0,type,0 or section relative */ -#define N_LCSYM 0x28 /* .lcomm symbol: name,,0,type,0 or section relative */ -#define N_ROSYM 0x2c /* ro_data: name,,0,type,0 or section relative */ -#define N_OPT 0x3c /* compiler options */ -#define N_RSYM 0x40 /* register sym: name,,0,type,register */ -#define N_SO 0x64 /* source file name: name,,0,0,0 */ -#define N_LSYM 0x80 /* local sym: name,,0,type,offset */ -#define N_SOL 0x84 /* #included file name: name,,0,0,0 */ -#define N_PSYM 0xa0 /* parameter: name,,0,type,offset */ -#define N_LBRAC 0xc0 /* left bracket: 0,,0,nesting level,function relative */ -#define N_RBRAC 0xe0 /* right bracket: 0,,0,nesting level,func relative */ -#define N_BINCL 0x82 /* header file: name,,0,0,0 */ -#define N_EINCL 0xa2 /* end of include file */ - -/* - * Nodes in the type tree - * - * Each node consists of a single tdesc_t, with one of several auxiliary - * structures linked in via the `data' union. - */ - -/* The type of tdesc_t node */ -typedef enum stabtype { - STABTYPE_FIRST, /* do not use */ - INTRINSIC, - POINTER, - ARRAY, - FUNCTION, - STRUCT, - UNION, - ENUM, - FORWARD, - TYPEDEF, - TYPEDEF_UNRES, - VOLATILE, - CONST, - RESTRICT, - STABTYPE_LAST /* do not use */ -} stabtype_t; - -typedef struct tdesc tdesc_t; - -/* Auxiliary structure for array tdesc_t */ -typedef struct ardef { - tdesc_t *ad_contents; - tdesc_t *ad_idxtype; - uint_t ad_nelems; -} ardef_t; - -/* Auxiliary structure for structure/union tdesc_t */ -typedef struct mlist { - int ml_offset; /* Offset from start of structure (in bits) */ - int ml_size; /* Member size (in bits) */ - char *ml_name; /* Member name */ - struct tdesc *ml_type; /* Member type */ - struct mlist *ml_next; /* Next member */ -} mlist_t; - -/* Auxiliary structure for enum tdesc_t */ -typedef struct elist { - char *el_name; - int el_number; - struct elist *el_next; -} elist_t; - -/* Auxiliary structure for intrinsics (integers and reals) */ -typedef enum { - INTR_INT, - INTR_REAL -} intrtype_t; - -typedef struct intr { - intrtype_t intr_type; - int intr_signed; - union { - char _iformat; - int _fformat; - } _u; - int intr_offset; - int intr_nbits; -} intr_t; - -#define intr_iformat _u._iformat -#define intr_fformat _u._fformat - -typedef struct fnarg { - char *fna_name; - struct tdesc *fna_type; -} fnarg_t; - -#define FN_F_GLOBAL 0x1 -#define FN_F_VARARGS 0x2 - -typedef struct fndef { - struct tdesc *fn_ret; - uint_t fn_nargs; - tdesc_t **fn_args; - uint_t fn_vargs; -} fndef_t; - -typedef int32_t tid_t; - -/* - * The tdesc_t (Type DESCription) is the basic node type used in the stabs data - * structure. Each data node gets a tdesc structure. Each node is linked into - * a directed graph (think of it as a tree with multiple roots and multiple - * leaves), with the root nodes at the top, and intrinsics at the bottom. The - * root nodes, which are pointed to by iidesc nodes, correspond to the types, - * globals, and statics defined by the stabs. - */ -struct tdesc { - char *t_name; - tdesc_t *t_next; /* Name hash next pointer */ - - tid_t t_id; - tdesc_t *t_hash; /* ID hash next pointer */ - - stabtype_t t_type; - int t_size; /* Size in bytes of object represented by this node */ - - union { - intr_t *intr; /* int, real */ - tdesc_t *tdesc; /* ptr, typedef, vol, const, restr */ - ardef_t *ardef; /* array */ - mlist_t *members; /* struct, union */ - elist_t *emem; /* enum */ - fndef_t *fndef; /* function - first is return type */ - } t_data; - - int t_flags; - int t_vgen; /* Visitation generation (see traverse.c) */ - int t_emark; /* Equality mark (see equiv_cb() in merge.c) */ -}; - -#define t_intr t_data.intr -#define t_tdesc t_data.tdesc -#define t_ardef t_data.ardef -#define t_members t_data.members -#define t_emem t_data.emem -#define t_fndef t_data.fndef - -#define TDESC_F_ISROOT 0x1 /* Has an iidesc_t (see below) */ -#define TDESC_F_GLOBAL 0x2 -#define TDESC_F_RESOLVED 0x4 - -/* - * iidesc_t (Interesting Item DESCription) nodes point to tdesc_t nodes that - * correspond to "interesting" stabs. A stab is interesting if it defines a - * global or static variable, a global or static function, or a data type. - */ -typedef enum iitype { - II_NOT = 0, - II_GFUN, /* Global function */ - II_SFUN, /* Static function */ - II_GVAR, /* Global variable */ - II_SVAR, /* Static variable */ - II_PSYM, /* Function argument */ - II_SOU, /* Struct or union */ - II_TYPE /* Type (typedef) */ -} iitype_t; - -typedef struct iidesc { - iitype_t ii_type; - char *ii_name; - tdesc_t *ii_dtype; - char *ii_owner; /* File that defined this node */ - int ii_flags; - - /* Function arguments (if any) */ - int ii_nargs; - tdesc_t **ii_args; - int ii_vargs; /* Function uses varargs */ -} iidesc_t; - -#define IIDESC_F_USED 0x1 /* Write this iidesc out */ - -/* - * labelent_t nodes identify labels and corresponding type ranges associated - * with them. The label in a given labelent_t is associated with types with - * ids <= le_idx. - */ -typedef struct labelent { - char *le_name; - int le_idx; -} labelent_t; - -/* - * The tdata_t (Type DATA) structure contains or references all type data for - * a given file or, during merging, several files. - */ -typedef struct tdata { - int td_curemark; /* Equality mark (see merge.c) */ - int td_curvgen; /* Visitation generation (see traverse.c) */ - int td_nextid; /* The ID for the next tdesc_t created */ - hash_t *td_iihash; /* The iidesc_t nodes for this file */ - - hash_t *td_layouthash; /* The tdesc nodes, hashed by structure */ - hash_t *td_idhash; /* The tdesc nodes, hashed by type id */ - list_t *td_fwdlist; /* All forward declaration tdesc nodes */ - - char *td_parlabel; /* Top label uniq'd against in parent */ - char *td_parname; /* Basename of parent */ - list_t *td_labels; /* Labels and their type ranges */ - - pthread_mutex_t td_mergelock; - - int td_ref; -} tdata_t; - -/* - * By design, the iidesc hash is heterogeneous. The CTF emitter, on the - * other hand, needs to be able to access the elements of the list by type, - * and in a specific sorted order. An iiburst holds these elements in that - * order. (A burster is a machine that separates carbon-copy forms) - */ -typedef struct iiburst { - int iib_nfuncs; - int iib_curfunc; - iidesc_t **iib_funcs; - - int iib_nobjts; - int iib_curobjt; - iidesc_t **iib_objts; - - list_t *iib_types; - int iib_maxtypeid; - - tdata_t *iib_td; - struct tdtrav_data *iib_tdtd; /* tdtrav_data_t */ -} iiburst_t; - -typedef struct ctf_buf ctf_buf_t; - -typedef struct symit_data symit_data_t; - -/* fixup_tdescs.c */ -void cvt_fixstabs(tdata_t *); -void cvt_fixups(tdata_t *, size_t); - -/* ctf.c */ -caddr_t ctf_gen(iiburst_t *, size_t *, int); -tdata_t *ctf_load(char *, caddr_t, size_t, symit_data_t *, char *); - -/* iidesc.c */ -iidesc_t *iidesc_new(char *); -int iidesc_hash(int, void *); -void iter_iidescs_by_name(tdata_t *, const char *, - int (*)(iidesc_t *, void *), void *); -iidesc_t *iidesc_dup(iidesc_t *); -iidesc_t *iidesc_dup_rename(iidesc_t *, char const *, char const *); -void iidesc_add(hash_t *, iidesc_t *); -void iidesc_free(iidesc_t *); -void iidesc_free_cb(void *, void *); -int iidesc_count_type(void *, void *); -void iidesc_stats(hash_t *); -int iidesc_dump(iidesc_t *); - -/* input.c */ -typedef enum source_types { - SOURCE_NONE = 0, - SOURCE_UNKNOWN = 1, - SOURCE_C = 2, - SOURCE_S = 4 -} source_types_t; - -source_types_t built_source_types(Elf *, const char *); -int count_files(char **, int); -int read_ctf(char **, int, char *, int (*)(tdata_t *, char *, void *), - void *, int); -int read_ctf_save_cb(tdata_t *, char *, void *); -symit_data_t *symit_new(Elf *, const char *); -void symit_reset(symit_data_t *); -char *symit_curfile(symit_data_t *); -GElf_Sym *symit_next(symit_data_t *, int); -char *symit_name(symit_data_t *); -void symit_free(symit_data_t *); - -/* merge.c */ -void merge_into_master(tdata_t *, tdata_t *, tdata_t *, int); - -/* output.c */ -#define CTF_FUZZY_MATCH 0x1 /* match local symbols to global CTF */ -#define CTF_USE_DYNSYM 0x2 /* use .dynsym not .symtab */ -#define CTF_COMPRESS 0x4 /* compress CTF output */ - -void write_ctf(tdata_t *, const char *, const char *, int); - -/* parse.c */ -void parse_init(tdata_t *); -void parse_finish(tdata_t *); -int parse_stab(stab_t *, char *, iidesc_t **); -tdesc_t *lookup(int); -tdesc_t *lookupname(const char *); -void check_hash(void); -void resolve_typed_bitfields(void); - -/* stabs.c */ -int stabs_read(tdata_t *, Elf *, const char *); - -/* dwarf.c */ -int dw_read(tdata_t *, Elf *, const char *); -const char *dw_tag2str(uint_t); - -/* tdata.c */ -tdata_t *tdata_new(void); -void tdata_free(tdata_t *); -void tdata_build_hashes(tdata_t *td); -const char *tdesc_name(tdesc_t *); -int tdesc_idhash(int, void *); -int tdesc_idcmp(void *, void *); -int tdesc_namehash(int, void *); -int tdesc_namecmp(void *, void *); -int tdesc_layouthash(int, void *); -int tdesc_layoutcmp(void *, void *); -void tdesc_free(tdesc_t *); -void tdata_label_add(tdata_t *, char *, int); -labelent_t *tdata_label_top(tdata_t *); -int tdata_label_find(tdata_t *, char *); -void tdata_label_free(tdata_t *); -void tdata_merge(tdata_t *, tdata_t *); -void tdata_label_newmax(tdata_t *, int); - -/* util.c */ -int streq(const char *, const char *); -int findelfsecidx(Elf *, const char *, const char *); -size_t elf_ptrsz(Elf *); -char *mktmpname(const char *, const char *); -void terminate(char *, ...) __NORETURN; -void aborterr(char *, ...) __NORETURN; -void set_terminate_cleanup(void (*)()); -void elfterminate(const char *, const char *, ...); -void warning(char *, ...); -void vadebug(int, char *, va_list); -void debug(int, char *, ...); - -/* altexec.c */ -void ctf_altexec(const char *, int argc, char **); - -#ifdef __cplusplus -} -#endif - -#endif /* _CTFTOOLS_H */ diff --git a/usr/src/tools/ctf/cvt/dwarf.c b/usr/src/tools/ctf/cvt/dwarf.c deleted file mode 100644 index afca423005..0000000000 --- a/usr/src/tools/ctf/cvt/dwarf.c +++ /dev/null @@ -1,2027 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ -/* - * Copyright 2012 Jason King. All rights reserved. - * Use is subject to license terms. - */ - -/* - * DWARF to tdata conversion - * - * For the most part, conversion is straightforward, proceeding in two passes. - * On the first pass, we iterate through every die, creating new type nodes as - * necessary. Referenced tdesc_t's are created in an uninitialized state, thus - * allowing type reference pointers to be filled in. If the tdesc_t - * corresponding to a given die can be completely filled out (sizes and offsets - * calculated, and so forth) without using any referenced types, the tdesc_t is - * marked as resolved. Consider an array type. If the type corresponding to - * the array contents has not yet been processed, we will create a blank tdesc - * for the contents type (only the type ID will be filled in, relying upon the - * later portion of the first pass to encounter and complete the referenced - * type). We will then attempt to determine the size of the array. If the - * array has a byte size attribute, we will have completely characterized the - * array type, and will be able to mark it as resolved. The lack of a byte - * size attribute, on the other hand, will prevent us from fully resolving the - * type, as the size will only be calculable with reference to the contents - * type, which has not, as yet, been encountered. The array type will thus be - * left without the resolved flag, and the first pass will continue. - * - * When we begin the second pass, we will have created tdesc_t nodes for every - * type in the section. We will traverse the tree, from the iidescs down, - * processing each unresolved node. As the referenced nodes will have been - * populated, the array type used in our example above will be able to use the - * size of the referenced types (if available) to determine its own type. The - * traversal will be repeated until all types have been resolved or we have - * failed to make progress. When all tdescs have been resolved, the conversion - * is complete. - * - * There are, as always, a few special cases that are handled during the first - * and second passes: - * - * 1. Empty enums - GCC will occasionally emit an enum without any members. - * Later on in the file, it will emit the same enum type, though this time - * with the full complement of members. All references to the memberless - * enum need to be redirected to the full definition. During the first - * pass, each enum is entered in dm_enumhash, along with a pointer to its - * corresponding tdesc_t. If, during the second pass, we encounter a - * memberless enum, we use the hash to locate the full definition. All - * tdescs referencing the empty enum are then redirected. - * - * 2. Forward declarations - If the compiler sees a forward declaration for - * a structure, followed by the definition of that structure, it will emit - * DWARF data for both the forward declaration and the definition. We need - * to resolve the forward declarations when possible, by redirecting - * forward-referencing tdescs to the actual struct/union definitions. This - * redirection is done completely within the first pass. We begin by - * recording all forward declarations in dw_fwdhash. When we define a - * structure, we check to see if there have been any corresponding forward - * declarations. If so, we redirect the tdescs which referenced the forward - * declarations to the structure or union definition. - * - * XXX see if a post traverser will allow the elimination of repeated pass 2 - * traversals. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <strings.h> -#include <errno.h> -#include <libelf.h> -#include <libdwarf.h> -#include <libgen.h> -#include <dwarf.h> - -#include "ctf_headers.h" -#include "ctftools.h" -#include "memory.h" -#include "list.h" -#include "traverse.h" - -/* The version of DWARF which we support. */ -#define DWARF_VERSION 2 - -/* - * We need to define a couple of our own intrinsics, to smooth out some of the - * differences between the GCC and DevPro DWARF emitters. See the referenced - * routines and the special cases in the file comment for more details. - * - * Type IDs are 32 bits wide. We're going to use the top of that field to - * indicate types that we've created ourselves. - */ -#define TID_FILEMAX 0x3fffffff /* highest tid from file */ -#define TID_VOID 0x40000001 /* see die_void() */ -#define TID_LONG 0x40000002 /* see die_array() */ - -#define TID_MFGTID_BASE 0x40000003 /* first mfg'd tid */ - -/* - * To reduce the staggering amount of error-handling code that would otherwise - * be required, the attribute-retrieval routines handle most of their own - * errors. If the following flag is supplied as the value of the `req' - * argument, they will also handle the absence of a requested attribute by - * terminating the program. - */ -#define DW_ATTR_REQ 1 - -#define TDESC_HASH_BUCKETS 511 - -typedef struct dwarf { - Dwarf_Debug dw_dw; /* for libdwarf */ - Dwarf_Error dw_err; /* for libdwarf */ - Dwarf_Unsigned dw_maxoff; /* highest legal offset in this cu */ - tdata_t *dw_td; /* root of the tdesc/iidesc tree */ - hash_t *dw_tidhash; /* hash of tdescs by t_id */ - hash_t *dw_fwdhash; /* hash of fwd decls by name */ - hash_t *dw_enumhash; /* hash of memberless enums by name */ - tdesc_t *dw_void; /* manufactured void type */ - tdesc_t *dw_long; /* manufactured long type for arrays */ - size_t dw_ptrsz; /* size of a pointer in this file */ - tid_t dw_mfgtid_last; /* last mfg'd type ID used */ - uint_t dw_nunres; /* count of unresolved types */ - char *dw_cuname; /* name of compilation unit */ -} dwarf_t; - -static void die_create_one(dwarf_t *, Dwarf_Die); -static void die_create(dwarf_t *, Dwarf_Die); - -static tid_t -mfgtid_next(dwarf_t *dw) -{ - return (++dw->dw_mfgtid_last); -} - -static void -tdesc_add(dwarf_t *dw, tdesc_t *tdp) -{ - hash_add(dw->dw_tidhash, tdp); -} - -static tdesc_t * -tdesc_lookup(dwarf_t *dw, int tid) -{ - tdesc_t tmpl, *tdp; - - tmpl.t_id = tid; - - if (hash_find(dw->dw_tidhash, &tmpl, (void **)&tdp)) - return (tdp); - else - return (NULL); -} - -/* - * Resolve a tdesc down to a node which should have a size. Returns the size, - * zero if the size hasn't yet been determined. - */ -static size_t -tdesc_size(tdesc_t *tdp) -{ - for (;;) { - switch (tdp->t_type) { - case INTRINSIC: - case POINTER: - case ARRAY: - case FUNCTION: - case STRUCT: - case UNION: - case ENUM: - return (tdp->t_size); - - case FORWARD: - return (0); - - case TYPEDEF: - case VOLATILE: - case CONST: - case RESTRICT: - tdp = tdp->t_tdesc; - continue; - - case 0: /* not yet defined */ - return (0); - - default: - terminate("tdp %u: tdesc_size on unknown type %d\n", - tdp->t_id, tdp->t_type); - } - } -} - -static size_t -tdesc_bitsize(tdesc_t *tdp) -{ - for (;;) { - switch (tdp->t_type) { - case INTRINSIC: - return (tdp->t_intr->intr_nbits); - - case ARRAY: - case FUNCTION: - case STRUCT: - case UNION: - case ENUM: - case POINTER: - return (tdp->t_size * NBBY); - - case FORWARD: - return (0); - - case TYPEDEF: - case VOLATILE: - case RESTRICT: - case CONST: - tdp = tdp->t_tdesc; - continue; - - case 0: /* not yet defined */ - return (0); - - default: - terminate("tdp %u: tdesc_bitsize on unknown type %d\n", - tdp->t_id, tdp->t_type); - } - } -} - -static tdesc_t * -tdesc_basetype(tdesc_t *tdp) -{ - for (;;) { - switch (tdp->t_type) { - case TYPEDEF: - case VOLATILE: - case RESTRICT: - case CONST: - tdp = tdp->t_tdesc; - break; - case 0: /* not yet defined */ - return (NULL); - default: - return (tdp); - } - } -} - -static Dwarf_Off -die_off(dwarf_t *dw, Dwarf_Die die) -{ - Dwarf_Off off; - - if (dwarf_dieoffset(die, &off, &dw->dw_err) == DW_DLV_OK) - return (off); - - terminate("failed to get offset for die: %s\n", - dwarf_errmsg(dw->dw_err)); - /*NOTREACHED*/ - return (0); -} - -static Dwarf_Die -die_sibling(dwarf_t *dw, Dwarf_Die die) -{ - Dwarf_Die sib; - int rc; - - if ((rc = dwarf_siblingof(dw->dw_dw, die, &sib, &dw->dw_err)) == - DW_DLV_OK) - return (sib); - else if (rc == DW_DLV_NO_ENTRY) - return (NULL); - - terminate("die %llu: failed to find type sibling: %s\n", - die_off(dw, die), dwarf_errmsg(dw->dw_err)); - /*NOTREACHED*/ - return (NULL); -} - -static Dwarf_Die -die_child(dwarf_t *dw, Dwarf_Die die) -{ - Dwarf_Die child; - int rc; - - if ((rc = dwarf_child(die, &child, &dw->dw_err)) == DW_DLV_OK) - return (child); - else if (rc == DW_DLV_NO_ENTRY) - return (NULL); - - terminate("die %llu: failed to find type child: %s\n", - die_off(dw, die), dwarf_errmsg(dw->dw_err)); - /*NOTREACHED*/ - return (NULL); -} - -static Dwarf_Half -die_tag(dwarf_t *dw, Dwarf_Die die) -{ - Dwarf_Half tag; - - if (dwarf_tag(die, &tag, &dw->dw_err) == DW_DLV_OK) - return (tag); - - terminate("die %llu: failed to get tag for type: %s\n", - die_off(dw, die), dwarf_errmsg(dw->dw_err)); - /*NOTREACHED*/ - return (0); -} - -static Dwarf_Attribute -die_attr(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, int req) -{ - Dwarf_Attribute attr; - int rc; - - if ((rc = dwarf_attr(die, name, &attr, &dw->dw_err)) == DW_DLV_OK) { - return (attr); - } else if (rc == DW_DLV_NO_ENTRY) { - if (req) { - terminate("die %llu: no attr 0x%x\n", die_off(dw, die), - name); - } else { - return (NULL); - } - } - - terminate("die %llu: failed to get attribute for type: %s\n", - die_off(dw, die), dwarf_errmsg(dw->dw_err)); - /*NOTREACHED*/ - return (NULL); -} - -static Dwarf_Half -die_attr_form(dwarf_t *dw, Dwarf_Attribute attr) -{ - Dwarf_Half form; - - if (dwarf_whatform(attr, &form, &dw->dw_err) == DW_DLV_OK) - return (form); - - terminate("failed to get attribute form for type: %s\n", - dwarf_errmsg(dw->dw_err)); - /*NOTREACHED*/ - return (0); -} - -/* - * the following functions lookup the value of an attribute in a DIE: - * - * die_signed - * die_unsigned - * die_bool - * die_string - * - * They all take the same parameters (with the exception of valp which is - * a pointer to the type of the attribute we are looking up): - * - * dw - the dwarf object to look in - * die - the DIE we're interested in - * name - the name of the attribute to lookup - * valp - pointer to where the value of the attribute is placed - * req - if the value is required (0 / non-zero) - * - * If the attribute is not found, one of the following happens: - * - program terminates (req is non-zero) - * - function returns 0 - * - * If the value is found, and in a form (class) we can handle, the function - * returns 1. - * - * Currently, we can only handle attribute values that are stored as - * constants (immediate value). If an attribute has a form we cannot - * handle (for example VLAs may store the dimensions of the array - * as a DWARF expression that can compute it at runtime by reading - * values off the stack or other locations in memory), it is treated - * the same as if the attribute does not exist. - */ -static int -die_signed(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, Dwarf_Signed *valp, - int req) -{ - Dwarf_Attribute attr; - Dwarf_Signed val; - - if ((attr = die_attr(dw, die, name, req)) == NULL) - return (0); /* die_attr will terminate for us if necessary */ - - if (dwarf_formsdata(attr, &val, &dw->dw_err) != DW_DLV_OK) { - if (req == 0) - return (0); - - terminate("die %llu: failed to get signed (form 0x%x)\n", - die_off(dw, die), die_attr_form(dw, attr)); - } - - dwarf_dealloc(dw->dw_dw, attr, DW_DLA_ATTR); - - *valp = val; - return (1); -} - -static int -die_unsigned(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, Dwarf_Unsigned *valp, - int req) -{ - Dwarf_Attribute attr; - Dwarf_Unsigned val; - - if ((attr = die_attr(dw, die, name, req)) == NULL) - return (0); /* die_attr will terminate for us if necessary */ - - if (dwarf_formudata(attr, &val, &dw->dw_err) != DW_DLV_OK) { - if (req == 0) - return (0); - - terminate("die %llu: failed to get unsigned (form 0x%x)\n", - die_off(dw, die), die_attr_form(dw, attr)); - } - - dwarf_dealloc(dw->dw_dw, attr, DW_DLA_ATTR); - - *valp = val; - return (1); -} - -static int -die_bool(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, Dwarf_Bool *valp, int req) -{ - Dwarf_Attribute attr; - Dwarf_Bool val; - - if ((attr = die_attr(dw, die, name, req)) == NULL) - return (0); /* die_attr will terminate for us if necessary */ - - if (dwarf_formflag(attr, &val, &dw->dw_err) != DW_DLV_OK) { - if (req == 0) - return (0); - - terminate("die %llu: failed to get bool (form 0x%x)\n", - die_off(dw, die), die_attr_form(dw, attr)); - } - - dwarf_dealloc(dw->dw_dw, attr, DW_DLA_ATTR); - - *valp = val; - return (1); -} - -static int -die_string(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, char **strp, int req) -{ - Dwarf_Attribute attr; - char *str; - - if ((attr = die_attr(dw, die, name, req)) == NULL) - return (0); /* die_attr will terminate for us if necessary */ - - if (dwarf_formstring(attr, &str, &dw->dw_err) != DW_DLV_OK) { - if (req == 0) - return (0); - - terminate("die %llu: failed to get string (form 0x%x)\n", - die_off(dw, die), die_attr_form(dw, attr)); - } - - *strp = xstrdup(str); - dwarf_dealloc(dw->dw_dw, str, DW_DLA_STRING); - - return (1); -} - -static Dwarf_Off -die_attr_ref(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name) -{ - Dwarf_Attribute attr; - Dwarf_Off off; - - attr = die_attr(dw, die, name, DW_ATTR_REQ); - - if (dwarf_formref(attr, &off, &dw->dw_err) != DW_DLV_OK) { - terminate("die %llu: failed to get ref (form 0x%x)\n", - die_off(dw, die), die_attr_form(dw, attr)); - } - - dwarf_dealloc(dw->dw_dw, attr, DW_DLA_ATTR); - - return (off); -} - -static char * -die_name(dwarf_t *dw, Dwarf_Die die) -{ - char *str = NULL; - - (void) die_string(dw, die, DW_AT_name, &str, 0); - - return (str); -} - -static int -die_isdecl(dwarf_t *dw, Dwarf_Die die) -{ - Dwarf_Bool val; - - return (die_bool(dw, die, DW_AT_declaration, &val, 0) && val); -} - -static int -die_isglobal(dwarf_t *dw, Dwarf_Die die) -{ - Dwarf_Signed vis; - Dwarf_Bool ext; - - /* - * Some compilers (gcc) use DW_AT_external to indicate function - * visibility. Others (Sun) use DW_AT_visibility. - */ - if (die_signed(dw, die, DW_AT_visibility, &vis, 0)) - return (vis == DW_VIS_exported); - else - return (die_bool(dw, die, DW_AT_external, &ext, 0) && ext); -} - -static tdesc_t * -die_add(dwarf_t *dw, Dwarf_Off off) -{ - tdesc_t *tdp = xcalloc(sizeof (tdesc_t)); - - tdp->t_id = off; - - tdesc_add(dw, tdp); - - return (tdp); -} - -static tdesc_t * -die_lookup_pass1(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name) -{ - Dwarf_Off ref = die_attr_ref(dw, die, name); - tdesc_t *tdp; - - if ((tdp = tdesc_lookup(dw, ref)) != NULL) - return (tdp); - - return (die_add(dw, ref)); -} - -static int -die_mem_offset(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, - Dwarf_Unsigned *valp, int req) -{ - Dwarf_Attribute attr; - Dwarf_Locdesc *loc; - Dwarf_Signed locnum; - - if ((attr = die_attr(dw, die, name, req)) == NULL) - return (0); /* die_attr will terminate for us if necessary */ - - if (dwarf_loclist(attr, &loc, &locnum, &dw->dw_err) != DW_DLV_OK) { - terminate("die %llu: failed to get mem offset location list\n", - die_off(dw, die)); - } - - dwarf_dealloc(dw->dw_dw, attr, DW_DLA_ATTR); - - if (locnum != 1 || loc->ld_s->lr_atom != DW_OP_plus_uconst) { - terminate("die %llu: cannot parse member offset\n", - die_off(dw, die)); - } - - *valp = loc->ld_s->lr_number; - - dwarf_dealloc(dw->dw_dw, loc->ld_s, DW_DLA_LOC_BLOCK); - dwarf_dealloc(dw->dw_dw, loc, DW_DLA_LOCDESC); - - return (1); -} - -static tdesc_t * -tdesc_intr_common(dwarf_t *dw, int tid, const char *name, size_t sz) -{ - tdesc_t *tdp; - intr_t *intr; - - intr = xcalloc(sizeof (intr_t)); - intr->intr_type = INTR_INT; - intr->intr_signed = 1; - intr->intr_nbits = sz * NBBY; - - tdp = xcalloc(sizeof (tdesc_t)); - tdp->t_name = xstrdup(name); - tdp->t_size = sz; - tdp->t_id = tid; - tdp->t_type = INTRINSIC; - tdp->t_intr = intr; - tdp->t_flags = TDESC_F_RESOLVED; - - tdesc_add(dw, tdp); - - return (tdp); -} - -/* - * Manufacture a void type. Used for gcc-emitted stabs, where the lack of a - * type reference implies a reference to a void type. A void *, for example - * will be represented by a pointer die without a DW_AT_type. CTF requires - * that pointer nodes point to something, so we'll create a void for use as - * the target. Note that the DWARF data may already create a void type. Ours - * would then be a duplicate, but it'll be removed in the self-uniquification - * merge performed at the completion of DWARF->tdesc conversion. - */ -static tdesc_t * -tdesc_intr_void(dwarf_t *dw) -{ - if (dw->dw_void == NULL) - dw->dw_void = tdesc_intr_common(dw, TID_VOID, "void", 0); - - return (dw->dw_void); -} - -static tdesc_t * -tdesc_intr_long(dwarf_t *dw) -{ - if (dw->dw_long == NULL) { - dw->dw_long = tdesc_intr_common(dw, TID_LONG, "long", - dw->dw_ptrsz); - } - - return (dw->dw_long); -} - -/* - * Used for creating bitfield types. We create a copy of an existing intrinsic, - * adjusting the size of the copy to match what the caller requested. The - * caller can then use the copy as the type for a bitfield structure member. - */ -static tdesc_t * -tdesc_intr_clone(dwarf_t *dw, tdesc_t *old, size_t bitsz) -{ - tdesc_t *new = xcalloc(sizeof (tdesc_t)); - - if (!(old->t_flags & TDESC_F_RESOLVED)) { - terminate("tdp %u: attempt to make a bit field from an " - "unresolved type\n", old->t_id); - } - - new->t_name = xstrdup(old->t_name); - new->t_size = old->t_size; - new->t_id = mfgtid_next(dw); - new->t_type = INTRINSIC; - new->t_flags = TDESC_F_RESOLVED; - - new->t_intr = xcalloc(sizeof (intr_t)); - bcopy(old->t_intr, new->t_intr, sizeof (intr_t)); - new->t_intr->intr_nbits = bitsz; - - tdesc_add(dw, new); - - return (new); -} - -static void -tdesc_array_create(dwarf_t *dw, Dwarf_Die dim, tdesc_t *arrtdp, - tdesc_t *dimtdp) -{ - Dwarf_Unsigned uval; - Dwarf_Signed sval; - tdesc_t *ctdp; - Dwarf_Die dim2; - ardef_t *ar; - - if ((dim2 = die_sibling(dw, dim)) == NULL) { - ctdp = arrtdp; - } else if (die_tag(dw, dim2) == DW_TAG_subrange_type) { - ctdp = xcalloc(sizeof (tdesc_t)); - ctdp->t_id = mfgtid_next(dw); - debug(3, "die %llu: creating new type %u for sub-dimension\n", - die_off(dw, dim2), ctdp->t_id); - tdesc_array_create(dw, dim2, arrtdp, ctdp); - } else { - terminate("die %llu: unexpected non-subrange node in array\n", - die_off(dw, dim2)); - } - - dimtdp->t_type = ARRAY; - dimtdp->t_ardef = ar = xcalloc(sizeof (ardef_t)); - - /* - * Array bounds can be signed or unsigned, but there are several kinds - * of signless forms (data1, data2, etc) that take their sign from the - * routine that is trying to interpret them. That is, data1 can be - * either signed or unsigned, depending on whether you use the signed or - * unsigned accessor function. GCC will use the signless forms to store - * unsigned values which have their high bit set, so we need to try to - * read them first as unsigned to get positive values. We could also - * try signed first, falling back to unsigned if we got a negative - * value. - */ - if (die_unsigned(dw, dim, DW_AT_upper_bound, &uval, 0)) - ar->ad_nelems = uval + 1; - else if (die_signed(dw, dim, DW_AT_upper_bound, &sval, 0)) - ar->ad_nelems = sval + 1; - else - ar->ad_nelems = 0; - - /* - * Different compilers use different index types. Force the type to be - * a common, known value (long). - */ - ar->ad_idxtype = tdesc_intr_long(dw); - ar->ad_contents = ctdp; - - if (ar->ad_contents->t_size != 0) { - dimtdp->t_size = ar->ad_contents->t_size * ar->ad_nelems; - dimtdp->t_flags |= TDESC_F_RESOLVED; - } -} - -/* - * Create a tdesc from an array node. Some arrays will come with byte size - * attributes, and thus can be resolved immediately. Others don't, and will - * need to wait until the second pass for resolution. - */ -static void -die_array_create(dwarf_t *dw, Dwarf_Die arr, Dwarf_Off off, tdesc_t *tdp) -{ - tdesc_t *arrtdp = die_lookup_pass1(dw, arr, DW_AT_type); - Dwarf_Unsigned uval; - Dwarf_Die dim; - - debug(3, "die %llu: creating array\n", off); - - if ((dim = die_child(dw, arr)) == NULL || - die_tag(dw, dim) != DW_TAG_subrange_type) - terminate("die %llu: failed to retrieve array bounds\n", off); - - tdesc_array_create(dw, dim, arrtdp, tdp); - - if (die_unsigned(dw, arr, DW_AT_byte_size, &uval, 0)) { - tdesc_t *dimtdp; - int flags; - - tdp->t_size = uval; - - /* - * Ensure that sub-dimensions have sizes too before marking - * as resolved. - */ - flags = TDESC_F_RESOLVED; - for (dimtdp = tdp->t_ardef->ad_contents; - dimtdp->t_type == ARRAY; - dimtdp = dimtdp->t_ardef->ad_contents) { - if (!(dimtdp->t_flags & TDESC_F_RESOLVED)) { - flags = 0; - break; - } - } - - tdp->t_flags |= flags; - } - - debug(3, "die %llu: array nelems %u size %u\n", off, - tdp->t_ardef->ad_nelems, tdp->t_size); -} - -/*ARGSUSED1*/ -static int -die_array_resolve(tdesc_t *tdp, tdesc_t **tdpp, void *private) -{ - dwarf_t *dw = private; - size_t sz; - - if (tdp->t_flags & TDESC_F_RESOLVED) - return (1); - - debug(3, "trying to resolve array %d (cont %d)\n", tdp->t_id, - tdp->t_ardef->ad_contents->t_id); - - if ((sz = tdesc_size(tdp->t_ardef->ad_contents)) == 0) { - debug(3, "unable to resolve array %s (%d) contents %d\n", - tdesc_name(tdp), tdp->t_id, - tdp->t_ardef->ad_contents->t_id); - - dw->dw_nunres++; - return (1); - } - - tdp->t_size = sz * tdp->t_ardef->ad_nelems; - tdp->t_flags |= TDESC_F_RESOLVED; - - debug(3, "resolved array %d: %u bytes\n", tdp->t_id, tdp->t_size); - - return (1); -} - -/*ARGSUSED1*/ -static int -die_array_failed(tdesc_t *tdp, tdesc_t **tdpp, void *private) -{ - tdesc_t *cont = tdp->t_ardef->ad_contents; - - if (tdp->t_flags & TDESC_F_RESOLVED) - return (1); - - fprintf(stderr, "Array %d: failed to size contents type %s (%d)\n", - tdp->t_id, tdesc_name(cont), cont->t_id); - - return (1); -} - -/* - * Most enums (those with members) will be resolved during this first pass. - * Others - those without members (see the file comment) - won't be, and will - * need to wait until the second pass when they can be matched with their full - * definitions. - */ -static void -die_enum_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp) -{ - Dwarf_Die mem; - Dwarf_Unsigned uval; - Dwarf_Signed sval; - - debug(3, "die %llu: creating enum\n", off); - - tdp->t_type = ENUM; - - (void) die_unsigned(dw, die, DW_AT_byte_size, &uval, DW_ATTR_REQ); - tdp->t_size = uval; - - if ((mem = die_child(dw, die)) != NULL) { - elist_t **elastp = &tdp->t_emem; - - do { - elist_t *el; - - if (die_tag(dw, mem) != DW_TAG_enumerator) { - /* Nested type declaration */ - die_create_one(dw, mem); - continue; - } - - el = xcalloc(sizeof (elist_t)); - el->el_name = die_name(dw, mem); - - /* - * We have to be careful here: newer GCCs generate DWARF - * where an unsigned value will happily pass - * die_signed(). Since negative values will fail - * die_unsigned(), we try that first to make sure we get - * the right value. - */ - if (die_unsigned(dw, mem, DW_AT_const_value, - &uval, 0)) { - el->el_number = uval; - } else if (die_signed(dw, mem, DW_AT_const_value, - &sval, 0)) { - el->el_number = sval; - } else { - terminate("die %llu: enum %llu: member without " - "value\n", off, die_off(dw, mem)); - } - - debug(3, "die %llu: enum %llu: created %s = %d\n", off, - die_off(dw, mem), el->el_name, el->el_number); - - *elastp = el; - elastp = &el->el_next; - - } while ((mem = die_sibling(dw, mem)) != NULL); - - hash_add(dw->dw_enumhash, tdp); - - tdp->t_flags |= TDESC_F_RESOLVED; - - if (tdp->t_name != NULL) { - iidesc_t *ii = xcalloc(sizeof (iidesc_t)); - ii->ii_type = II_SOU; - ii->ii_name = xstrdup(tdp->t_name); - ii->ii_dtype = tdp; - - iidesc_add(dw->dw_td->td_iihash, ii); - } - } -} - -static int -die_enum_match(void *arg1, void *arg2) -{ - tdesc_t *tdp = arg1, **fullp = arg2; - - if (tdp->t_emem != NULL) { - *fullp = tdp; - return (-1); /* stop the iteration */ - } - - return (0); -} - -/*ARGSUSED1*/ -static int -die_enum_resolve(tdesc_t *tdp, tdesc_t **tdpp, void *private) -{ - dwarf_t *dw = private; - tdesc_t *full = NULL; - - if (tdp->t_flags & TDESC_F_RESOLVED) - return (1); - - (void) hash_find_iter(dw->dw_enumhash, tdp, die_enum_match, &full); - - /* - * The answer to this one won't change from iteration to iteration, - * so don't even try. - */ - if (full == NULL) { - terminate("tdp %u: enum %s has no members\n", tdp->t_id, - tdesc_name(tdp)); - } - - debug(3, "tdp %u: enum %s redirected to %u\n", tdp->t_id, - tdesc_name(tdp), full->t_id); - - tdp->t_flags |= TDESC_F_RESOLVED; - - return (1); -} - -static int -die_fwd_map(void *arg1, void *arg2) -{ - tdesc_t *fwd = arg1, *sou = arg2; - - debug(3, "tdp %u: mapped forward %s to sou %u\n", fwd->t_id, - tdesc_name(fwd), sou->t_id); - fwd->t_tdesc = sou; - - return (0); -} - -/* - * Structures and unions will never be resolved during the first pass, as we - * won't be able to fully determine the member sizes. The second pass, which - * have access to sizing information, will be able to complete the resolution. - */ -static void -die_sou_create(dwarf_t *dw, Dwarf_Die str, Dwarf_Off off, tdesc_t *tdp, - int type, const char *typename) -{ - Dwarf_Unsigned sz, bitsz, bitoff; - Dwarf_Die mem; - mlist_t *ml, **mlastp; - iidesc_t *ii; - - tdp->t_type = (die_isdecl(dw, str) ? FORWARD : type); - - debug(3, "die %llu: creating %s %s\n", off, - (tdp->t_type == FORWARD ? "forward decl" : typename), - tdesc_name(tdp)); - - if (tdp->t_type == FORWARD) { - hash_add(dw->dw_fwdhash, tdp); - return; - } - - (void) hash_find_iter(dw->dw_fwdhash, tdp, die_fwd_map, tdp); - - (void) die_unsigned(dw, str, DW_AT_byte_size, &sz, DW_ATTR_REQ); - tdp->t_size = sz; - - /* - * GCC allows empty SOUs as an extension. - */ - if ((mem = die_child(dw, str)) == NULL) - goto out; - - mlastp = &tdp->t_members; - - do { - Dwarf_Off memoff = die_off(dw, mem); - Dwarf_Half tag = die_tag(dw, mem); - Dwarf_Unsigned mloff; - - if (tag != DW_TAG_member) { - /* Nested type declaration */ - die_create_one(dw, mem); - continue; - } - - debug(3, "die %llu: mem %llu: creating member\n", off, memoff); - - ml = xcalloc(sizeof (mlist_t)); - - /* - * This could be a GCC anon struct/union member, so we'll allow - * an empty name, even though nothing can really handle them - * properly. Note that some versions of GCC miss out debug - * info for anon structs, though recent versions are fixed (gcc - * bug 11816). - */ - if ((ml->ml_name = die_name(dw, mem)) == NULL) - ml->ml_name = ""; - - ml->ml_type = die_lookup_pass1(dw, mem, DW_AT_type); - - if (die_mem_offset(dw, mem, DW_AT_data_member_location, - &mloff, 0)) { - debug(3, "die %llu: got mloff %llx\n", off, - (u_longlong_t)mloff); - ml->ml_offset = mloff * 8; - } - - if (die_unsigned(dw, mem, DW_AT_bit_size, &bitsz, 0)) - ml->ml_size = bitsz; - else - ml->ml_size = tdesc_bitsize(ml->ml_type); - - if (die_unsigned(dw, mem, DW_AT_bit_offset, &bitoff, 0)) { -#ifdef _BIG_ENDIAN - ml->ml_offset += bitoff; -#else - ml->ml_offset += tdesc_bitsize(ml->ml_type) - bitoff - - ml->ml_size; -#endif - } - - debug(3, "die %llu: mem %llu: created \"%s\" (off %u sz %u)\n", - off, memoff, ml->ml_name, ml->ml_offset, ml->ml_size); - - *mlastp = ml; - mlastp = &ml->ml_next; - } while ((mem = die_sibling(dw, mem)) != NULL); - - /* - * GCC will attempt to eliminate unused types, thus decreasing the - * size of the emitted dwarf. That is, if you declare a foo_t in your - * header, include said header in your source file, and neglect to - * actually use (directly or indirectly) the foo_t in the source file, - * the foo_t won't make it into the emitted DWARF. So, at least, goes - * the theory. - * - * Occasionally, it'll emit the DW_TAG_structure_type for the foo_t, - * and then neglect to emit the members. Strangely, the loner struct - * tag will always be followed by a proper nested declaration of - * something else. This is clearly a bug, but we're not going to have - * time to get it fixed before this goo goes back, so we'll have to work - * around it. If we see a no-membered struct with a nested declaration - * (i.e. die_child of the struct tag won't be null), we'll ignore it. - * Being paranoid, we won't simply remove it from the hash. Instead, - * we'll decline to create an iidesc for it, thus ensuring that this - * type won't make it into the output file. To be safe, we'll also - * change the name. - */ - if (tdp->t_members == NULL) { - const char *old = tdesc_name(tdp); - size_t newsz = 7 + strlen(old) + 1; - char *new = xmalloc(newsz); - (void) snprintf(new, newsz, "orphan %s", old); - - debug(3, "die %llu: worked around %s %s\n", off, typename, old); - - if (tdp->t_name != NULL) - free(tdp->t_name); - tdp->t_name = new; - return; - } - -out: - if (tdp->t_name != NULL) { - ii = xcalloc(sizeof (iidesc_t)); - ii->ii_type = II_SOU; - ii->ii_name = xstrdup(tdp->t_name); - ii->ii_dtype = tdp; - - iidesc_add(dw->dw_td->td_iihash, ii); - } -} - -static void -die_struct_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp) -{ - die_sou_create(dw, die, off, tdp, STRUCT, "struct"); -} - -static void -die_union_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp) -{ - die_sou_create(dw, die, off, tdp, UNION, "union"); -} - -/*ARGSUSED1*/ -static int -die_sou_resolve(tdesc_t *tdp, tdesc_t **tdpp, void *private) -{ - dwarf_t *dw = private; - mlist_t *ml; - tdesc_t *mt; - - if (tdp->t_flags & TDESC_F_RESOLVED) - return (1); - - debug(3, "resolving sou %s\n", tdesc_name(tdp)); - - for (ml = tdp->t_members; ml != NULL; ml = ml->ml_next) { - if (ml->ml_size == 0) { - mt = tdesc_basetype(ml->ml_type); - - if ((ml->ml_size = tdesc_bitsize(mt)) != 0) - continue; - - /* - * For empty members, or GCC/C99 flexible array - * members, a size of 0 is correct. - */ - if (mt->t_members == NULL) - continue; - if (mt->t_type == ARRAY && mt->t_ardef->ad_nelems == 0) - continue; - - dw->dw_nunres++; - return (1); - } - - if ((mt = tdesc_basetype(ml->ml_type)) == NULL) { - dw->dw_nunres++; - return (1); - } - - if (ml->ml_size != 0 && mt->t_type == INTRINSIC && - mt->t_intr->intr_nbits != ml->ml_size) { - /* - * This member is a bitfield, and needs to reference - * an intrinsic type with the same width. If the - * currently-referenced type isn't of the same width, - * we'll copy it, adjusting the width of the copy to - * the size we'd like. - */ - debug(3, "tdp %u: creating bitfield for %d bits\n", - tdp->t_id, ml->ml_size); - - ml->ml_type = tdesc_intr_clone(dw, mt, ml->ml_size); - } - } - - tdp->t_flags |= TDESC_F_RESOLVED; - - return (1); -} - -/*ARGSUSED1*/ -static int -die_sou_failed(tdesc_t *tdp, tdesc_t **tdpp, void *private) -{ - const char *typename = (tdp->t_type == STRUCT ? "struct" : "union"); - mlist_t *ml; - - if (tdp->t_flags & TDESC_F_RESOLVED) - return (1); - - for (ml = tdp->t_members; ml != NULL; ml = ml->ml_next) { - if (ml->ml_size == 0) { - fprintf(stderr, "%s %d: failed to size member \"%s\" " - "of type %s (%d)\n", typename, tdp->t_id, - ml->ml_name, tdesc_name(ml->ml_type), - ml->ml_type->t_id); - } - } - - return (1); -} - -static void -die_funcptr_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp) -{ - Dwarf_Attribute attr; - Dwarf_Half tag; - Dwarf_Die arg; - fndef_t *fn; - int i; - - debug(3, "die %llu: creating function pointer\n", off); - - /* - * We'll begin by processing any type definition nodes that may be - * lurking underneath this one. - */ - for (arg = die_child(dw, die); arg != NULL; - arg = die_sibling(dw, arg)) { - if ((tag = die_tag(dw, arg)) != DW_TAG_formal_parameter && - tag != DW_TAG_unspecified_parameters) { - /* Nested type declaration */ - die_create_one(dw, arg); - } - } - - if (die_isdecl(dw, die)) { - /* - * This is a prototype. We don't add prototypes to the - * tree, so we're going to drop the tdesc. Unfortunately, - * it has already been added to the tree. Nobody will reference - * it, though, and it will be leaked. - */ - return; - } - - fn = xcalloc(sizeof (fndef_t)); - - tdp->t_type = FUNCTION; - - if ((attr = die_attr(dw, die, DW_AT_type, 0)) != NULL) { - dwarf_dealloc(dw->dw_dw, attr, DW_DLA_ATTR); - fn->fn_ret = die_lookup_pass1(dw, die, DW_AT_type); - } else { - fn->fn_ret = tdesc_intr_void(dw); - } - - /* - * Count the arguments to the function, then read them in. - */ - for (fn->fn_nargs = 0, arg = die_child(dw, die); arg != NULL; - arg = die_sibling(dw, arg)) { - if ((tag = die_tag(dw, arg)) == DW_TAG_formal_parameter) - fn->fn_nargs++; - else if (tag == DW_TAG_unspecified_parameters && - fn->fn_nargs > 0) - fn->fn_vargs = 1; - } - - if (fn->fn_nargs != 0) { - debug(3, "die %llu: adding %d argument%s\n", off, fn->fn_nargs, - (fn->fn_nargs > 1 ? "s" : "")); - - fn->fn_args = xcalloc(sizeof (tdesc_t *) * fn->fn_nargs); - for (i = 0, arg = die_child(dw, die); - arg != NULL && i < fn->fn_nargs; - arg = die_sibling(dw, arg)) { - if (die_tag(dw, arg) != DW_TAG_formal_parameter) - continue; - - fn->fn_args[i++] = die_lookup_pass1(dw, arg, - DW_AT_type); - } - } - - tdp->t_fndef = fn; - tdp->t_flags |= TDESC_F_RESOLVED; -} - -/* - * GCC and DevPro use different names for the base types. While the terms are - * the same, they are arranged in a different order. Some terms, such as int, - * are implied in one, and explicitly named in the other. Given a base type - * as input, this routine will return a common name, along with an intr_t - * that reflects said name. - */ -static intr_t * -die_base_name_parse(const char *name, char **newp) -{ - char buf[100]; - char *base, *c; - int nlong = 0, nshort = 0, nchar = 0, nint = 0; - int sign = 1; - char fmt = '\0'; - intr_t *intr; - - if (strlen(name) > sizeof (buf) - 1) - terminate("base type name \"%s\" is too long\n", name); - - strncpy(buf, name, sizeof (buf)); - - for (c = strtok(buf, " "); c != NULL; c = strtok(NULL, " ")) { - if (strcmp(c, "signed") == 0) - sign = 1; - else if (strcmp(c, "unsigned") == 0) - sign = 0; - else if (strcmp(c, "long") == 0) - nlong++; - else if (strcmp(c, "char") == 0) { - nchar++; - fmt = 'c'; - } else if (strcmp(c, "short") == 0) - nshort++; - else if (strcmp(c, "int") == 0) - nint++; - else { - /* - * If we don't recognize any of the tokens, we'll tell - * the caller to fall back to the dwarf-provided - * encoding information. - */ - return (NULL); - } - } - - if (nchar > 1 || nshort > 1 || nint > 1 || nlong > 2) - return (NULL); - - if (nchar > 0) { - if (nlong > 0 || nshort > 0 || nint > 0) - return (NULL); - - base = "char"; - - } else if (nshort > 0) { - if (nlong > 0) - return (NULL); - - base = "short"; - - } else if (nlong > 0) { - base = "long"; - - } else { - base = "int"; - } - - intr = xcalloc(sizeof (intr_t)); - intr->intr_type = INTR_INT; - intr->intr_signed = sign; - intr->intr_iformat = fmt; - - snprintf(buf, sizeof (buf), "%s%s%s", - (sign ? "" : "unsigned "), - (nlong > 1 ? "long " : ""), - base); - - *newp = xstrdup(buf); - return (intr); -} - -typedef struct fp_size_map { - size_t fsm_typesz[2]; /* size of {32,64} type */ - uint_t fsm_enc[3]; /* CTF_FP_* for {bare,cplx,imagry} type */ -} fp_size_map_t; - -static const fp_size_map_t fp_encodings[] = { - { { 4, 4 }, { CTF_FP_SINGLE, CTF_FP_CPLX, CTF_FP_IMAGRY } }, - { { 8, 8 }, { CTF_FP_DOUBLE, CTF_FP_DCPLX, CTF_FP_DIMAGRY } }, -#ifdef __sparc - { { 16, 16 }, { CTF_FP_LDOUBLE, CTF_FP_LDCPLX, CTF_FP_LDIMAGRY } }, -#else - { { 12, 16 }, { CTF_FP_LDOUBLE, CTF_FP_LDCPLX, CTF_FP_LDIMAGRY } }, -#endif - { { 0, 0 } } -}; - -static uint_t -die_base_type2enc(dwarf_t *dw, Dwarf_Off off, Dwarf_Signed enc, size_t sz) -{ - const fp_size_map_t *map = fp_encodings; - uint_t szidx = dw->dw_ptrsz == sizeof (uint64_t); - uint_t mult = 1, col = 0; - - if (enc == DW_ATE_complex_float) { - mult = 2; - col = 1; - } else if (enc == DW_ATE_imaginary_float || - enc == DW_ATE_SUN_imaginary_float) - col = 2; - - while (map->fsm_typesz[szidx] != 0) { - if (map->fsm_typesz[szidx] * mult == sz) - return (map->fsm_enc[col]); - map++; - } - - terminate("die %llu: unrecognized real type size %u\n", off, sz); - /*NOTREACHED*/ - return (0); -} - -static intr_t * -die_base_from_dwarf(dwarf_t *dw, Dwarf_Die base, Dwarf_Off off, size_t sz) -{ - intr_t *intr = xcalloc(sizeof (intr_t)); - Dwarf_Signed enc; - - (void) die_signed(dw, base, DW_AT_encoding, &enc, DW_ATTR_REQ); - - switch (enc) { - case DW_ATE_unsigned: - case DW_ATE_address: - intr->intr_type = INTR_INT; - break; - case DW_ATE_unsigned_char: - intr->intr_type = INTR_INT; - intr->intr_iformat = 'c'; - break; - case DW_ATE_signed: - intr->intr_type = INTR_INT; - intr->intr_signed = 1; - break; - case DW_ATE_signed_char: - intr->intr_type = INTR_INT; - intr->intr_signed = 1; - intr->intr_iformat = 'c'; - break; - case DW_ATE_boolean: - intr->intr_type = INTR_INT; - intr->intr_signed = 1; - intr->intr_iformat = 'b'; - break; - case DW_ATE_float: - case DW_ATE_complex_float: - case DW_ATE_imaginary_float: - case DW_ATE_SUN_imaginary_float: - case DW_ATE_SUN_interval_float: - intr->intr_type = INTR_REAL; - intr->intr_signed = 1; - intr->intr_fformat = die_base_type2enc(dw, off, enc, sz); - break; - default: - terminate("die %llu: unknown base type encoding 0x%llx\n", - off, enc); - } - - return (intr); -} - -static void -die_base_create(dwarf_t *dw, Dwarf_Die base, Dwarf_Off off, tdesc_t *tdp) -{ - Dwarf_Unsigned sz; - intr_t *intr; - char *new; - - debug(3, "die %llu: creating base type\n", off); - - /* - * The compilers have their own clever (internally inconsistent) ideas - * as to what base types should look like. Some times gcc will, for - * example, use DW_ATE_signed_char for char. Other times, however, it - * will use DW_ATE_signed. Needless to say, this causes some problems - * down the road, particularly with merging. We do, however, use the - * DWARF idea of type sizes, as this allows us to avoid caring about - * the data model. - */ - (void) die_unsigned(dw, base, DW_AT_byte_size, &sz, DW_ATTR_REQ); - - if (tdp->t_name == NULL) - terminate("die %llu: base type without name\n", off); - - /* XXX make a name parser for float too */ - if ((intr = die_base_name_parse(tdp->t_name, &new)) != NULL) { - /* Found it. We'll use the parsed version */ - debug(3, "die %llu: name \"%s\" remapped to \"%s\"\n", off, - tdesc_name(tdp), new); - - free(tdp->t_name); - tdp->t_name = new; - } else { - /* - * We didn't recognize the type, so we'll create an intr_t - * based on the DWARF data. - */ - debug(3, "die %llu: using dwarf data for base \"%s\"\n", off, - tdesc_name(tdp)); - - intr = die_base_from_dwarf(dw, base, off, sz); - } - - intr->intr_nbits = sz * 8; - - tdp->t_type = INTRINSIC; - tdp->t_intr = intr; - tdp->t_size = sz; - - tdp->t_flags |= TDESC_F_RESOLVED; -} - -static void -die_through_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp, - int type, const char *typename) -{ - Dwarf_Attribute attr; - - debug(3, "die %llu: creating %s\n", off, typename); - - tdp->t_type = type; - - if ((attr = die_attr(dw, die, DW_AT_type, 0)) != NULL) { - dwarf_dealloc(dw->dw_dw, attr, DW_DLA_ATTR); - tdp->t_tdesc = die_lookup_pass1(dw, die, DW_AT_type); - } else { - tdp->t_tdesc = tdesc_intr_void(dw); - } - - if (type == POINTER) - tdp->t_size = dw->dw_ptrsz; - - tdp->t_flags |= TDESC_F_RESOLVED; - - if (type == TYPEDEF) { - iidesc_t *ii = xcalloc(sizeof (iidesc_t)); - ii->ii_type = II_TYPE; - ii->ii_name = xstrdup(tdp->t_name); - ii->ii_dtype = tdp; - - iidesc_add(dw->dw_td->td_iihash, ii); - } -} - -static void -die_typedef_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp) -{ - die_through_create(dw, die, off, tdp, TYPEDEF, "typedef"); -} - -static void -die_const_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp) -{ - die_through_create(dw, die, off, tdp, CONST, "const"); -} - -static void -die_pointer_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp) -{ - die_through_create(dw, die, off, tdp, POINTER, "pointer"); -} - -static void -die_restrict_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp) -{ - die_through_create(dw, die, off, tdp, RESTRICT, "restrict"); -} - -static void -die_volatile_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp) -{ - die_through_create(dw, die, off, tdp, VOLATILE, "volatile"); -} - -/*ARGSUSED3*/ -static void -die_function_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp) -{ - Dwarf_Die arg; - Dwarf_Half tag; - iidesc_t *ii; - char *name; - - debug(3, "die %llu: creating function definition\n", off); - - /* - * We'll begin by processing any type definition nodes that may be - * lurking underneath this one. - */ - for (arg = die_child(dw, die); arg != NULL; - arg = die_sibling(dw, arg)) { - if ((tag = die_tag(dw, arg)) != DW_TAG_formal_parameter && - tag != DW_TAG_variable) { - /* Nested type declaration */ - die_create_one(dw, arg); - } - } - - if (die_isdecl(dw, die) || (name = die_name(dw, die)) == NULL) { - /* - * We process neither prototypes nor subprograms without - * names. - */ - return; - } - - ii = xcalloc(sizeof (iidesc_t)); - ii->ii_type = die_isglobal(dw, die) ? II_GFUN : II_SFUN; - ii->ii_name = name; - if (ii->ii_type == II_SFUN) - ii->ii_owner = xstrdup(dw->dw_cuname); - - debug(3, "die %llu: function %s is %s\n", off, ii->ii_name, - (ii->ii_type == II_GFUN ? "global" : "static")); - - if (die_attr(dw, die, DW_AT_type, 0) != NULL) - ii->ii_dtype = die_lookup_pass1(dw, die, DW_AT_type); - else - ii->ii_dtype = tdesc_intr_void(dw); - - for (arg = die_child(dw, die); arg != NULL; - arg = die_sibling(dw, arg)) { - char *name; - - debug(3, "die %llu: looking at sub member at %llu\n", - off, die_off(dw, die)); - - if (die_tag(dw, arg) != DW_TAG_formal_parameter) - continue; - - if ((name = die_name(dw, arg)) == NULL) { - terminate("die %llu: func arg %d has no name\n", - off, ii->ii_nargs + 1); - } - - if (strcmp(name, "...") == 0) { - free(name); - ii->ii_vargs = 1; - continue; - } - - ii->ii_nargs++; - } - - if (ii->ii_nargs > 0) { - int i; - - debug(3, "die %llu: function has %d argument%s\n", off, - ii->ii_nargs, (ii->ii_nargs == 1 ? "" : "s")); - - ii->ii_args = xcalloc(sizeof (tdesc_t) * ii->ii_nargs); - - for (arg = die_child(dw, die), i = 0; - arg != NULL && i < ii->ii_nargs; - arg = die_sibling(dw, arg)) { - if (die_tag(dw, arg) != DW_TAG_formal_parameter) - continue; - - ii->ii_args[i++] = die_lookup_pass1(dw, arg, - DW_AT_type); - } - } - - iidesc_add(dw->dw_td->td_iihash, ii); -} - -/*ARGSUSED3*/ -static void -die_variable_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp) -{ - iidesc_t *ii; - char *name; - - debug(3, "die %llu: creating object definition\n", off); - - /* Skip "Non-Defining Declarations" */ - if (die_isdecl(dw, die)) - return; - - /* - * If we find a DIE of "Declarations Completing Non-Defining - * Declarations", we will use the referenced type's DIE. This isn't - * quite correct, e.g. DW_AT_decl_line will be the forward declaration - * not this site. It's sufficient for what we need, however: in - * particular, we should find DW_AT_external as needed there. - */ - if (die_attr(dw, die, DW_AT_specification, 0) != NULL) { - Dwarf_Die sdie; - Dwarf_Off soff; - - soff = die_attr_ref(dw, die, DW_AT_specification); - - if (dwarf_offdie(dw->dw_dw, soff, - &sdie, &dw->dw_err) != DW_DLV_OK) { - terminate("dwarf_offdie(%llu) failed: %s\n", - soff, dwarf_errmsg(dw->dw_err)); - } - - die = sdie; - } - - if ((name = die_name(dw, die)) == NULL) - return; - - ii = xcalloc(sizeof (iidesc_t)); - ii->ii_type = die_isglobal(dw, die) ? II_GVAR : II_SVAR; - ii->ii_name = name; - ii->ii_dtype = die_lookup_pass1(dw, die, DW_AT_type); - if (ii->ii_type == II_SVAR) - ii->ii_owner = xstrdup(dw->dw_cuname); - - iidesc_add(dw->dw_td->td_iihash, ii); -} - -/*ARGSUSED2*/ -static int -die_fwd_resolve(tdesc_t *fwd, tdesc_t **fwdp, void *private) -{ - if (fwd->t_flags & TDESC_F_RESOLVED) - return (1); - - if (fwd->t_tdesc != NULL) { - debug(3, "tdp %u: unforwarded %s\n", fwd->t_id, - tdesc_name(fwd)); - *fwdp = fwd->t_tdesc; - } - - fwd->t_flags |= TDESC_F_RESOLVED; - - return (1); -} - -/*ARGSUSED*/ -static void -die_lexblk_descend(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp) -{ - Dwarf_Die child = die_child(dw, die); - - if (child != NULL) - die_create(dw, child); -} - -/* - * Used to map the die to a routine which can parse it, using the tag to do the - * mapping. While the processing of most tags entails the creation of a tdesc, - * there are a few which don't - primarily those which result in the creation of - * iidescs which refer to existing tdescs. - */ - -#define DW_F_NOTDP 0x1 /* Don't create a tdesc for the creator */ - -typedef struct die_creator { - Dwarf_Half dc_tag; - uint16_t dc_flags; - void (*dc_create)(dwarf_t *, Dwarf_Die, Dwarf_Off, tdesc_t *); -} die_creator_t; - -static const die_creator_t die_creators[] = { - { DW_TAG_array_type, 0, die_array_create }, - { DW_TAG_enumeration_type, 0, die_enum_create }, - { DW_TAG_lexical_block, DW_F_NOTDP, die_lexblk_descend }, - { DW_TAG_pointer_type, 0, die_pointer_create }, - { DW_TAG_structure_type, 0, die_struct_create }, - { DW_TAG_subroutine_type, 0, die_funcptr_create }, - { DW_TAG_typedef, 0, die_typedef_create }, - { DW_TAG_union_type, 0, die_union_create }, - { DW_TAG_base_type, 0, die_base_create }, - { DW_TAG_const_type, 0, die_const_create }, - { DW_TAG_subprogram, DW_F_NOTDP, die_function_create }, - { DW_TAG_variable, DW_F_NOTDP, die_variable_create }, - { DW_TAG_volatile_type, 0, die_volatile_create }, - { DW_TAG_restrict_type, 0, die_restrict_create }, - { 0, 0, NULL } -}; - -static const die_creator_t * -die_tag2ctor(Dwarf_Half tag) -{ - const die_creator_t *dc; - - for (dc = die_creators; dc->dc_create != NULL; dc++) { - if (dc->dc_tag == tag) - return (dc); - } - - return (NULL); -} - -static void -die_create_one(dwarf_t *dw, Dwarf_Die die) -{ - Dwarf_Off off = die_off(dw, die); - const die_creator_t *dc; - Dwarf_Half tag; - tdesc_t *tdp; - - debug(3, "die %llu: create_one\n", off); - - if (off > dw->dw_maxoff) { - terminate("illegal die offset %llu (max %llu)\n", off, - dw->dw_maxoff); - } - - tag = die_tag(dw, die); - - if ((dc = die_tag2ctor(tag)) == NULL) { - debug(2, "die %llu: ignoring tag type %x\n", off, tag); - return; - } - - if ((tdp = tdesc_lookup(dw, off)) == NULL && - !(dc->dc_flags & DW_F_NOTDP)) { - tdp = xcalloc(sizeof (tdesc_t)); - tdp->t_id = off; - tdesc_add(dw, tdp); - } - - if (tdp != NULL) - tdp->t_name = die_name(dw, die); - - dc->dc_create(dw, die, off, tdp); -} - -static void -die_create(dwarf_t *dw, Dwarf_Die die) -{ - do { - die_create_one(dw, die); - } while ((die = die_sibling(dw, die)) != NULL); -} - -static tdtrav_cb_f die_resolvers[] = { - NULL, - NULL, /* intrinsic */ - NULL, /* pointer */ - die_array_resolve, /* array */ - NULL, /* function */ - die_sou_resolve, /* struct */ - die_sou_resolve, /* union */ - die_enum_resolve, /* enum */ - die_fwd_resolve, /* forward */ - NULL, /* typedef */ - NULL, /* typedef unres */ - NULL, /* volatile */ - NULL, /* const */ - NULL, /* restrict */ -}; - -static tdtrav_cb_f die_fail_reporters[] = { - NULL, - NULL, /* intrinsic */ - NULL, /* pointer */ - die_array_failed, /* array */ - NULL, /* function */ - die_sou_failed, /* struct */ - die_sou_failed, /* union */ - NULL, /* enum */ - NULL, /* forward */ - NULL, /* typedef */ - NULL, /* typedef unres */ - NULL, /* volatile */ - NULL, /* const */ - NULL, /* restrict */ -}; - -static void -die_resolve(dwarf_t *dw) -{ - int last = -1; - int pass = 0; - - do { - pass++; - dw->dw_nunres = 0; - - (void) iitraverse_hash(dw->dw_td->td_iihash, - &dw->dw_td->td_curvgen, NULL, NULL, die_resolvers, dw); - - debug(3, "resolve: pass %d, %u left\n", pass, dw->dw_nunres); - - if (dw->dw_nunres == last) { - fprintf(stderr, "%s: failed to resolve the following " - "types:\n", progname); - - (void) iitraverse_hash(dw->dw_td->td_iihash, - &dw->dw_td->td_curvgen, NULL, NULL, - die_fail_reporters, dw); - - terminate("failed to resolve types\n"); - } - - last = dw->dw_nunres; - - } while (dw->dw_nunres != 0); -} - -/* - * Any object containing a function or object symbol at any scope should also - * contain DWARF data. - */ -static boolean_t -should_have_dwarf(Elf *elf) -{ - Elf_Scn *scn = NULL; - Elf_Data *data = NULL; - GElf_Shdr shdr; - GElf_Sym sym; - uint32_t symdx = 0; - size_t nsyms = 0; - boolean_t found = B_FALSE; - - while ((scn = elf_nextscn(elf, scn)) != NULL) { - gelf_getshdr(scn, &shdr); - - if (shdr.sh_type == SHT_SYMTAB) { - found = B_TRUE; - break; - } - } - - if (!found) - terminate("cannot convert stripped objects\n"); - - data = elf_getdata(scn, NULL); - nsyms = shdr.sh_size / shdr.sh_entsize; - - for (symdx = 0; symdx < nsyms; symdx++) { - gelf_getsym(data, symdx, &sym); - - if ((GELF_ST_TYPE(sym.st_info) == STT_FUNC) || - (GELF_ST_TYPE(sym.st_info) == STT_TLS) || - (GELF_ST_TYPE(sym.st_info) == STT_OBJECT)) { - char *name; - - name = elf_strptr(elf, shdr.sh_link, sym.st_name); - - /* Studio emits these local symbols regardless */ - if ((strcmp(name, "Bbss.bss") != 0) && - (strcmp(name, "Ttbss.bss") != 0) && - (strcmp(name, "Ddata.data") != 0) && - (strcmp(name, "Ttdata.data") != 0) && - (strcmp(name, "Drodata.rodata") != 0)) - return (B_TRUE); - } - } - - return (B_FALSE); -} - -/*ARGSUSED*/ -int -dw_read(tdata_t *td, Elf *elf, const char *filename) -{ - Dwarf_Unsigned abboff, hdrlen, nxthdr; - Dwarf_Half vers, addrsz; - Dwarf_Die cu, child; - dwarf_t dw; - char *prod = NULL; - int rc; - - bzero(&dw, sizeof (dwarf_t)); - dw.dw_td = td; - dw.dw_ptrsz = elf_ptrsz(elf); - dw.dw_mfgtid_last = TID_MFGTID_BASE; - dw.dw_tidhash = hash_new(TDESC_HASH_BUCKETS, tdesc_idhash, tdesc_idcmp); - dw.dw_fwdhash = hash_new(TDESC_HASH_BUCKETS, tdesc_namehash, - tdesc_namecmp); - dw.dw_enumhash = hash_new(TDESC_HASH_BUCKETS, tdesc_namehash, - tdesc_namecmp); - - if ((rc = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dw.dw_dw, - &dw.dw_err)) == DW_DLV_NO_ENTRY) { - if (should_have_dwarf(elf)) { - errno = ENOENT; - return (-1); - } else { - return (0); - } - } else if (rc != DW_DLV_OK) { - if (dwarf_errno(dw.dw_err) == DW_DLE_DEBUG_INFO_NULL) { - /* - * There's no type data in the DWARF section, but - * libdwarf is too clever to handle that properly. - */ - return (0); - } - - terminate("failed to initialize DWARF: %s\n", - dwarf_errmsg(dw.dw_err)); - } - - if ((rc = dwarf_next_cu_header(dw.dw_dw, &hdrlen, &vers, &abboff, - &addrsz, &nxthdr, &dw.dw_err)) != DW_DLV_OK) - terminate("file does not contain valid DWARF data: %s\n", - dwarf_errmsg(dw.dw_err)); - - /* - * Some compilers emit no DWARF for empty files, others emit an empty - * compilation unit. - */ - if ((cu = die_sibling(&dw, NULL)) == NULL || - ((child = die_child(&dw, cu)) == NULL) && - should_have_dwarf(elf)) { - terminate("file does not contain dwarf type data " - "(try compiling with -g)\n"); - } else if (child == NULL) { - return (0); - } - - dw.dw_maxoff = nxthdr - 1; - - if (dw.dw_maxoff > TID_FILEMAX) - terminate("file contains too many types\n"); - - debug(1, "DWARF version: %d\n", vers); - if (vers != DWARF_VERSION) { - terminate("file contains incompatible version %d DWARF code " - "(version 2 required)\n", vers); - } - - if (die_string(&dw, cu, DW_AT_producer, &prod, 0)) { - debug(1, "DWARF emitter: %s\n", prod); - free(prod); - } - - if ((dw.dw_cuname = die_name(&dw, cu)) != NULL) { - char *base = xstrdup(basename(dw.dw_cuname)); - free(dw.dw_cuname); - dw.dw_cuname = base; - - debug(1, "CU name: %s\n", dw.dw_cuname); - } - - die_create(&dw, child); - - if ((rc = dwarf_next_cu_header(dw.dw_dw, &hdrlen, &vers, &abboff, - &addrsz, &nxthdr, &dw.dw_err)) != DW_DLV_NO_ENTRY) - terminate("multiple compilation units not supported\n"); - - (void) dwarf_finish(dw.dw_dw, &dw.dw_err); - - die_resolve(&dw); - - cvt_fixups(td, dw.dw_ptrsz); - - /* leak the dwarf_t */ - - return (0); -} diff --git a/usr/src/tools/ctf/cvt/fifo.c b/usr/src/tools/ctf/cvt/fifo.c deleted file mode 100644 index fb9a11fccf..0000000000 --- a/usr/src/tools/ctf/cvt/fifo.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2002 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Routines for manipulating a FIFO queue - */ - -#include <stdlib.h> - -#include "fifo.h" -#include "memory.h" - -typedef struct fifonode { - void *fn_data; - struct fifonode *fn_next; -} fifonode_t; - -struct fifo { - fifonode_t *f_head; - fifonode_t *f_tail; -}; - -fifo_t * -fifo_new(void) -{ - fifo_t *f; - - f = xcalloc(sizeof (fifo_t)); - - return (f); -} - -/* Add to the end of the fifo */ -void -fifo_add(fifo_t *f, void *data) -{ - fifonode_t *fn = xmalloc(sizeof (fifonode_t)); - - fn->fn_data = data; - fn->fn_next = NULL; - - if (f->f_tail == NULL) - f->f_head = f->f_tail = fn; - else { - f->f_tail->fn_next = fn; - f->f_tail = fn; - } -} - -/* Remove from the front of the fifo */ -void * -fifo_remove(fifo_t *f) -{ - fifonode_t *fn; - void *data; - - if ((fn = f->f_head) == NULL) - return (NULL); - - data = fn->fn_data; - if ((f->f_head = fn->fn_next) == NULL) - f->f_tail = NULL; - - free(fn); - - return (data); -} - -/*ARGSUSED*/ -static void -fifo_nullfree(void *arg) -{ - /* this function intentionally left blank */ -} - -/* Free an entire fifo */ -void -fifo_free(fifo_t *f, void (*freefn)(void *)) -{ - fifonode_t *fn = f->f_head; - fifonode_t *tmp; - - if (freefn == NULL) - freefn = fifo_nullfree; - - while (fn) { - (*freefn)(fn->fn_data); - - tmp = fn; - fn = fn->fn_next; - free(tmp); - } - - free(f); -} - -int -fifo_len(fifo_t *f) -{ - fifonode_t *fn; - int i; - - for (i = 0, fn = f->f_head; fn; fn = fn->fn_next, i++); - - return (i); -} - -int -fifo_empty(fifo_t *f) -{ - return (f->f_head == NULL); -} - -int -fifo_iter(fifo_t *f, int (*iter)(void *data, void *arg), void *arg) -{ - fifonode_t *fn; - int rc; - int ret = 0; - - for (fn = f->f_head; fn; fn = fn->fn_next) { - if ((rc = iter(fn->fn_data, arg)) < 0) - return (-1); - ret += rc; - } - - return (ret); -} diff --git a/usr/src/tools/ctf/cvt/fifo.h b/usr/src/tools/ctf/cvt/fifo.h deleted file mode 100644 index e4b948abc4..0000000000 --- a/usr/src/tools/ctf/cvt/fifo.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2002 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _FIFO_H -#define _FIFO_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Routines for manipulating a FIFO queue - */ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct fifo fifo_t; - -extern fifo_t *fifo_new(void); -extern void fifo_add(fifo_t *, void *); -extern void *fifo_remove(fifo_t *); -extern void fifo_free(fifo_t *, void (*)(void *)); -extern int fifo_len(fifo_t *); -extern int fifo_empty(fifo_t *); -extern int fifo_iter(fifo_t *, int (*)(void *, void *), void *); - -#ifdef __cplusplus -} -#endif - -#endif /* _FIFO_H */ diff --git a/usr/src/tools/ctf/cvt/fixup_tdescs.c b/usr/src/tools/ctf/cvt/fixup_tdescs.c deleted file mode 100644 index 8524693d02..0000000000 --- a/usr/src/tools/ctf/cvt/fixup_tdescs.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Workarounds for stabs generation bugs in the compiler and general needed - * fixups. - */ - -#include <stdio.h> -#include <strings.h> - -#include "ctf_headers.h" -#include "ctftools.h" -#include "hash.h" -#include "memory.h" - -/* - * Due to 4432619, the 6.1 compiler will sometimes incorrectly generate pointer - * stabs. Given a struct foo, and a corresponding typedef struct foo foo_t. - * In some cases, when faced with a pointer to a foo_t, the compiler will - * sometimes generate a stab that describes a pointer to a struct foo. - * Regardless of correctness, this breaks merges, as it occurs inconsistently - * by file. The following two routines know how to recognize and repair foo_t * - * and foo_t ** bugs in a specific set of cases. There is no general way to - * solve this problem without a fix to the compiler. In general, cases should - * only be added to these routines to fix merging problems in genunix. - */ -static void -fix_ptrptr_to_struct(tdata_t *td) -{ - char *strs[2] = { "as", "fdbuffer" }; - char *mems[2] = { "a_objectdir", "fd_shadow" }; - char *acts[2] = { "vnode", "page" }; - char *tgts[2] = { "vnode_t", "page_t" }; - tdesc_t *str; - tdesc_t *act, *tgt; - tdesc_t *p1, *p2; - mlist_t *ml; - int i; - - for (i = 0; i < sizeof (strs) / sizeof (strs[0]); i++) { - if (!(str = lookupname(strs[i])) || str->t_type != STRUCT) - continue; - - for (ml = str->t_members; ml; ml = ml->ml_next) { - if (streq(ml->ml_name, mems[i])) - break; - } - if (!ml) - continue; - - if (ml->ml_type->t_type != POINTER || ml->ml_type->t_name || - ml->ml_type->t_tdesc->t_type != POINTER || - ml->ml_type->t_tdesc->t_name) - continue; - - act = ml->ml_type->t_tdesc->t_tdesc; - if (act->t_type != STRUCT || !streq(act->t_name, acts[i])) - continue; - - if (!(tgt = lookupname(tgts[i])) || tgt->t_type != TYPEDEF) - continue; - - /* We have an instance of the bug */ - p2 = xcalloc(sizeof (*p2)); - p2->t_type = POINTER; - p2->t_id = td->td_nextid++; - p2->t_tdesc = tgt; - - p1 = xcalloc(sizeof (*p1)); - p1->t_type = POINTER; - p1->t_id = td->td_nextid++; - p1->t_tdesc = p2; - - ml->ml_type = p1; - - debug(3, "Fixed %s->%s => ptrptr struct %s bug\n", - strs[i], mems[i], acts[i]); - } -} - -static void -fix_ptr_to_struct(tdata_t *td) -{ - char *strs[2] = { "vmem", "id_space" }; - char *mems[2] = { NULL, "is_vmem" }; - tdesc_t *ptr = NULL; - tdesc_t *str, *vmt; - mlist_t *ml; - int i; - - if ((vmt = lookupname("vmem_t")) == NULL || vmt->t_type != TYPEDEF) - return; - - for (i = 0; i < sizeof (strs) / sizeof (strs[0]); i++) { - if (!(str = lookupname(strs[i])) || str->t_type != STRUCT) - continue; - - for (ml = str->t_members; ml; ml = ml->ml_next) { - if (mems[i] && !streq(ml->ml_name, mems[i])) - continue; - - if (ml->ml_type->t_type != POINTER || - ml->ml_type->t_name || - (ml->ml_type->t_tdesc->t_type != STRUCT && - ml->ml_type->t_tdesc->t_type != FORWARD) || - !streq(ml->ml_type->t_tdesc->t_name, "vmem")) - continue; - - debug(3, "Fixed %s->%s => ptr struct vmem bug\n", - strs[i], ml->ml_name); - - if (!ptr) { - ptr = xcalloc(sizeof (*ptr)); - ptr->t_type = POINTER; - ptr->t_id = td->td_nextid++; - ptr->t_tdesc = vmt; - } - - ml->ml_type = ptr; - } - } -} - -/* - * Fix stabs generation bugs. These routines must be run before the - * post-conversion merge - */ -void -cvt_fixstabs(tdata_t *td) -{ - fix_ptrptr_to_struct(td); - fix_ptr_to_struct(td); -} - -struct match { - tdesc_t *m_ret; - const char *m_name; -}; - -static int -matching_iidesc(iidesc_t *iidesc, struct match *match) -{ - if (!streq(iidesc->ii_name, match->m_name)) - return (0); - - if (iidesc->ii_type != II_TYPE && iidesc->ii_type != II_SOU) - return (0); - - match->m_ret = iidesc->ii_dtype; - return (-1); -} - -static tdesc_t * -lookup_tdesc(tdata_t *td, const char *name) -{ - struct match match = { NULL, name }; - iter_iidescs_by_name(td, name, (int (*)())matching_iidesc, &match); - return (match.m_ret); -} - -/* - * The cpu structure grows, with the addition of a machcpu member, if - * _MACHDEP is defined. This means that, for example, the cpu structure - * in unix is different from the cpu structure in genunix. As one might - * expect, this causes merges to fail. Since everyone indirectly contains - * a pointer to a CPU structure, the failed merges can cause massive amounts - * of duplication. In the case of unix uniquifying against genunix, upwards - * of 50% of the structures were unmerged due to this problem. We fix this - * by adding a cpu_m member. If machcpu hasn't been defined in our module, - * we make a forward node for it. - */ -static void -fix_small_cpu_struct(tdata_t *td, size_t ptrsize) -{ - tdesc_t *cput, *cpu; - tdesc_t *machcpu; - mlist_t *ml, *lml; - mlist_t *cpum; - int foundcpucyc = 0; - - /* - * We're going to take the circuitous route finding the cpu structure, - * because we want to make sure that we find the right one. It would - * be nice if we could verify the header name too. DWARF might not - * have the cpu_t, so we let this pass. - */ - if ((cput = lookup_tdesc(td, "cpu_t")) != NULL) { - if (cput->t_type != TYPEDEF) - return; - cpu = cput->t_tdesc; - } else { - cpu = lookup_tdesc(td, "cpu"); - } - - if (cpu == NULL) - return; - - if (!streq(cpu->t_name, "cpu") || cpu->t_type != STRUCT) - return; - - for (ml = cpu->t_members, lml = NULL; ml; - lml = ml, ml = ml->ml_next) { - if (strcmp(ml->ml_name, "cpu_cyclic") == 0) - foundcpucyc = 1; - } - - if (foundcpucyc == 0 || lml == NULL || - strcmp(lml->ml_name, "cpu_m") == 0) - return; - - /* - * We need to derive the right offset for the fake cpu_m member. To do - * that, we require a special unused member to be the last member - * before the 'cpu_m', that we encode knowledge of here. ABI alignment - * on all platforms is such that we only need to add a pointer-size - * number of bits to get the right offset for cpu_m. This would most - * likely break if gcc's -malign-double were ever used, but that option - * breaks the ABI anyway. - */ - if (!streq(lml->ml_name, "cpu_m_pad") && - getenv("CTFCONVERT_PERMISSIVE") == NULL) { - terminate("last cpu_t member before cpu_m is %s; " - "it must be cpu_m_pad.\n", lml->ml_name); - } - - if ((machcpu = lookup_tdesc(td, "machcpu")) == NULL) { - machcpu = xcalloc(sizeof (*machcpu)); - machcpu->t_name = xstrdup("machcpu"); - machcpu->t_id = td->td_nextid++; - machcpu->t_type = FORWARD; - } else if (machcpu->t_type != STRUCT) { - return; - } - - debug(3, "Adding cpu_m machcpu %s to cpu struct\n", - (machcpu->t_type == FORWARD ? "forward" : "struct")); - - cpum = xmalloc(sizeof (*cpum)); - cpum->ml_offset = lml->ml_offset + (ptrsize * NBBY); - cpum->ml_size = 0; - cpum->ml_name = xstrdup("cpu_m"); - cpum->ml_type = machcpu; - cpum->ml_next = NULL; - - lml->ml_next = cpum; -} - -void -cvt_fixups(tdata_t *td, size_t ptrsize) -{ - fix_small_cpu_struct(td, ptrsize); -} diff --git a/usr/src/tools/ctf/cvt/hash.c b/usr/src/tools/ctf/cvt/hash.c deleted file mode 100644 index e3c2978f6e..0000000000 --- a/usr/src/tools/ctf/cvt/hash.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Routines for manipulating hash tables - */ - -#include <stdio.h> -#include <stdlib.h> -#include <strings.h> -#include <sys/types.h> -#include <sys/sysmacros.h> - -#include "hash.h" -#include "memory.h" -#include "list.h" - -struct hash { - int h_nbuckets; - list_t **h_buckets; - - int (*h_hashfn)(int, void *); - int (*h_cmp)(void *, void *); -}; - -struct hash_data { - hash_t *hd_hash; - int (*hd_fun)(); - void *hd_key; - void *hd_private; - - void *hd_ret; -}; - -static int -hash_def_hash(int nbuckets, uintptr_t data) -{ - return (data % nbuckets); -} - -static int -hash_def_cmp(uintptr_t d1, uintptr_t d2) -{ - return (d1 != d2); -} - - -int -hash_name(int nbuckets, const char *name) -{ - const char *c; - ulong_t g; - int h = 0; - - for (c = name; *c; c++) { - h = (h << 4) + *c; - if ((g = (h & 0xf0000000)) != 0) { - h ^= (g >> 24); - h ^= g; - } - } - - return (h % nbuckets); -} - -hash_t * -hash_new(int nbuckets, int (*hashfn)(int, void *), int (*cmp)(void *, void *)) -{ - hash_t *hash; - - hash = xmalloc(sizeof (hash_t)); - hash->h_buckets = xcalloc(sizeof (list_t *) * nbuckets); - hash->h_nbuckets = nbuckets; - hash->h_hashfn = hashfn ? hashfn : (int (*)())hash_def_hash; - hash->h_cmp = cmp ? cmp : (int (*)())hash_def_cmp; - - return (hash); -} - -void -hash_add(hash_t *hash, void *key) -{ - int bucket = hash->h_hashfn(hash->h_nbuckets, key); - - list_add(&hash->h_buckets[bucket], key); -} - -static int -hash_add_cb(void *node, void *private) -{ - hash_add((hash_t *)private, node); - return (0); -} - -void -hash_merge(hash_t *to, hash_t *from) -{ - (void) hash_iter(from, hash_add_cb, to); -} - -static int -hash_remove_cb(void *key1, void *key2, hash_t *hash) -{ - return (hash->h_cmp(key1, key2)); -} - -void -hash_remove(hash_t *hash, void *key) -{ - int bucket = hash->h_hashfn(hash->h_nbuckets, key); - - (void) list_remove(&hash->h_buckets[bucket], key, - (int (*)())hash_remove_cb, hash); -} - -int -hash_match(hash_t *hash, void *key, int (*fun)(void *, void *), - void *private) -{ - int bucket = hash->h_hashfn(hash->h_nbuckets, key); - - return (list_iter(hash->h_buckets[bucket], fun, private) < 0); -} - -static int -hash_find_list_cb(void *node, struct hash_data *hd) -{ - int cbrc; - int rc = 0; - - if (hd->hd_hash->h_cmp(hd->hd_key, node) == 0) { - if ((cbrc = hd->hd_fun(node, hd->hd_private)) < 0) - return (cbrc); - rc += cbrc; - } - - return (rc); -} - -int -hash_find_iter(hash_t *hash, void *key, int (*fun)(void *, void *), - void *private) -{ - int bucket = hash->h_hashfn(hash->h_nbuckets, key); - struct hash_data hd; - - hd.hd_hash = hash; - hd.hd_fun = fun; - hd.hd_key = key; - hd.hd_private = private; - - return (list_iter(hash->h_buckets[bucket], (int (*)())hash_find_list_cb, - &hd)); -} - -/* stop on first match */ -static int -hash_find_first_cb(void *node, struct hash_data *hd) -{ - if (hd->hd_hash->h_cmp(hd->hd_key, node) == 0) { - hd->hd_ret = node; - return (-1); - } - - return (0); -} - -int -hash_find(hash_t *hash, void *key, void **value) -{ - int ret; - struct hash_data hd; - - hd.hd_hash = hash; - hd.hd_fun = hash_find_first_cb; - hd.hd_key = key; - - ret = hash_match(hash, key, (int (*)())hash_find_first_cb, &hd); - if (ret && value) - *value = hd.hd_ret; - - return (ret); -} - -int -hash_iter(hash_t *hash, int (*fun)(void *, void *), void *private) -{ - int cumrc = 0; - int cbrc; - int i; - - for (i = 0; i < hash->h_nbuckets; i++) { - if (hash->h_buckets[i] != NULL) { - if ((cbrc = list_iter(hash->h_buckets[i], fun, - private)) < 0) - return (cbrc); - cumrc += cbrc; - } - } - - return (cumrc); -} - -int -hash_count(hash_t *hash) -{ - int num, i; - - for (num = 0, i = 0; i < hash->h_nbuckets; i++) - num += list_count(hash->h_buckets[i]); - - return (num); -} - -void -hash_free(hash_t *hash, void (*datafree)(void *, void *), void *private) -{ - int i; - - if (hash == NULL) - return; - - for (i = 0; i < hash->h_nbuckets; i++) - list_free(hash->h_buckets[i], datafree, private); - free(hash->h_buckets); - free(hash); -} - -void -hash_stats(hash_t *hash, int verbose) -{ - int min = list_count(hash->h_buckets[0]); - int minidx = 0; - int max = min; - int maxidx = 0; - int tot = min; - int count; - int i; - - if (min && verbose) - printf("%3d: %d\n", 0, min); - for (i = 1; i < hash->h_nbuckets; i++) { - count = list_count(hash->h_buckets[i]); - if (min > count) { - min = count; - minidx = i; - } - if (max < count) { - max = count; - maxidx = i; - } - if (count && verbose) - printf("%3d: %d\n", i, count); - tot += count; - } - - printf("Hash statistics:\n"); - printf(" Buckets: %d\n", hash->h_nbuckets); - printf(" Items : %d\n", tot); - printf(" Min/Max: %d in #%d, %d in #%d\n", min, minidx, max, maxidx); - printf(" Average: %5.2f\n", (float)tot / (float)hash->h_nbuckets); -} diff --git a/usr/src/tools/ctf/cvt/hash.h b/usr/src/tools/ctf/cvt/hash.h deleted file mode 100644 index 94d93d4e5e..0000000000 --- a/usr/src/tools/ctf/cvt/hash.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _HASH_H -#define _HASH_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Routines for manipulating hash tables - */ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct hash hash_t; - -hash_t *hash_new(int, int (*)(int, void *), int (*)(void *, void *)); -void hash_add(hash_t *, void *); -void hash_merge(hash_t *, hash_t *); -void hash_remove(hash_t *, void *); -int hash_find(hash_t *, void *, void **); -int hash_find_iter(hash_t *, void *, int (*)(void *, void *), void *); -int hash_iter(hash_t *, int (*)(void *, void *), void *); -int hash_match(hash_t *, void *, int (*)(void *, void *), void *); -int hash_count(hash_t *); -int hash_name(int, const char *); -void hash_stats(hash_t *, int); -void hash_free(hash_t *, void (*)(void *, void *), void *); - -#ifdef __cplusplus -} -#endif - -#endif /* _HASH_H */ diff --git a/usr/src/tools/ctf/cvt/i386/Makefile b/usr/src/tools/ctf/cvt/i386/Makefile deleted file mode 100644 index 9d3f4c8023..0000000000 --- a/usr/src/tools/ctf/cvt/i386/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -include ../Makefile.com -include ../Makefile.targ - diff --git a/usr/src/tools/ctf/cvt/iidesc.c b/usr/src/tools/ctf/cvt/iidesc.c deleted file mode 100644 index 0d75e3f852..0000000000 --- a/usr/src/tools/ctf/cvt/iidesc.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * Routines for manipulating iidesc_t structures - */ - -#include <stdio.h> -#include <stdlib.h> -#include <strings.h> - -#include "ctftools.h" -#include "memory.h" -#include "list.h" -#include "hash.h" - -typedef struct iidesc_find { - iidesc_t *iif_tgt; - iidesc_t *iif_ret; -} iidesc_find_t; - -iidesc_t * -iidesc_new(char *name) -{ - iidesc_t *ii; - - ii = xcalloc(sizeof (iidesc_t)); - if (name) - ii->ii_name = xstrdup(name); - - return (ii); -} - -int -iidesc_hash(int nbuckets, void *arg) -{ - iidesc_t *ii = arg; - int h = 0; - - if (ii->ii_name) - return (hash_name(nbuckets, ii->ii_name)); - - return (h); -} - -static int -iidesc_cmp(iidesc_t *src, iidesc_find_t *find) -{ - iidesc_t *tgt = find->iif_tgt; - - if (src->ii_type != tgt->ii_type || - !streq(src->ii_name, tgt->ii_name)) - return (0); - - find->iif_ret = src; - - return (-1); -} - -void -iidesc_add(hash_t *hash, iidesc_t *new) -{ - iidesc_find_t find; - - find.iif_tgt = new; - find.iif_ret = NULL; - - (void) hash_match(hash, new, (int (*)())iidesc_cmp, &find); - - if (find.iif_ret != NULL) { - iidesc_t *old = find.iif_ret; - iidesc_t tmp; - /* replacing existing one */ - bcopy(old, &tmp, sizeof (tmp)); - bcopy(new, old, sizeof (*old)); - bcopy(&tmp, new, sizeof (*new)); - - iidesc_free(new); - return; - } - - hash_add(hash, new); -} - -void -iter_iidescs_by_name(tdata_t *td, const char *name, - int (*func)(iidesc_t *, void *), void *data) -{ - iidesc_t tmpdesc; - bzero(&tmpdesc, sizeof (iidesc_t)); - tmpdesc.ii_name = (char *)name; - (void) hash_match(td->td_iihash, &tmpdesc, (int (*)())func, data); -} - -iidesc_t * -iidesc_dup(iidesc_t *src) -{ - iidesc_t *tgt; - - tgt = xmalloc(sizeof (iidesc_t)); - bcopy(src, tgt, sizeof (iidesc_t)); - - tgt->ii_name = src->ii_name ? xstrdup(src->ii_name) : NULL; - tgt->ii_owner = src->ii_owner ? xstrdup(src->ii_owner) : NULL; - - if (tgt->ii_nargs) { - tgt->ii_args = xmalloc(sizeof (tdesc_t *) * tgt->ii_nargs); - bcopy(src->ii_args, tgt->ii_args, - sizeof (tdesc_t *) * tgt->ii_nargs); - } - - return (tgt); -} - -iidesc_t * -iidesc_dup_rename(iidesc_t *src, char const *name, char const *owner) -{ - iidesc_t *tgt = iidesc_dup(src); - free(tgt->ii_name); - free(tgt->ii_owner); - - tgt->ii_name = name ? xstrdup(name) : NULL; - tgt->ii_owner = owner ? xstrdup(owner) : NULL; - - return (tgt); -} - -/*ARGSUSED*/ -void -iidesc_free_cb(void *ptr, void *private) -{ - iidesc_t *idp = ptr; - - free(idp->ii_name); - free(idp->ii_args); - free(idp->ii_owner); - free(idp); -} - -void -iidesc_free(iidesc_t *idp) -{ - iidesc_free_cb(idp, NULL); -} - -int -iidesc_dump(iidesc_t *ii) -{ - printf("type: %d name %s\n", ii->ii_type, - (ii->ii_name ? ii->ii_name : "(anon)")); - - return (0); -} - -int -iidesc_count_type(void *data, void *private) -{ - iidesc_t *ii = data; - iitype_t match = (iitype_t)private; - - return (ii->ii_type == match); -} - -void -iidesc_stats(hash_t *ii) -{ - printf("GFun: %5d SFun: %5d GVar: %5d SVar: %5d T %5d SOU: %5d\n", - hash_iter(ii, iidesc_count_type, (void *)II_GFUN), - hash_iter(ii, iidesc_count_type, (void *)II_SFUN), - hash_iter(ii, iidesc_count_type, (void *)II_GVAR), - hash_iter(ii, iidesc_count_type, (void *)II_SVAR), - hash_iter(ii, iidesc_count_type, (void *)II_TYPE), - hash_iter(ii, iidesc_count_type, (void *)II_SOU)); -} diff --git a/usr/src/tools/ctf/cvt/input.c b/usr/src/tools/ctf/cvt/input.c deleted file mode 100644 index d901e5340b..0000000000 --- a/usr/src/tools/ctf/cvt/input.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Routines for retrieving CTF data from a .SUNW_ctf ELF section - */ - -#include <stdio.h> -#include <stdlib.h> -#include <fcntl.h> -#include <unistd.h> -#include <gelf.h> -#include <strings.h> -#include <sys/types.h> - -#include "ctftools.h" -#include "memory.h" -#include "symbol.h" - -typedef int read_cb_f(tdata_t *, char *, void *); - -/* - * Return the source types that the object was generated from. - */ -source_types_t -built_source_types(Elf *elf, char const *file) -{ - source_types_t types = SOURCE_NONE; - symit_data_t *si; - - if ((si = symit_new(elf, file)) == NULL) - return (SOURCE_NONE); - - while (symit_next(si, STT_FILE) != NULL) { - char *name = symit_name(si); - size_t len = strlen(name); - if (len < 2 || name[len - 2] != '.') { - types |= SOURCE_UNKNOWN; - continue; - } - - switch (name[len - 1]) { - case 'c': - types |= SOURCE_C; - break; - case 'h': - /* ignore */ - break; - case 's': - types |= SOURCE_S; - break; - default: - types |= SOURCE_UNKNOWN; - } - } - - symit_free(si); - return (types); -} - -static int -read_file(Elf *elf, char *file, char *label, read_cb_f *func, void *arg, - int require_ctf) -{ - Elf_Scn *ctfscn; - Elf_Data *ctfdata; - symit_data_t *si = NULL; - int ctfscnidx; - tdata_t *td; - - if ((ctfscnidx = findelfsecidx(elf, file, ".SUNW_ctf")) < 0) { - if (require_ctf && - (built_source_types(elf, file) & SOURCE_C)) { - terminate("Input file %s was partially built from " - "C sources, but no CTF data was present\n", file); - } - return (0); - } - - if ((ctfscn = elf_getscn(elf, ctfscnidx)) == NULL || - (ctfdata = elf_getdata(ctfscn, NULL)) == NULL) - elfterminate(file, "Cannot read CTF section"); - - /* Reconstruction of type tree */ - if ((si = symit_new(elf, file)) == NULL) { - warning("%s has no symbol table - skipping", file); - return (0); - } - - td = ctf_load(file, ctfdata->d_buf, ctfdata->d_size, si, label); - tdata_build_hashes(td); - - symit_free(si); - - if (td != NULL) { - if (func(td, file, arg) < 0) - return (-1); - else - return (1); - } - return (0); -} - -static int -read_archive(int fd, Elf *elf, char *file, char *label, read_cb_f *func, - void *arg, int require_ctf) -{ - Elf *melf; - Elf_Cmd cmd = ELF_C_READ; - Elf_Arhdr *arh; - int secnum = 1, found = 0; - - while ((melf = elf_begin(fd, cmd, elf)) != NULL) { - int rc = 0; - - if ((arh = elf_getarhdr(melf)) == NULL) { - elfterminate(file, "Can't get archive header for " - "member %d", secnum); - } - - /* skip special sections - their names begin with "/" */ - if (*arh->ar_name != '/') { - size_t memlen = strlen(file) + 1 + - strlen(arh->ar_name) + 1 + 1; - char *memname = xmalloc(memlen); - - snprintf(memname, memlen, "%s(%s)", file, arh->ar_name); - - switch (elf_kind(melf)) { - case ELF_K_AR: - rc = read_archive(fd, melf, memname, label, - func, arg, require_ctf); - break; - case ELF_K_ELF: - rc = read_file(melf, memname, label, - func, arg, require_ctf); - break; - default: - terminate("%s: Unknown elf kind %d\n", - memname, elf_kind(melf)); - } - - free(memname); - } - - cmd = elf_next(melf); - (void) elf_end(melf); - secnum++; - - if (rc < 0) - return (rc); - else - found += rc; - } - - return (found); -} - -static int -read_ctf_common(char *file, char *label, read_cb_f *func, void *arg, - int require_ctf) -{ - Elf *elf; - int found = 0; - int fd; - - debug(3, "Reading %s (label %s)\n", file, (label ? label : "NONE")); - - (void) elf_version(EV_CURRENT); - - if ((fd = open(file, O_RDONLY)) < 0) - terminate("%s: Cannot open for reading", file); - if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) - elfterminate(file, "Cannot read"); - - switch (elf_kind(elf)) { - case ELF_K_AR: - found = read_archive(fd, elf, file, label, - func, arg, require_ctf); - break; - - case ELF_K_ELF: - found = read_file(elf, file, label, - func, arg, require_ctf); - break; - - default: - terminate("%s: Unknown elf kind %d\n", file, elf_kind(elf)); - } - - (void) elf_end(elf); - (void) close(fd); - - return (found); -} - -/*ARGSUSED*/ -int -read_ctf_save_cb(tdata_t *td, char *name, void *retp) -{ - tdata_t **tdp = retp; - - *tdp = td; - - return (1); -} - -int -read_ctf(char **files, int n, char *label, read_cb_f *func, void *private, - int require_ctf) -{ - int found; - int i, rc; - - for (i = 0, found = 0; i < n; i++) { - if ((rc = read_ctf_common(files[i], label, func, - private, require_ctf)) < 0) - return (rc); - found += rc; - } - - return (found); -} - -static int -count_archive(int fd, Elf *elf, char *file) -{ - Elf *melf; - Elf_Cmd cmd = ELF_C_READ; - Elf_Arhdr *arh; - int nfiles = 0, err = 0; - - while ((melf = elf_begin(fd, cmd, elf)) != NULL) { - if ((arh = elf_getarhdr(melf)) == NULL) { - warning("Can't process input archive %s\n", - file); - err++; - } - - if (*arh->ar_name != '/') - nfiles++; - - cmd = elf_next(melf); - (void) elf_end(melf); - } - - if (err > 0) - return (-1); - - return (nfiles); -} - -int -count_files(char **files, int n) -{ - int nfiles = 0, err = 0; - Elf *elf; - int fd, rc, i; - - (void) elf_version(EV_CURRENT); - - for (i = 0; i < n; i++) { - char *file = files[i]; - - if ((fd = open(file, O_RDONLY)) < 0) { - warning("Can't read input file %s", file); - err++; - continue; - } - - if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { - warning("Can't open input file %s: %s\n", file, - elf_errmsg(-1)); - err++; - (void) close(fd); - continue; - } - - switch (elf_kind(elf)) { - case ELF_K_AR: - if ((rc = count_archive(fd, elf, file)) < 0) - err++; - else - nfiles += rc; - break; - case ELF_K_ELF: - nfiles++; - break; - default: - warning("Input file %s is corrupt\n", file); - err++; - } - - (void) elf_end(elf); - (void) close(fd); - } - - if (err > 0) - return (-1); - - debug(2, "Found %d files in %d input files\n", nfiles, n); - - return (nfiles); -} - -struct symit_data { - GElf_Shdr si_shdr; - Elf_Data *si_symd; - Elf_Data *si_strd; - GElf_Sym si_cursym; - char *si_curname; - char *si_curfile; - int si_nument; - int si_next; -}; - -symit_data_t * -symit_new(Elf *elf, const char *file) -{ - symit_data_t *si; - Elf_Scn *scn; - int symtabidx; - - if ((symtabidx = findelfsecidx(elf, file, ".symtab")) < 0) - return (NULL); - - si = xcalloc(sizeof (symit_data_t)); - - if ((scn = elf_getscn(elf, symtabidx)) == NULL || - gelf_getshdr(scn, &si->si_shdr) == NULL || - (si->si_symd = elf_getdata(scn, NULL)) == NULL) - elfterminate(file, "Cannot read .symtab"); - - if ((scn = elf_getscn(elf, si->si_shdr.sh_link)) == NULL || - (si->si_strd = elf_getdata(scn, NULL)) == NULL) - elfterminate(file, "Cannot read strings for .symtab"); - - si->si_nument = si->si_shdr.sh_size / si->si_shdr.sh_entsize; - - return (si); -} - -void -symit_free(symit_data_t *si) -{ - free(si); -} - -void -symit_reset(symit_data_t *si) -{ - si->si_next = 0; -} - -char * -symit_curfile(symit_data_t *si) -{ - return (si->si_curfile); -} - -GElf_Sym * -symit_next(symit_data_t *si, int type) -{ - GElf_Sym sym; - int check_sym = (type == STT_OBJECT || type == STT_FUNC); - - for (; si->si_next < si->si_nument; si->si_next++) { - gelf_getsym(si->si_symd, si->si_next, &si->si_cursym); - gelf_getsym(si->si_symd, si->si_next, &sym); - si->si_curname = (caddr_t)si->si_strd->d_buf + sym.st_name; - - if (GELF_ST_TYPE(sym.st_info) == STT_FILE) - si->si_curfile = si->si_curname; - - if (GELF_ST_TYPE(sym.st_info) != type || - sym.st_shndx == SHN_UNDEF) - continue; - - if (check_sym && ignore_symbol(&sym, si->si_curname)) - continue; - - si->si_next++; - - return (&si->si_cursym); - } - - return (NULL); -} - -char * -symit_name(symit_data_t *si) -{ - return (si->si_curname); -} diff --git a/usr/src/tools/ctf/cvt/merge.c b/usr/src/tools/ctf/cvt/merge.c deleted file mode 100644 index 2af28b65a2..0000000000 --- a/usr/src/tools/ctf/cvt/merge.c +++ /dev/null @@ -1,1140 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * This file contains routines that merge one tdata_t tree, called the child, - * into another, called the parent. Note that these names are used mainly for - * convenience and to represent the direction of the merge. They are not meant - * to imply any relationship between the tdata_t graphs prior to the merge. - * - * tdata_t structures contain two main elements - a hash of iidesc_t nodes, and - * a directed graph of tdesc_t nodes, pointed to by the iidesc_t nodes. Simply - * put, we merge the tdesc_t graphs, followed by the iidesc_t nodes, and then we - * clean up loose ends. - * - * The algorithm is as follows: - * - * 1. Mapping iidesc_t nodes - * - * For each child iidesc_t node, we first try to map its tdesc_t subgraph - * against the tdesc_t graph in the parent. For each node in the child subgraph - * that exists in the parent, a mapping between the two (between their type IDs) - * is established. For the child nodes that cannot be mapped onto existing - * parent nodes, a mapping is established between the child node ID and a - * newly-allocated ID that the node will use when it is re-created in the - * parent. These unmappable nodes are added to the md_tdtba (tdesc_t To Be - * Added) hash, which tracks nodes that need to be created in the parent. - * - * If all of the nodes in the subgraph for an iidesc_t in the child can be - * mapped to existing nodes in the parent, then we can try to map the child - * iidesc_t onto an iidesc_t in the parent. If we cannot find an equivalent - * iidesc_t, or if we were not able to completely map the tdesc_t subgraph(s), - * then we add this iidesc_t to the md_iitba (iidesc_t To Be Added) list. This - * list tracks iidesc_t nodes that are to be created in the parent. - * - * While visiting the tdesc_t nodes, we may discover a forward declaration (a - * FORWARD tdesc_t) in the parent that is resolved in the child. That is, there - * may be a structure or union definition in the child with the same name as the - * forward declaration in the parent. If we find such a node, we record an - * association in the md_fdida (Forward => Definition ID Association) list - * between the parent ID of the forward declaration and the ID that the - * definition will use when re-created in the parent. - * - * 2. Creating new tdesc_t nodes (the md_tdtba hash) - * - * We have now attempted to map all tdesc_t nodes from the child into the - * parent, and have, in md_tdtba, a hash of all tdesc_t nodes that need to be - * created (or, as we so wittily call it, conjured) in the parent. We iterate - * through this hash, creating the indicated tdesc_t nodes. For a given tdesc_t - * node, conjuring requires two steps - the copying of the common tdesc_t data - * (name, type, etc) from the child node, and the creation of links from the - * newly-created node to the parent equivalents of other tdesc_t nodes pointed - * to by node being conjured. Note that in some cases, the targets of these - * links will be on the md_tdtba hash themselves, and may not have been created - * yet. As such, we can't establish the links from these new nodes into the - * parent graph. We therefore conjure them with links to nodes in the *child* - * graph, and add pointers to the links to be created to the md_tdtbr (tdesc_t - * To Be Remapped) hash. For example, a POINTER tdesc_t that could not be - * resolved would have its &tdesc_t->t_tdesc added to md_tdtbr. - * - * 3. Creating new iidesc_t nodes (the md_iitba list) - * - * When we have completed step 2, all tdesc_t nodes have been created (or - * already existed) in the parent. Some of them may have incorrect links (the - * members of the md_tdtbr list), but they've all been created. As such, we can - * create all of the iidesc_t nodes, as we can attach the tdesc_t subgraph - * pointers correctly. We create each node, and attach the pointers to the - * appropriate parts of the parent tdesc_t graph. - * - * 4. Resolving newly-created tdesc_t node links (the md_tdtbr list) - * - * As in step 3, we rely on the fact that all of the tdesc_t nodes have been - * created. Each entry in the md_tdtbr list is a pointer to where a link into - * the parent will be established. As saved in the md_tdtbr list, these - * pointers point into the child tdesc_t subgraph. We can thus get the target - * type ID from the child, look at the ID mapping to determine the desired link - * target, and redirect the link accordingly. - * - * 5. Parent => child forward declaration resolution - * - * If entries were made in the md_fdida list in step 1, we have forward - * declarations in the parent that need to be resolved to their definitions - * re-created in step 2 from the child. Using the md_fdida list, we can locate - * the definition for the forward declaration, and we can redirect all inbound - * edges to the forward declaration node to the actual definition. - * - * A pox on the house of anyone who changes the algorithm without updating - * this comment. - */ - -#include <stdio.h> -#include <strings.h> -#include <assert.h> -#include <pthread.h> - -#include "ctf_headers.h" -#include "ctftools.h" -#include "list.h" -#include "alist.h" -#include "memory.h" -#include "traverse.h" - -typedef struct equiv_data equiv_data_t; -typedef struct merge_cb_data merge_cb_data_t; - -/* - * There are two traversals in this file, for equivalency and for tdesc_t - * re-creation, that do not fit into the tdtraverse() framework. We have our - * own traversal mechanism and ops vector here for those two cases. - */ -typedef struct tdesc_ops { - char *name; - int (*equiv)(tdesc_t *, tdesc_t *, equiv_data_t *); - tdesc_t *(*conjure)(tdesc_t *, int, merge_cb_data_t *); -} tdesc_ops_t; -extern tdesc_ops_t tdesc_ops[]; - -/* - * The workhorse structure of tdata_t merging. Holds all lists of nodes to be - * processed during various phases of the merge algorithm. - */ -struct merge_cb_data { - tdata_t *md_parent; - tdata_t *md_tgt; - alist_t *md_ta; /* Type Association */ - alist_t *md_fdida; /* Forward -> Definition ID Association */ - list_t **md_iitba; /* iidesc_t nodes To Be Added to the parent */ - hash_t *md_tdtba; /* tdesc_t nodes To Be Added to the parent */ - list_t **md_tdtbr; /* tdesc_t nodes To Be Remapped */ - int md_flags; -}; /* merge_cb_data_t */ - -/* - * When we first create a tdata_t from stabs data, we will have duplicate nodes. - * Normal merges, however, assume that the child tdata_t is already self-unique, - * and for speed reasons do not attempt to self-uniquify. If this flag is set, - * the merge algorithm will self-uniquify by avoiding the insertion of - * duplicates in the md_tdtdba list. - */ -#define MCD_F_SELFUNIQUIFY 0x1 - -/* - * When we merge the CTF data for the modules, we don't want it to contain any - * data that can be found in the reference module (usually genunix). If this - * flag is set, we're doing a merge between the fully merged tdata_t for this - * module and the tdata_t for the reference module, with the data unique to this - * module ending up in a third tdata_t. It is this third tdata_t that will end - * up in the .SUNW_ctf section for the module. - */ -#define MCD_F_REFMERGE 0x2 - -/* - * Mapping of child type IDs to parent type IDs - */ - -static void -add_mapping(alist_t *ta, tid_t srcid, tid_t tgtid) -{ - debug(3, "Adding mapping %u => %u\n", srcid, tgtid); - - assert(!alist_find(ta, (void *)srcid, NULL)); - assert(srcid != 0 && tgtid != 0); - - alist_add(ta, (void *)srcid, (void *)tgtid); -} - -static tid_t -get_mapping(alist_t *ta, int srcid) -{ - long ltgtid; - - if (alist_find(ta, (void *)srcid, (void **)<gtid)) - return ((int)ltgtid); - else - return (0); -} - -/* - * Determining equivalence of tdesc_t subgraphs - */ - -struct equiv_data { - alist_t *ed_ta; - tdesc_t *ed_node; - tdesc_t *ed_tgt; - - int ed_clear_mark; - int ed_cur_mark; - int ed_selfuniquify; -}; /* equiv_data_t */ - -static int equiv_node(tdesc_t *, tdesc_t *, equiv_data_t *); - -/*ARGSUSED2*/ -static int -equiv_intrinsic(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed) -{ - intr_t *si = stdp->t_intr; - intr_t *ti = ttdp->t_intr; - - if (si->intr_type != ti->intr_type || - si->intr_signed != ti->intr_signed || - si->intr_offset != ti->intr_offset || - si->intr_nbits != ti->intr_nbits) - return (0); - - if (si->intr_type == INTR_INT && - si->intr_iformat != ti->intr_iformat) - return (0); - else if (si->intr_type == INTR_REAL && - si->intr_fformat != ti->intr_fformat) - return (0); - - return (1); -} - -static int -equiv_plain(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed) -{ - return (equiv_node(stdp->t_tdesc, ttdp->t_tdesc, ed)); -} - -static int -equiv_function(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed) -{ - fndef_t *fn1 = stdp->t_fndef, *fn2 = ttdp->t_fndef; - int i; - - if (fn1->fn_nargs != fn2->fn_nargs || - fn1->fn_vargs != fn2->fn_vargs) - return (0); - - if (!equiv_node(fn1->fn_ret, fn2->fn_ret, ed)) - return (0); - - for (i = 0; i < fn1->fn_nargs; i++) { - if (!equiv_node(fn1->fn_args[i], fn2->fn_args[i], ed)) - return (0); - } - - return (1); -} - -static int -equiv_array(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed) -{ - ardef_t *ar1 = stdp->t_ardef, *ar2 = ttdp->t_ardef; - - if (!equiv_node(ar1->ad_contents, ar2->ad_contents, ed) || - !equiv_node(ar1->ad_idxtype, ar2->ad_idxtype, ed)) - return (0); - - if (ar1->ad_nelems != ar2->ad_nelems) - return (0); - - return (1); -} - -static int -equiv_su(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed) -{ - mlist_t *ml1 = stdp->t_members, *ml2 = ttdp->t_members; - mlist_t *olm1 = NULL; - - while (ml1 && ml2) { - if (ml1->ml_offset != ml2->ml_offset || - strcmp(ml1->ml_name, ml2->ml_name) != 0) - return (0); - - /* - * Don't do the recursive equivalency checking more than - * we have to. - */ - if (olm1 == NULL || olm1->ml_type->t_id != ml1->ml_type->t_id) { - if (ml1->ml_size != ml2->ml_size || - !equiv_node(ml1->ml_type, ml2->ml_type, ed)) - return (0); - } - - olm1 = ml1; - ml1 = ml1->ml_next; - ml2 = ml2->ml_next; - } - - if (ml1 || ml2) - return (0); - - return (1); -} - -/*ARGSUSED2*/ -static int -equiv_enum(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed) -{ - elist_t *el1 = stdp->t_emem; - elist_t *el2 = ttdp->t_emem; - - while (el1 && el2) { - if (el1->el_number != el2->el_number || - strcmp(el1->el_name, el2->el_name) != 0) - return (0); - - el1 = el1->el_next; - el2 = el2->el_next; - } - - if (el1 || el2) - return (0); - - return (1); -} - -/*ARGSUSED*/ -static int -equiv_assert(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed) -{ - /* foul, evil, and very bad - this is a "shouldn't happen" */ - assert(1 == 0); - - return (0); -} - -static int -fwd_equiv(tdesc_t *ctdp, tdesc_t *mtdp) -{ - tdesc_t *defn = (ctdp->t_type == FORWARD ? mtdp : ctdp); - - return (defn->t_type == STRUCT || defn->t_type == UNION); -} - -static int -equiv_node(tdesc_t *ctdp, tdesc_t *mtdp, equiv_data_t *ed) -{ - int (*equiv)(); - int mapping; - - if (ctdp->t_emark > ed->ed_clear_mark || - mtdp->t_emark > ed->ed_clear_mark) - return (ctdp->t_emark == mtdp->t_emark); - - /* - * In normal (non-self-uniquify) mode, we don't want to do equivalency - * checking on a subgraph that has already been checked. If a mapping - * has already been established for a given child node, we can simply - * compare the mapping for the child node with the ID of the parent - * node. If we are in self-uniquify mode, then we're comparing two - * subgraphs within the child graph, and thus need to ignore any - * type mappings that have been created, as they are only valid into the - * parent. - */ - if ((mapping = get_mapping(ed->ed_ta, ctdp->t_id)) > 0 && - mapping == mtdp->t_id && !ed->ed_selfuniquify) - return (1); - - if (!streq(ctdp->t_name, mtdp->t_name)) - return (0); - - if (ctdp->t_type != mtdp->t_type) { - if (ctdp->t_type == FORWARD || mtdp->t_type == FORWARD) - return (fwd_equiv(ctdp, mtdp)); - else - return (0); - } - - ctdp->t_emark = ed->ed_cur_mark; - mtdp->t_emark = ed->ed_cur_mark; - ed->ed_cur_mark++; - - if ((equiv = tdesc_ops[ctdp->t_type].equiv) != NULL) - return (equiv(ctdp, mtdp, ed)); - - return (1); -} - -/* - * We perform an equivalency check on two subgraphs by traversing through them - * in lockstep. If a given node is equivalent in both the parent and the child, - * we mark it in both subgraphs, using the t_emark field, with a monotonically - * increasing number. If, in the course of the traversal, we reach a node that - * we have visited and numbered during this equivalency check, we have a cycle. - * If the previously-visited nodes don't have the same emark, then the edges - * that brought us to these nodes are not equivalent, and so the check ends. - * If the emarks are the same, the edges are equivalent. We then backtrack and - * continue the traversal. If we have exhausted all edges in the subgraph, and - * have not found any inequivalent nodes, then the subgraphs are equivalent. - */ -static int -equiv_cb(void *bucket, void *arg) -{ - equiv_data_t *ed = arg; - tdesc_t *mtdp = bucket; - tdesc_t *ctdp = ed->ed_node; - - ed->ed_clear_mark = ed->ed_cur_mark + 1; - ed->ed_cur_mark = ed->ed_clear_mark + 1; - - if (equiv_node(ctdp, mtdp, ed)) { - debug(3, "equiv_node matched %d %d\n", ctdp->t_id, mtdp->t_id); - ed->ed_tgt = mtdp; - /* matched. stop looking */ - return (-1); - } - - return (0); -} - -/*ARGSUSED1*/ -static int -map_td_tree_pre(tdesc_t *ctdp, tdesc_t **ctdpp, void *private) -{ - merge_cb_data_t *mcd = private; - - if (get_mapping(mcd->md_ta, ctdp->t_id) > 0) - return (0); - - return (1); -} - -/*ARGSUSED1*/ -static int -map_td_tree_post(tdesc_t *ctdp, tdesc_t **ctdpp, void *private) -{ - merge_cb_data_t *mcd = private; - equiv_data_t ed; - - ed.ed_ta = mcd->md_ta; - ed.ed_clear_mark = mcd->md_parent->td_curemark; - ed.ed_cur_mark = mcd->md_parent->td_curemark + 1; - ed.ed_node = ctdp; - ed.ed_selfuniquify = 0; - - debug(3, "map_td_tree_post on %d %s\n", ctdp->t_id, tdesc_name(ctdp)); - - if (hash_find_iter(mcd->md_parent->td_layouthash, ctdp, - equiv_cb, &ed) < 0) { - /* We found an equivalent node */ - if (ed.ed_tgt->t_type == FORWARD && ctdp->t_type != FORWARD) { - int id = mcd->md_tgt->td_nextid++; - - debug(3, "Creating new defn type %d\n", id); - add_mapping(mcd->md_ta, ctdp->t_id, id); - alist_add(mcd->md_fdida, (void *)(ulong_t)ed.ed_tgt, - (void *)(ulong_t)id); - hash_add(mcd->md_tdtba, ctdp); - } else - add_mapping(mcd->md_ta, ctdp->t_id, ed.ed_tgt->t_id); - - } else if (debug_level > 1 && hash_iter(mcd->md_parent->td_idhash, - equiv_cb, &ed) < 0) { - /* - * We didn't find an equivalent node by looking through the - * layout hash, but we somehow found it by performing an - * exhaustive search through the entire graph. This usually - * means that the "name" hash function is broken. - */ - aborterr("Second pass for %d (%s) == %d\n", ctdp->t_id, - tdesc_name(ctdp), ed.ed_tgt->t_id); - } else { - int id = mcd->md_tgt->td_nextid++; - - debug(3, "Creating new type %d\n", id); - add_mapping(mcd->md_ta, ctdp->t_id, id); - hash_add(mcd->md_tdtba, ctdp); - } - - mcd->md_parent->td_curemark = ed.ed_cur_mark + 1; - - return (1); -} - -/*ARGSUSED1*/ -static int -map_td_tree_self_post(tdesc_t *ctdp, tdesc_t **ctdpp, void *private) -{ - merge_cb_data_t *mcd = private; - equiv_data_t ed; - - ed.ed_ta = mcd->md_ta; - ed.ed_clear_mark = mcd->md_parent->td_curemark; - ed.ed_cur_mark = mcd->md_parent->td_curemark + 1; - ed.ed_node = ctdp; - ed.ed_selfuniquify = 1; - ed.ed_tgt = NULL; - - if (hash_find_iter(mcd->md_tdtba, ctdp, equiv_cb, &ed) < 0) { - debug(3, "Self check found %d in %d\n", ctdp->t_id, - ed.ed_tgt->t_id); - add_mapping(mcd->md_ta, ctdp->t_id, - get_mapping(mcd->md_ta, ed.ed_tgt->t_id)); - } else if (debug_level > 1 && hash_iter(mcd->md_tdtba, - equiv_cb, &ed) < 0) { - /* - * We didn't find an equivalent node using the quick way (going - * through the hash normally), but we did find it by iterating - * through the entire hash. This usually means that the hash - * function is broken. - */ - aborterr("Self-unique second pass for %d (%s) == %d\n", - ctdp->t_id, tdesc_name(ctdp), ed.ed_tgt->t_id); - } else { - int id = mcd->md_tgt->td_nextid++; - - debug(3, "Creating new type %d\n", id); - add_mapping(mcd->md_ta, ctdp->t_id, id); - hash_add(mcd->md_tdtba, ctdp); - } - - mcd->md_parent->td_curemark = ed.ed_cur_mark + 1; - - return (1); -} - -static tdtrav_cb_f map_pre[] = { - NULL, - map_td_tree_pre, /* intrinsic */ - map_td_tree_pre, /* pointer */ - map_td_tree_pre, /* array */ - map_td_tree_pre, /* function */ - map_td_tree_pre, /* struct */ - map_td_tree_pre, /* union */ - map_td_tree_pre, /* enum */ - map_td_tree_pre, /* forward */ - map_td_tree_pre, /* typedef */ - tdtrav_assert, /* typedef_unres */ - map_td_tree_pre, /* volatile */ - map_td_tree_pre, /* const */ - map_td_tree_pre /* restrict */ -}; - -static tdtrav_cb_f map_post[] = { - NULL, - map_td_tree_post, /* intrinsic */ - map_td_tree_post, /* pointer */ - map_td_tree_post, /* array */ - map_td_tree_post, /* function */ - map_td_tree_post, /* struct */ - map_td_tree_post, /* union */ - map_td_tree_post, /* enum */ - map_td_tree_post, /* forward */ - map_td_tree_post, /* typedef */ - tdtrav_assert, /* typedef_unres */ - map_td_tree_post, /* volatile */ - map_td_tree_post, /* const */ - map_td_tree_post /* restrict */ -}; - -static tdtrav_cb_f map_self_post[] = { - NULL, - map_td_tree_self_post, /* intrinsic */ - map_td_tree_self_post, /* pointer */ - map_td_tree_self_post, /* array */ - map_td_tree_self_post, /* function */ - map_td_tree_self_post, /* struct */ - map_td_tree_self_post, /* union */ - map_td_tree_self_post, /* enum */ - map_td_tree_self_post, /* forward */ - map_td_tree_self_post, /* typedef */ - tdtrav_assert, /* typedef_unres */ - map_td_tree_self_post, /* volatile */ - map_td_tree_self_post, /* const */ - map_td_tree_self_post /* restrict */ -}; - -/* - * Determining equivalence of iidesc_t nodes - */ - -typedef struct iifind_data { - iidesc_t *iif_template; - alist_t *iif_ta; - int iif_newidx; - int iif_refmerge; -} iifind_data_t; - -/* - * Check to see if this iidesc_t (node) - the current one on the list we're - * iterating through - matches the target one (iif->iif_template). Return -1 - * if it matches, to stop the iteration. - */ -static int -iidesc_match(void *data, void *arg) -{ - iidesc_t *node = data; - iifind_data_t *iif = arg; - int i; - - if (node->ii_type != iif->iif_template->ii_type || - !streq(node->ii_name, iif->iif_template->ii_name) || - node->ii_dtype->t_id != iif->iif_newidx) - return (0); - - if ((node->ii_type == II_SVAR || node->ii_type == II_SFUN) && - !streq(node->ii_owner, iif->iif_template->ii_owner)) - return (0); - - if (node->ii_nargs != iif->iif_template->ii_nargs) - return (0); - - for (i = 0; i < node->ii_nargs; i++) { - if (get_mapping(iif->iif_ta, - iif->iif_template->ii_args[i]->t_id) != - node->ii_args[i]->t_id) - return (0); - } - - if (iif->iif_refmerge) { - switch (iif->iif_template->ii_type) { - case II_GFUN: - case II_SFUN: - case II_GVAR: - case II_SVAR: - debug(3, "suppressing duping of %d %s from %s\n", - iif->iif_template->ii_type, - iif->iif_template->ii_name, - (iif->iif_template->ii_owner ? - iif->iif_template->ii_owner : "NULL")); - return (0); - case II_NOT: - case II_PSYM: - case II_SOU: - case II_TYPE: - break; - } - } - - return (-1); -} - -static int -merge_type_cb(void *data, void *arg) -{ - iidesc_t *sii = data; - merge_cb_data_t *mcd = arg; - iifind_data_t iif; - tdtrav_cb_f *post; - - post = (mcd->md_flags & MCD_F_SELFUNIQUIFY ? map_self_post : map_post); - - /* Map the tdesc nodes */ - (void) iitraverse(sii, &mcd->md_parent->td_curvgen, NULL, map_pre, post, - mcd); - - /* Map the iidesc nodes */ - iif.iif_template = sii; - iif.iif_ta = mcd->md_ta; - iif.iif_newidx = get_mapping(mcd->md_ta, sii->ii_dtype->t_id); - iif.iif_refmerge = (mcd->md_flags & MCD_F_REFMERGE); - - if (hash_match(mcd->md_parent->td_iihash, sii, iidesc_match, - &iif) == 1) - /* successfully mapped */ - return (1); - - debug(3, "tba %s (%d)\n", (sii->ii_name ? sii->ii_name : "(anon)"), - sii->ii_type); - - list_add(mcd->md_iitba, sii); - - return (0); -} - -static int -remap_node(tdesc_t **tgtp, tdesc_t *oldtgt, int selftid, tdesc_t *newself, - merge_cb_data_t *mcd) -{ - tdesc_t *tgt = NULL; - tdesc_t template; - int oldid = oldtgt->t_id; - - if (oldid == selftid) { - *tgtp = newself; - return (1); - } - - if ((template.t_id = get_mapping(mcd->md_ta, oldid)) == 0) - aborterr("failed to get mapping for tid %d\n", oldid); - - if (!hash_find(mcd->md_parent->td_idhash, (void *)&template, - (void *)&tgt) && (!(mcd->md_flags & MCD_F_REFMERGE) || - !hash_find(mcd->md_tgt->td_idhash, (void *)&template, - (void *)&tgt))) { - debug(3, "Remap couldn't find %d (from %d)\n", template.t_id, - oldid); - *tgtp = oldtgt; - list_add(mcd->md_tdtbr, tgtp); - return (0); - } - - *tgtp = tgt; - return (1); -} - -static tdesc_t * -conjure_template(tdesc_t *old, int newselfid) -{ - tdesc_t *new = xcalloc(sizeof (tdesc_t)); - - new->t_name = old->t_name ? xstrdup(old->t_name) : NULL; - new->t_type = old->t_type; - new->t_size = old->t_size; - new->t_id = newselfid; - new->t_flags = old->t_flags; - - return (new); -} - -/*ARGSUSED2*/ -static tdesc_t * -conjure_intrinsic(tdesc_t *old, int newselfid, merge_cb_data_t *mcd) -{ - tdesc_t *new = conjure_template(old, newselfid); - - new->t_intr = xmalloc(sizeof (intr_t)); - bcopy(old->t_intr, new->t_intr, sizeof (intr_t)); - - return (new); -} - -static tdesc_t * -conjure_plain(tdesc_t *old, int newselfid, merge_cb_data_t *mcd) -{ - tdesc_t *new = conjure_template(old, newselfid); - - (void) remap_node(&new->t_tdesc, old->t_tdesc, old->t_id, new, mcd); - - return (new); -} - -static tdesc_t * -conjure_function(tdesc_t *old, int newselfid, merge_cb_data_t *mcd) -{ - tdesc_t *new = conjure_template(old, newselfid); - fndef_t *nfn = xmalloc(sizeof (fndef_t)); - fndef_t *ofn = old->t_fndef; - int i; - - (void) remap_node(&nfn->fn_ret, ofn->fn_ret, old->t_id, new, mcd); - - nfn->fn_nargs = ofn->fn_nargs; - nfn->fn_vargs = ofn->fn_vargs; - - if (nfn->fn_nargs > 0) - nfn->fn_args = xcalloc(sizeof (tdesc_t *) * ofn->fn_nargs); - - for (i = 0; i < ofn->fn_nargs; i++) { - (void) remap_node(&nfn->fn_args[i], ofn->fn_args[i], old->t_id, - new, mcd); - } - - new->t_fndef = nfn; - - return (new); -} - -static tdesc_t * -conjure_array(tdesc_t *old, int newselfid, merge_cb_data_t *mcd) -{ - tdesc_t *new = conjure_template(old, newselfid); - ardef_t *nar = xmalloc(sizeof (ardef_t)); - ardef_t *oar = old->t_ardef; - - (void) remap_node(&nar->ad_contents, oar->ad_contents, old->t_id, new, - mcd); - (void) remap_node(&nar->ad_idxtype, oar->ad_idxtype, old->t_id, new, - mcd); - - nar->ad_nelems = oar->ad_nelems; - - new->t_ardef = nar; - - return (new); -} - -static tdesc_t * -conjure_su(tdesc_t *old, int newselfid, merge_cb_data_t *mcd) -{ - tdesc_t *new = conjure_template(old, newselfid); - mlist_t *omem, **nmemp; - - for (omem = old->t_members, nmemp = &new->t_members; - omem; omem = omem->ml_next, nmemp = &((*nmemp)->ml_next)) { - *nmemp = xmalloc(sizeof (mlist_t)); - (*nmemp)->ml_offset = omem->ml_offset; - (*nmemp)->ml_size = omem->ml_size; - (*nmemp)->ml_name = xstrdup(omem->ml_name); - (void) remap_node(&((*nmemp)->ml_type), omem->ml_type, - old->t_id, new, mcd); - } - *nmemp = NULL; - - return (new); -} - -/*ARGSUSED2*/ -static tdesc_t * -conjure_enum(tdesc_t *old, int newselfid, merge_cb_data_t *mcd) -{ - tdesc_t *new = conjure_template(old, newselfid); - elist_t *oel, **nelp; - - for (oel = old->t_emem, nelp = &new->t_emem; - oel; oel = oel->el_next, nelp = &((*nelp)->el_next)) { - *nelp = xmalloc(sizeof (elist_t)); - (*nelp)->el_name = xstrdup(oel->el_name); - (*nelp)->el_number = oel->el_number; - } - *nelp = NULL; - - return (new); -} - -/*ARGSUSED2*/ -static tdesc_t * -conjure_forward(tdesc_t *old, int newselfid, merge_cb_data_t *mcd) -{ - tdesc_t *new = conjure_template(old, newselfid); - - list_add(&mcd->md_tgt->td_fwdlist, new); - - return (new); -} - -/*ARGSUSED*/ -static tdesc_t * -conjure_assert(tdesc_t *old, int newselfid, merge_cb_data_t *mcd) -{ - assert(1 == 0); - return (NULL); -} - -static iidesc_t * -conjure_iidesc(iidesc_t *old, merge_cb_data_t *mcd) -{ - iidesc_t *new = iidesc_dup(old); - int i; - - (void) remap_node(&new->ii_dtype, old->ii_dtype, -1, NULL, mcd); - for (i = 0; i < new->ii_nargs; i++) { - (void) remap_node(&new->ii_args[i], old->ii_args[i], -1, NULL, - mcd); - } - - return (new); -} - -static int -fwd_redir(tdesc_t *fwd, tdesc_t **fwdp, void *private) -{ - alist_t *map = private; - tdesc_t *defn; - - if (!alist_find(map, (void *)fwd, (void **)&defn)) - return (0); - - debug(3, "Redirecting an edge to %s\n", tdesc_name(defn)); - - *fwdp = defn; - - return (1); -} - -static tdtrav_cb_f fwd_redir_cbs[] = { - NULL, - NULL, /* intrinsic */ - NULL, /* pointer */ - NULL, /* array */ - NULL, /* function */ - NULL, /* struct */ - NULL, /* union */ - NULL, /* enum */ - fwd_redir, /* forward */ - NULL, /* typedef */ - tdtrav_assert, /* typedef_unres */ - NULL, /* volatile */ - NULL, /* const */ - NULL /* restrict */ -}; - -typedef struct redir_mstr_data { - tdata_t *rmd_tgt; - alist_t *rmd_map; -} redir_mstr_data_t; - -static int -redir_mstr_fwd_cb(void *name, void *value, void *arg) -{ - tdesc_t *fwd = name; - int defnid = (int)value; - redir_mstr_data_t *rmd = arg; - tdesc_t template; - tdesc_t *defn; - - template.t_id = defnid; - - if (!hash_find(rmd->rmd_tgt->td_idhash, (void *)&template, - (void *)&defn)) { - aborterr("Couldn't unforward %d (%s)\n", defnid, - tdesc_name(defn)); - } - - debug(3, "Forward map: resolved %d to %s\n", defnid, tdesc_name(defn)); - - alist_add(rmd->rmd_map, (void *)fwd, (void *)defn); - - return (1); -} - -static void -redir_mstr_fwds(merge_cb_data_t *mcd) -{ - redir_mstr_data_t rmd; - alist_t *map = alist_new(NULL, NULL); - - rmd.rmd_tgt = mcd->md_tgt; - rmd.rmd_map = map; - - if (alist_iter(mcd->md_fdida, redir_mstr_fwd_cb, &rmd)) { - (void) iitraverse_hash(mcd->md_tgt->td_iihash, - &mcd->md_tgt->td_curvgen, fwd_redir_cbs, NULL, NULL, map); - } - - alist_free(map); -} - -static int -add_iitba_cb(void *data, void *private) -{ - merge_cb_data_t *mcd = private; - iidesc_t *tba = data; - iidesc_t *new; - iifind_data_t iif; - int newidx; - - newidx = get_mapping(mcd->md_ta, tba->ii_dtype->t_id); - assert(newidx != -1); - - (void) list_remove(mcd->md_iitba, data, NULL, NULL); - - iif.iif_template = tba; - iif.iif_ta = mcd->md_ta; - iif.iif_newidx = newidx; - iif.iif_refmerge = (mcd->md_flags & MCD_F_REFMERGE); - - if (hash_match(mcd->md_parent->td_iihash, tba, iidesc_match, - &iif) == 1) { - debug(3, "iidesc_t %s already exists\n", - (tba->ii_name ? tba->ii_name : "(anon)")); - return (1); - } - - new = conjure_iidesc(tba, mcd); - hash_add(mcd->md_tgt->td_iihash, new); - - return (1); -} - -static int -add_tdesc(tdesc_t *oldtdp, int newid, merge_cb_data_t *mcd) -{ - tdesc_t *newtdp; - tdesc_t template; - - template.t_id = newid; - assert(hash_find(mcd->md_parent->td_idhash, - (void *)&template, NULL) == 0); - - debug(3, "trying to conjure %d %s (%d) as %d\n", - oldtdp->t_type, tdesc_name(oldtdp), oldtdp->t_id, newid); - - if ((newtdp = tdesc_ops[oldtdp->t_type].conjure(oldtdp, newid, - mcd)) == NULL) - /* couldn't map everything */ - return (0); - - debug(3, "succeeded\n"); - - hash_add(mcd->md_tgt->td_idhash, newtdp); - hash_add(mcd->md_tgt->td_layouthash, newtdp); - - return (1); -} - -static int -add_tdtba_cb(void *data, void *arg) -{ - tdesc_t *tdp = data; - merge_cb_data_t *mcd = arg; - int newid; - int rc; - - newid = get_mapping(mcd->md_ta, tdp->t_id); - assert(newid != -1); - - if ((rc = add_tdesc(tdp, newid, mcd))) - hash_remove(mcd->md_tdtba, (void *)tdp); - - return (rc); -} - -static int -add_tdtbr_cb(void *data, void *arg) -{ - tdesc_t **tdpp = data; - merge_cb_data_t *mcd = arg; - - debug(3, "Remapping %s (%d)\n", tdesc_name(*tdpp), (*tdpp)->t_id); - - if (!remap_node(tdpp, *tdpp, -1, NULL, mcd)) - return (0); - - (void) list_remove(mcd->md_tdtbr, (void *)tdpp, NULL, NULL); - return (1); -} - -static void -merge_types(hash_t *src, merge_cb_data_t *mcd) -{ - list_t *iitba = NULL; - list_t *tdtbr = NULL; - int iirc, tdrc; - - mcd->md_iitba = &iitba; - mcd->md_tdtba = hash_new(TDATA_LAYOUT_HASH_SIZE, tdesc_layouthash, - tdesc_layoutcmp); - mcd->md_tdtbr = &tdtbr; - - (void) hash_iter(src, merge_type_cb, mcd); - - tdrc = hash_iter(mcd->md_tdtba, add_tdtba_cb, (void *)mcd); - debug(3, "add_tdtba_cb added %d items\n", tdrc); - - iirc = list_iter(*mcd->md_iitba, add_iitba_cb, (void *)mcd); - debug(3, "add_iitba_cb added %d items\n", iirc); - - assert(list_count(*mcd->md_iitba) == 0 && - hash_count(mcd->md_tdtba) == 0); - - tdrc = list_iter(*mcd->md_tdtbr, add_tdtbr_cb, (void *)mcd); - debug(3, "add_tdtbr_cb added %d items\n", tdrc); - - if (list_count(*mcd->md_tdtbr) != 0) - aborterr("Couldn't remap all nodes\n"); - - /* - * We now have an alist of master forwards and the ids of the new master - * definitions for those forwards in mcd->md_fdida. By this point, - * we're guaranteed that all of the master definitions referenced in - * fdida have been added to the master tree. We now traverse through - * the master tree, redirecting all edges inbound to forwards that have - * definitions to those definitions. - */ - if (mcd->md_parent == mcd->md_tgt) { - redir_mstr_fwds(mcd); - } -} - -void -merge_into_master(tdata_t *cur, tdata_t *mstr, tdata_t *tgt, int selfuniquify) -{ - merge_cb_data_t mcd; - - cur->td_ref++; - mstr->td_ref++; - if (tgt) - tgt->td_ref++; - - assert(cur->td_ref == 1 && mstr->td_ref == 1 && - (tgt == NULL || tgt->td_ref == 1)); - - mcd.md_parent = mstr; - mcd.md_tgt = (tgt ? tgt : mstr); - mcd.md_ta = alist_new(NULL, NULL); - mcd.md_fdida = alist_new(NULL, NULL); - mcd.md_flags = 0; - - if (selfuniquify) - mcd.md_flags |= MCD_F_SELFUNIQUIFY; - if (tgt) - mcd.md_flags |= MCD_F_REFMERGE; - - mstr->td_curvgen = MAX(mstr->td_curvgen, cur->td_curvgen); - mstr->td_curemark = MAX(mstr->td_curemark, cur->td_curemark); - - merge_types(cur->td_iihash, &mcd); - - if (debug_level >= 3) { - debug(3, "Type association stats\n"); - alist_stats(mcd.md_ta, 0); - debug(3, "Layout hash stats\n"); - hash_stats(mcd.md_tgt->td_layouthash, 1); - } - - alist_free(mcd.md_fdida); - alist_free(mcd.md_ta); - - cur->td_ref--; - mstr->td_ref--; - if (tgt) - tgt->td_ref--; -} - -tdesc_ops_t tdesc_ops[] = { - { "ERROR! BAD tdesc TYPE", NULL, NULL }, - { "intrinsic", equiv_intrinsic, conjure_intrinsic }, - { "pointer", equiv_plain, conjure_plain }, - { "array", equiv_array, conjure_array }, - { "function", equiv_function, conjure_function }, - { "struct", equiv_su, conjure_su }, - { "union", equiv_su, conjure_su }, - { "enum", equiv_enum, conjure_enum }, - { "forward", NULL, conjure_forward }, - { "typedef", equiv_plain, conjure_plain }, - { "typedef_unres", equiv_assert, conjure_assert }, - { "volatile", equiv_plain, conjure_plain }, - { "const", equiv_plain, conjure_plain }, - { "restrict", equiv_plain, conjure_plain } -}; diff --git a/usr/src/tools/ctf/cvt/output.c b/usr/src/tools/ctf/cvt/output.c deleted file mode 100644 index f23aa7394c..0000000000 --- a/usr/src/tools/ctf/cvt/output.c +++ /dev/null @@ -1,713 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * Routines for preparing tdata trees for conversion into CTF data, and - * for placing the resulting data into an output file. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <strings.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <libelf.h> -#include <gelf.h> -#include <unistd.h> - -#include "ctftools.h" -#include "list.h" -#include "memory.h" -#include "traverse.h" -#include "symbol.h" - -typedef struct iidesc_match { - int iim_fuzzy; - iidesc_t *iim_ret; - char *iim_name; - char *iim_file; - uchar_t iim_bind; -} iidesc_match_t; - -static int -burst_iitypes(void *data, void *arg) -{ - iidesc_t *ii = data; - iiburst_t *iiburst = arg; - - switch (ii->ii_type) { - case II_GFUN: - case II_SFUN: - case II_GVAR: - case II_SVAR: - if (!(ii->ii_flags & IIDESC_F_USED)) - return (0); - break; - default: - break; - } - - ii->ii_dtype->t_flags |= TDESC_F_ISROOT; - (void) iitraverse_td(ii, iiburst->iib_tdtd); - return (1); -} - -/*ARGSUSED1*/ -static int -save_type_by_id(tdesc_t *tdp, tdesc_t **tdpp, void *private) -{ - iiburst_t *iiburst = private; - - /* - * Doing this on every node is horribly inefficient, but given that - * we may be suppressing some types, we can't trust nextid in the - * tdata_t. - */ - if (tdp->t_id > iiburst->iib_maxtypeid) - iiburst->iib_maxtypeid = tdp->t_id; - - slist_add(&iiburst->iib_types, tdp, tdesc_idcmp); - - return (1); -} - -static tdtrav_cb_f burst_types_cbs[] = { - NULL, - save_type_by_id, /* intrinsic */ - save_type_by_id, /* pointer */ - save_type_by_id, /* array */ - save_type_by_id, /* function */ - save_type_by_id, /* struct */ - save_type_by_id, /* union */ - save_type_by_id, /* enum */ - save_type_by_id, /* forward */ - save_type_by_id, /* typedef */ - tdtrav_assert, /* typedef_unres */ - save_type_by_id, /* volatile */ - save_type_by_id, /* const */ - save_type_by_id /* restrict */ -}; - - -static iiburst_t * -iiburst_new(tdata_t *td, int max) -{ - iiburst_t *iiburst = xcalloc(sizeof (iiburst_t)); - iiburst->iib_td = td; - iiburst->iib_funcs = xcalloc(sizeof (iidesc_t *) * max); - iiburst->iib_nfuncs = 0; - iiburst->iib_objts = xcalloc(sizeof (iidesc_t *) * max); - iiburst->iib_nobjts = 0; - return (iiburst); -} - -static void -iiburst_types(iiburst_t *iiburst) -{ - tdtrav_data_t tdtd; - - tdtrav_init(&tdtd, &iiburst->iib_td->td_curvgen, NULL, burst_types_cbs, - NULL, (void *)iiburst); - - iiburst->iib_tdtd = &tdtd; - - (void) hash_iter(iiburst->iib_td->td_iihash, burst_iitypes, iiburst); -} - -static void -iiburst_free(iiburst_t *iiburst) -{ - free(iiburst->iib_funcs); - free(iiburst->iib_objts); - list_free(iiburst->iib_types, NULL, NULL); - free(iiburst); -} - -/* - * See if this iidesc matches the ELF symbol data we pass in. - * - * A fuzzy match is where we have a local symbol matching the name of a - * global type description. This is common when a mapfile is used for a - * DSO, but we don't accept it by default. - * - * A weak fuzzy match is when a weak symbol was resolved and matched to - * a global type description. - */ -static int -matching_iidesc(iidesc_t *iidesc, iidesc_match_t *match) -{ - if (streq(iidesc->ii_name, match->iim_name) == 0) - return (0); - - switch (iidesc->ii_type) { - case II_GFUN: - case II_GVAR: - if (match->iim_bind == STB_GLOBAL) { - match->iim_ret = iidesc; - return (-1); - } else if (match->iim_fuzzy && match->iim_ret == NULL) { - match->iim_ret = iidesc; - /* continue to look for strong match */ - return (0); - } - break; - case II_SFUN: - case II_SVAR: - if (match->iim_bind == STB_LOCAL && - match->iim_file != NULL && - streq(iidesc->ii_owner, match->iim_file)) { - match->iim_ret = iidesc; - return (-1); - } - break; - } - return (0); -} - -static iidesc_t * -find_iidesc(tdata_t *td, iidesc_match_t *match) -{ - match->iim_ret = NULL; - iter_iidescs_by_name(td, match->iim_name, - (int (*)())matching_iidesc, match); - return (match->iim_ret); -} - -/* - * If we have a weak symbol, attempt to find the strong symbol it will - * resolve to. Note: the code where this actually happens is in - * sym_process() in cmd/sgs/libld/common/syms.c - * - * Finding the matching symbol is unfortunately not trivial. For a - * symbol to be a candidate, it must: - * - * - have the same type (function, object) - * - have the same value (address) - * - have the same size - * - not be another weak symbol - * - belong to the same section (checked via section index) - * - * If such a candidate is global, then we assume we've found it. The - * linker generates the symbol table such that the curfile might be - * incorrect; this is OK for global symbols, since find_iidesc() doesn't - * need to check for the source file for the symbol. - * - * We might have found a strong local symbol, where the curfile is - * accurate and matches that of the weak symbol. We assume this is a - * reasonable match. - * - * If we've got a local symbol with a non-matching curfile, there are - * two possibilities. Either this is a completely different symbol, or - * it's a once-global symbol that was scoped to local via a mapfile. In - * the latter case, curfile is likely inaccurate since the linker does - * not preserve the needed curfile in the order of the symbol table (see - * the comments about locally scoped symbols in libld's update_osym()). - * As we can't tell this case from the former one, we use this symbol - * iff no other matching symbol is found. - * - * What we really need here is a SUNW section containing weak<->strong - * mappings that we can consume. - */ -static int -check_for_weak(GElf_Sym *weak, char const *weakfile, - Elf_Data *data, int nent, Elf_Data *strdata, - GElf_Sym *retsym, char **curfilep) -{ - char *curfile = NULL; - char *tmpfile; - GElf_Sym tmpsym; - int candidate = 0; - int i; - - if (GELF_ST_BIND(weak->st_info) != STB_WEAK) - return (0); - - for (i = 0; i < nent; i++) { - GElf_Sym sym; - uchar_t type; - - if (gelf_getsym(data, i, &sym) == NULL) - continue; - - type = GELF_ST_TYPE(sym.st_info); - - if (type == STT_FILE) - curfile = (char *)strdata->d_buf + sym.st_name; - - if (GELF_ST_TYPE(weak->st_info) != type || - weak->st_value != sym.st_value) - continue; - - if (weak->st_size != sym.st_size) - continue; - - if (GELF_ST_BIND(sym.st_info) == STB_WEAK) - continue; - - if (sym.st_shndx != weak->st_shndx) - continue; - - if (GELF_ST_BIND(sym.st_info) == STB_LOCAL && - (curfile == NULL || weakfile == NULL || - strcmp(curfile, weakfile) != 0)) { - candidate = 1; - tmpfile = curfile; - tmpsym = sym; - continue; - } - - *curfilep = curfile; - *retsym = sym; - return (1); - } - - if (candidate) { - *curfilep = tmpfile; - *retsym = tmpsym; - return (1); - } - - return (0); -} - -/* - * When we've found the underlying symbol's type description - * for a weak symbol, we need to copy it and rename it to match - * the weak symbol. We also need to add it to the td so it's - * handled along with the others later. - */ -static iidesc_t * -copy_from_strong(tdata_t *td, GElf_Sym *sym, iidesc_t *strongdesc, - const char *weakname, const char *weakfile) -{ - iidesc_t *new = iidesc_dup_rename(strongdesc, weakname, weakfile); - uchar_t type = GELF_ST_TYPE(sym->st_info); - - switch (type) { - case STT_OBJECT: - new->ii_type = II_GVAR; - break; - case STT_FUNC: - new->ii_type = II_GFUN; - break; - } - - hash_add(td->td_iihash, new); - - return (new); -} - -/* - * Process the symbol table of the output file, associating each symbol - * with a type description if possible, and sorting them into functions - * and data, maintaining symbol table order. - */ -static iiburst_t * -sort_iidescs(Elf *elf, const char *file, tdata_t *td, int fuzzymatch, - int dynsym) -{ - iiburst_t *iiburst; - Elf_Scn *scn; - GElf_Shdr shdr; - Elf_Data *data, *strdata; - int i, stidx; - int nent; - iidesc_match_t match; - - match.iim_fuzzy = fuzzymatch; - match.iim_file = NULL; - - if ((stidx = findelfsecidx(elf, file, - dynsym ? ".dynsym" : ".symtab")) < 0) - terminate("%s: Can't open symbol table\n", file); - scn = elf_getscn(elf, stidx); - data = elf_getdata(scn, NULL); - gelf_getshdr(scn, &shdr); - nent = shdr.sh_size / shdr.sh_entsize; - - scn = elf_getscn(elf, shdr.sh_link); - strdata = elf_getdata(scn, NULL); - - iiburst = iiburst_new(td, nent); - - for (i = 0; i < nent; i++) { - GElf_Sym sym; - iidesc_t **tolist; - GElf_Sym ssym; - iidesc_match_t smatch; - int *curr; - iidesc_t *iidesc; - - if (gelf_getsym(data, i, &sym) == NULL) - elfterminate(file, "Couldn't read symbol %d", i); - - match.iim_name = (char *)strdata->d_buf + sym.st_name; - match.iim_bind = GELF_ST_BIND(sym.st_info); - - switch (GELF_ST_TYPE(sym.st_info)) { - case STT_FILE: - match.iim_file = match.iim_name; - continue; - case STT_OBJECT: - tolist = iiburst->iib_objts; - curr = &iiburst->iib_nobjts; - break; - case STT_FUNC: - tolist = iiburst->iib_funcs; - curr = &iiburst->iib_nfuncs; - break; - default: - continue; - } - - if (ignore_symbol(&sym, match.iim_name)) - continue; - - iidesc = find_iidesc(td, &match); - - if (iidesc != NULL) { - tolist[*curr] = iidesc; - iidesc->ii_flags |= IIDESC_F_USED; - (*curr)++; - continue; - } - - if (!check_for_weak(&sym, match.iim_file, data, nent, strdata, - &ssym, &smatch.iim_file)) { - (*curr)++; - continue; - } - - smatch.iim_fuzzy = fuzzymatch; - smatch.iim_name = (char *)strdata->d_buf + ssym.st_name; - smatch.iim_bind = GELF_ST_BIND(ssym.st_info); - - debug(3, "Weak symbol %s resolved to %s\n", match.iim_name, - smatch.iim_name); - - iidesc = find_iidesc(td, &smatch); - - if (iidesc != NULL) { - tolist[*curr] = copy_from_strong(td, &sym, - iidesc, match.iim_name, match.iim_file); - tolist[*curr]->ii_flags |= IIDESC_F_USED; - } - - (*curr)++; - } - - /* - * Stabs are generated for every function declared in a given C source - * file. When converting an object file, we may encounter a stab that - * has no symbol table entry because the optimizer has decided to omit - * that item (for example, an unreferenced static function). We may - * see iidescs that do not have an associated symtab entry, and so - * we do not write records for those functions into the CTF data. - * All others get marked as a root by this function. - */ - iiburst_types(iiburst); - - /* - * By not adding some of the functions and/or objects, we may have - * caused some types that were referenced solely by those - * functions/objects to be suppressed. This could cause a label, - * generated prior to the evisceration, to be incorrect. Find the - * highest type index, and change the label indicies to be no higher - * than this value. - */ - tdata_label_newmax(td, iiburst->iib_maxtypeid); - - return (iiburst); -} - -static void -write_file(Elf *src, const char *srcname, Elf *dst, const char *dstname, - caddr_t ctfdata, size_t ctfsize, int flags) -{ - GElf_Ehdr sehdr, dehdr; - Elf_Scn *sscn, *dscn; - Elf_Data *sdata, *ddata; - GElf_Shdr shdr; - GElf_Word symtab_type; - int symtab_idx = -1; - off_t new_offset = 0; - off_t ctfnameoff = 0; - int dynsym = (flags & CTF_USE_DYNSYM); - int *secxlate; - int srcidx, dstidx; - int curnmoff = 0; - int changing = 0; - int pad; - int i; - - if (gelf_newehdr(dst, gelf_getclass(src)) == 0) - elfterminate(dstname, "Cannot copy ehdr to temp file"); - gelf_getehdr(src, &sehdr); - memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr)); - gelf_update_ehdr(dst, &dehdr); - - symtab_type = dynsym ? SHT_DYNSYM : SHT_SYMTAB; - - /* - * Neither the existing stab sections nor the SUNW_ctf sections (new or - * existing) are SHF_ALLOC'd, so they won't be in areas referenced by - * program headers. As such, we can just blindly copy the program - * headers from the existing file to the new file. - */ - if (sehdr.e_phnum != 0) { - (void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT); - if (gelf_newphdr(dst, sehdr.e_phnum) == 0) - elfterminate(dstname, "Cannot make phdrs in temp file"); - - for (i = 0; i < sehdr.e_phnum; i++) { - GElf_Phdr phdr; - - gelf_getphdr(src, i, &phdr); - gelf_update_phdr(dst, i, &phdr); - } - } - - secxlate = xmalloc(sizeof (int) * sehdr.e_shnum); - for (srcidx = dstidx = 0; srcidx < sehdr.e_shnum; srcidx++) { - Elf_Scn *scn = elf_getscn(src, srcidx); - GElf_Shdr shdr; - char *sname; - - gelf_getshdr(scn, &shdr); - sname = elf_strptr(src, sehdr.e_shstrndx, shdr.sh_name); - if (sname == NULL) { - elfterminate(srcname, "Can't find string at %u", - shdr.sh_name); - } - - if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) { - secxlate[srcidx] = -1; - } else if (dynsym && shdr.sh_type == SHT_SYMTAB) { - /* - * If we're building CTF against the dynsym, - * we'll rip out the symtab so debuggers aren't - * confused. - */ - secxlate[srcidx] = -1; - } else { - secxlate[srcidx] = dstidx++; - curnmoff += strlen(sname) + 1; - } - - new_offset = (off_t)dehdr.e_phoff; - } - - for (srcidx = 1; srcidx < sehdr.e_shnum; srcidx++) { - char *sname; - - sscn = elf_getscn(src, srcidx); - gelf_getshdr(sscn, &shdr); - - if (secxlate[srcidx] == -1) { - changing = 1; - continue; - } - - dscn = elf_newscn(dst); - - /* - * If this file has program headers, we need to explicitly lay - * out sections. If none of the sections prior to this one have - * been removed, then we can just use the existing location. If - * one or more sections have been changed, then we need to - * adjust this one to avoid holes. - */ - if (changing && sehdr.e_phnum != 0) { - pad = new_offset % shdr.sh_addralign; - - if (pad) - new_offset += shdr.sh_addralign - pad; - shdr.sh_offset = new_offset; - } - - shdr.sh_link = secxlate[shdr.sh_link]; - - if (shdr.sh_type == SHT_REL || shdr.sh_type == SHT_RELA) - shdr.sh_info = secxlate[shdr.sh_info]; - - sname = elf_strptr(src, sehdr.e_shstrndx, shdr.sh_name); - if (sname == NULL) { - elfterminate(srcname, "Can't find string at %u", - shdr.sh_name); - } - if ((sdata = elf_getdata(sscn, NULL)) == NULL) - elfterminate(srcname, "Cannot get sect %s data", sname); - if ((ddata = elf_newdata(dscn)) == NULL) - elfterminate(dstname, "Can't make sect %s data", sname); - bcopy(sdata, ddata, sizeof (Elf_Data)); - - if (srcidx == sehdr.e_shstrndx) { - char seclen = strlen(CTF_ELF_SCN_NAME); - - ddata->d_buf = xmalloc(ddata->d_size + shdr.sh_size + - seclen + 1); - bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size); - strcpy((caddr_t)ddata->d_buf + shdr.sh_size, - CTF_ELF_SCN_NAME); - ctfnameoff = (off_t)shdr.sh_size; - shdr.sh_size += seclen + 1; - ddata->d_size += seclen + 1; - - if (sehdr.e_phnum != 0) - changing = 1; - } - - if (shdr.sh_type == symtab_type && shdr.sh_entsize != 0) { - int nsym = shdr.sh_size / shdr.sh_entsize; - - symtab_idx = secxlate[srcidx]; - - ddata->d_buf = xmalloc(shdr.sh_size); - bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size); - - for (i = 0; i < nsym; i++) { - GElf_Sym sym; - short newscn; - - (void) gelf_getsym(ddata, i, &sym); - - if (sym.st_shndx >= SHN_LORESERVE) - continue; - - if ((newscn = secxlate[sym.st_shndx]) != - sym.st_shndx) { - sym.st_shndx = - (newscn == -1 ? 1 : newscn); - - gelf_update_sym(ddata, i, &sym); - } - } - } - - if (gelf_update_shdr(dscn, &shdr) == 0) - elfterminate(dstname, "Cannot update sect %s", sname); - - new_offset = (off_t)shdr.sh_offset; - if (shdr.sh_type != SHT_NOBITS) - new_offset += shdr.sh_size; - } - - if (symtab_idx == -1) { - terminate("%s: Cannot find %s section\n", srcname, - dynsym ? "SHT_DYNSYM" : "SHT_SYMTAB"); - } - - /* Add the ctf section */ - dscn = elf_newscn(dst); - gelf_getshdr(dscn, &shdr); - shdr.sh_name = ctfnameoff; - shdr.sh_type = SHT_PROGBITS; - shdr.sh_size = ctfsize; - shdr.sh_link = symtab_idx; - shdr.sh_addralign = 4; - if (changing && sehdr.e_phnum != 0) { - pad = new_offset % shdr.sh_addralign; - - if (pad) - new_offset += shdr.sh_addralign - pad; - - shdr.sh_offset = new_offset; - new_offset += shdr.sh_size; - } - - ddata = elf_newdata(dscn); - ddata->d_buf = ctfdata; - ddata->d_size = ctfsize; - ddata->d_align = shdr.sh_addralign; - - gelf_update_shdr(dscn, &shdr); - - /* update the section header location */ - if (sehdr.e_phnum != 0) { - size_t align = gelf_fsize(dst, ELF_T_ADDR, 1, EV_CURRENT); - size_t r = new_offset % align; - - if (r) - new_offset += align - r; - - dehdr.e_shoff = new_offset; - } - - /* commit to disk */ - dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx]; - gelf_update_ehdr(dst, &dehdr); - if (elf_update(dst, ELF_C_WRITE) < 0) - elfterminate(dstname, "Cannot finalize temp file"); - - free(secxlate); -} - -static caddr_t -make_ctf_data(tdata_t *td, Elf *elf, const char *file, size_t *lenp, int flags) -{ - iiburst_t *iiburst; - caddr_t data; - - iiburst = sort_iidescs(elf, file, td, flags & CTF_FUZZY_MATCH, - flags & CTF_USE_DYNSYM); - data = ctf_gen(iiburst, lenp, flags & CTF_COMPRESS); - - iiburst_free(iiburst); - - return (data); -} - -void -write_ctf(tdata_t *td, const char *curname, const char *newname, int flags) -{ - struct stat st; - Elf *elf = NULL; - Elf *telf = NULL; - caddr_t data; - size_t len; - int fd = -1; - int tfd = -1; - - (void) elf_version(EV_CURRENT); - if ((fd = open(curname, O_RDONLY)) < 0 || fstat(fd, &st) < 0) - terminate("%s: Cannot open for re-reading", curname); - if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) - elfterminate(curname, "Cannot re-read"); - - if ((tfd = open(newname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) - terminate("Cannot open temp file %s for writing", newname); - if ((telf = elf_begin(tfd, ELF_C_WRITE, NULL)) == NULL) - elfterminate(curname, "Cannot write"); - - data = make_ctf_data(td, elf, curname, &len, flags); - write_file(elf, curname, telf, newname, data, len, flags); - free(data); - - elf_end(telf); - elf_end(elf); - (void) close(fd); - (void) close(tfd); -} diff --git a/usr/src/tools/ctf/cvt/sparc/Makefile b/usr/src/tools/ctf/cvt/sparc/Makefile deleted file mode 100644 index 999f6c9af8..0000000000 --- a/usr/src/tools/ctf/cvt/sparc/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -include ../Makefile.com -include ../Makefile.targ diff --git a/usr/src/tools/ctf/cvt/st_parse.c b/usr/src/tools/ctf/cvt/st_parse.c deleted file mode 100644 index 37e7756cdf..0000000000 --- a/usr/src/tools/ctf/cvt/st_parse.c +++ /dev/null @@ -1,1214 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. - */ - -/* - * Copyright (c) 2018, Joyent, Inc. - */ - -/* - * This file is a sewer. - */ - -#include <limits.h> -#include <stdarg.h> -#include <stdio.h> -#include <assert.h> -#include <strings.h> -#include <setjmp.h> -#include <ctype.h> -#include <uts/common/sys/ctf.h> - -#include "ctftools.h" -#include "memory.h" -#include "list.h" - -#define HASH(NUM) ((int)(NUM & (BUCKETS - 1))) -#define BUCKETS 128 - -#define TYPEPAIRMULT 10000 -#define MAKETYPEID(file, num) ((file) * TYPEPAIRMULT + num) -#define TYPEFILE(tid) ((tid) / TYPEPAIRMULT) -#define TYPENUM(tid) ((tid) % TYPEPAIRMULT) - -#define expected(a, b, c) _expected(a, b, c, __LINE__) - -static int faketypenumber = 100000000; - -static tdesc_t *hash_table[BUCKETS]; -static tdesc_t *name_table[BUCKETS]; - -list_t *typedbitfldmems; - -static void reset(void); -static jmp_buf resetbuf; - -static char *soudef(char *cp, stabtype_t type, tdesc_t **rtdp); -static void enumdef(char *cp, tdesc_t **rtdp); -static int compute_sum(const char *w); - -static char *number(char *cp, int *n); -static char *name(char *cp, char **w); -static char *id(char *cp, int *h); -static char *whitesp(char *cp); -static void addhash(tdesc_t *tdp, int num); -static int tagadd(char *w, int h, tdesc_t *tdp); -static char *tdefdecl(char *cp, int h, tdesc_t **rtdp); -static char *intrinsic(char *cp, tdesc_t **rtdp); -static char *arraydef(char *cp, tdesc_t **rtdp); - -extern int debug_level; -int debug_parse = DEBUG_PARSE; - -/*PRINTFLIKE3*/ -static void -parse_debug(int level, char *cp, char *fmt, ...) -{ - va_list ap; - char buf[1024]; - char tmp[32]; - int i; - - if (level > debug_level || !debug_parse) - return; - - if (cp != NULL) { - for (i = 0; i < 30; i++) { - if (cp[i] == '\0') - break; - if (!iscntrl(cp[i])) - tmp[i] = cp[i]; - } - tmp[i] = '\0'; - (void) snprintf(buf, sizeof (buf), "%s [cp='%s']\n", fmt, tmp); - } else { - strcpy(buf, fmt); - strcat(buf, "\n"); - } - - va_start(ap, fmt); - vadebug(level, buf, ap); - va_end(ap); -} - -/* Report unexpected syntax in stabs. */ -static void -_expected( - char *who, /* what function, or part thereof, is reporting */ - char *what, /* what was expected */ - char *where, /* where we were in the line of input */ - int line) -{ - fprintf(stderr, "%s, expecting \"%s\" at \"%s\"\n", who, what, where); - fprintf(stderr, "code line: %d, file %s\n", line, - (curhdr ? curhdr : "NO FILE")); - reset(); -} - -/*ARGSUSED*/ -void -parse_init(tdata_t *td) -{ - int i; - - for (i = 0; i < BUCKETS; i++) { - hash_table[i] = NULL; - name_table[i] = NULL; - } - - if (typedbitfldmems != NULL) { - list_free(typedbitfldmems, NULL, NULL); - typedbitfldmems = NULL; - } -} - -void -parse_finish(tdata_t *td) -{ - td->td_nextid = ++faketypenumber; -} - -static tdesc_t * -unres_new(int tid) -{ - tdesc_t *tdp; - - tdp = xcalloc(sizeof (*tdp)); - tdp->t_type = TYPEDEF_UNRES; - tdp->t_id = tid; - - return (tdp); -} - -char * -read_tid(char *cp, tdesc_t **tdpp) -{ - tdesc_t *tdp; - int tid; - - cp = id(cp, &tid); - - assert(tid != 0); - - if (*cp == '=') { - if (!(cp = tdefdecl(cp + 1, tid, &tdp))) - return (NULL); - if (tdp->t_id && tdp->t_id != tid) { - tdesc_t *ntdp = xcalloc(sizeof (*ntdp)); - - ntdp->t_type = TYPEDEF; - ntdp->t_tdesc = tdp; - tdp = ntdp; - } - addhash(tdp, tid); - } else if ((tdp = lookup(tid)) == NULL) - tdp = unres_new(tid); - - *tdpp = tdp; - return (cp); -} - -static iitype_t -parse_fun(char *cp, iidesc_t *ii) -{ - iitype_t iitype; - tdesc_t *tdp; - tdesc_t **args = NULL; - int nargs = 0; - int va = 0; - - /* - * name:P prototype - * name:F global function - * name:f static function - */ - switch (*cp++) { - case 'P': - iitype = II_NOT; /* not interesting */ - break; - - case 'F': - iitype = II_GFUN; - break; - - case 'f': - iitype = II_SFUN; - break; - - default: - expected("parse_nfun", "[PfF]", cp - 1); - } - - if (!(cp = read_tid(cp, &tdp))) - return (-1); - - if (*cp) - args = xmalloc(sizeof (tdesc_t *) * FUNCARG_DEF); - - while (*cp && *++cp) { - if (*cp == '0') { - va = 1; - continue; - } - - nargs++; - if (nargs > FUNCARG_DEF) - args = xrealloc(args, sizeof (tdesc_t *) * nargs); - if (!(cp = read_tid(cp, &args[nargs - 1]))) - return (-1); - } - - ii->ii_type = iitype; - ii->ii_dtype = tdp; - ii->ii_nargs = nargs; - ii->ii_args = args; - ii->ii_vargs = va; - - return (iitype); -} - -static iitype_t -parse_sym(char *cp, iidesc_t *ii) -{ - tdesc_t *tdp; - iitype_t iitype; - - /* - * name:G global variable - * name:S static variable - */ - switch (*cp++) { - case 'G': - iitype = II_GVAR; - break; - case 'S': - iitype = II_SVAR; - break; - case 'p': - iitype = II_PSYM; - break; - case '(': - cp--; - /*FALLTHROUGH*/ - case 'r': - case 'V': - iitype = II_NOT; /* not interesting */ - break; - default: - expected("parse_sym", "[GprSV(]", cp - 1); - } - - if (!(cp = read_tid(cp, &tdp))) - return (-1); - - ii->ii_type = iitype; - ii->ii_dtype = tdp; - - return (iitype); -} - -static iitype_t -parse_type(char *cp, iidesc_t *ii) -{ - tdesc_t *tdp, *ntdp; - int tid; - - if (*cp++ != 't') - expected("parse_type", "t (type)", cp - 1); - - cp = id(cp, &tid); - if ((tdp = lookup(tid)) == NULL) { - if (*cp++ != '=') - expected("parse_type", "= (definition)", cp - 1); - - (void) tdefdecl(cp, tid, &tdp); - - if (tdp->t_id == tid) { - assert(tdp->t_type != TYPEDEF); - assert(!lookup(tdp->t_id)); - - if (!streq(tdp->t_name, ii->ii_name)) { - ntdp = xcalloc(sizeof (*ntdp)); - ntdp->t_name = xstrdup(ii->ii_name); - ntdp->t_type = TYPEDEF; - ntdp->t_tdesc = tdp; - tdp->t_id = faketypenumber++; - tdp = ntdp; - } - } else if (tdp->t_id == 0) { - assert(tdp->t_type == FORWARD || - tdp->t_type == INTRINSIC); - - if (tdp->t_name && !streq(tdp->t_name, ii->ii_name)) { - ntdp = xcalloc(sizeof (*ntdp)); - ntdp->t_name = xstrdup(ii->ii_name); - ntdp->t_type = TYPEDEF; - ntdp->t_tdesc = tdp; - tdp->t_id = faketypenumber++; - tdp = ntdp; - } - } else if (tdp->t_id != tid) { - ntdp = xcalloc(sizeof (*ntdp)); - ntdp->t_name = xstrdup(ii->ii_name); - ntdp->t_type = TYPEDEF; - ntdp->t_tdesc = tdp; - tdp = ntdp; - } - - if (tagadd(ii->ii_name, tid, tdp) < 0) - return (-1); - } - - ii->ii_type = II_TYPE; - ii->ii_dtype = tdp; - return (II_TYPE); -} - -static iitype_t -parse_sou(char *cp, iidesc_t *idp) -{ - tdesc_t *rtdp; - int tid; - - if (*cp++ != 'T') - expected("parse_sou", "T (sou)", cp - 1); - - cp = id(cp, &tid); - if (*cp++ != '=') - expected("parse_sou", "= (definition)", cp - 1); - - parse_debug(1, NULL, "parse_sou: declaring '%s'", idp->ii_name ? - idp->ii_name : "(anon)"); - if ((rtdp = lookup(tid)) != NULL) { - if (idp->ii_name != NULL) { - if (rtdp->t_name != NULL && - strcmp(rtdp->t_name, idp->ii_name) != 0) { - tdesc_t *tdp; - - tdp = xcalloc(sizeof (*tdp)); - tdp->t_name = xstrdup(idp->ii_name); - tdp->t_type = TYPEDEF; - tdp->t_tdesc = rtdp; - addhash(tdp, tid); /* for *(x,y) types */ - parse_debug(3, NULL, " %s defined as %s(%d)", - idp->ii_name, tdesc_name(rtdp), tid); - } else if (rtdp->t_name == NULL) { - rtdp->t_name = xstrdup(idp->ii_name); - addhash(rtdp, tid); - } - } - } else { - rtdp = xcalloc(sizeof (*rtdp)); - rtdp->t_name = idp->ii_name ? xstrdup(idp->ii_name) : NULL; - addhash(rtdp, tid); - } - - switch (*cp++) { - case 's': - (void) soudef(cp, STRUCT, &rtdp); - break; - case 'u': - (void) soudef(cp, UNION, &rtdp); - break; - case 'e': - enumdef(cp, &rtdp); - break; - default: - expected("parse_sou", "<tag type s/u/e>", cp - 1); - break; - } - - idp->ii_type = II_SOU; - idp->ii_dtype = rtdp; - return (II_SOU); -} - -int -parse_stab(stab_t *stab, char *cp, iidesc_t **iidescp) -{ - iidesc_t *ii = NULL; - iitype_t (*parse)(char *, iidesc_t *); - int rc; - - /* - * set up for reset() - */ - if (setjmp(resetbuf)) - return (-1); - - cp = whitesp(cp); - ii = iidesc_new(NULL); - cp = name(cp, &ii->ii_name); - - switch (stab->n_type) { - case N_FUN: - parse = parse_fun; - break; - - case N_LSYM: - if (*cp == 't') - parse = parse_type; - else if (*cp == 'T') - parse = parse_sou; - else - parse = parse_sym; - break; - - case N_GSYM: - case N_LCSYM: - case N_PSYM: - case N_ROSYM: - case N_RSYM: - case N_STSYM: - parse = parse_sym; - break; - default: - parse_debug(1, cp, "Unknown stab type %#x", stab->n_type); - bzero(&resetbuf, sizeof (resetbuf)); - return (-1); - } - - rc = parse(cp, ii); - bzero(&resetbuf, sizeof (resetbuf)); - - if (rc < 0 || ii->ii_type == II_NOT) { - iidesc_free(ii); - return (rc); - } - - *iidescp = ii; - - return (1); -} - -/* - * Check if we have this node in the hash table already - */ -tdesc_t * -lookup(int h) -{ - int bucket = HASH(h); - tdesc_t *tdp = hash_table[bucket]; - - while (tdp != NULL) { - if (tdp->t_id == h) - return (tdp); - tdp = tdp->t_hash; - } - return (NULL); -} - -static char * -whitesp(char *cp) -{ - char c; - - for (c = *cp++; isspace(c); c = *cp++) - ; - --cp; - return (cp); -} - -static char * -name(char *cp, char **w) -{ - char *new, *orig, c; - int len; - - orig = cp; - c = *cp++; - if (c == ':') - *w = NULL; - else if (isalpha(c) || strchr("_.$#", c)) { - for (c = *cp++; isalnum(c) || strchr(" _.$#", c); c = *cp++) - ; - if (c != ':') - reset(); - len = cp - orig; - new = xmalloc(len); - while (orig < cp - 1) - *new++ = *orig++; - *new = '\0'; - *w = new - (len - 1); - } else - reset(); - - return (cp); -} - -static char * -number(char *cp, int *n) -{ - char *next; - - *n = (int)strtol(cp, &next, 10); - if (next == cp) - expected("number", "<number>", cp); - return (next); -} - -static char * -id(char *cp, int *h) -{ - int n1, n2; - - if (*cp == '(') { /* SunPro style */ - cp++; - cp = number(cp, &n1); - if (*cp++ != ',') - expected("id", ",", cp - 1); - cp = number(cp, &n2); - if (*cp++ != ')') - expected("id", ")", cp - 1); - *h = MAKETYPEID(n1, n2); - } else if (isdigit(*cp)) { /* gcc style */ - cp = number(cp, &n1); - *h = n1; - } else { - expected("id", "(/0-9", cp); - } - return (cp); -} - -static int -tagadd(char *w, int h, tdesc_t *tdp) -{ - tdesc_t *otdp; - - tdp->t_name = w; - if (!(otdp = lookup(h))) - addhash(tdp, h); - else if (otdp != tdp) { - warning("duplicate entry\n"); - warning(" old: %s %d (%d,%d)\n", tdesc_name(otdp), - otdp->t_type, TYPEFILE(otdp->t_id), TYPENUM(otdp->t_id)); - warning(" new: %s %d (%d,%d)\n", tdesc_name(tdp), - tdp->t_type, TYPEFILE(tdp->t_id), TYPENUM(tdp->t_id)); - return (-1); - } - - return (0); -} - -static char * -tdefdecl(char *cp, int h, tdesc_t **rtdp) -{ - tdesc_t *ntdp; - char *w; - int c, h2; - char type; - - parse_debug(3, cp, "tdefdecl h=%d", h); - - /* Type codes */ - switch (type = *cp) { - case 'b': /* integer */ - case 'R': /* fp */ - cp = intrinsic(cp, rtdp); - break; - case '(': /* equiv to another type */ - cp = id(cp, &h2); - ntdp = lookup(h2); - - if (ntdp != NULL && *cp == '=') { - if (ntdp->t_type == FORWARD && *(cp + 1) == 'x') { - /* - * The 6.2 compiler, and possibly others, will - * sometimes emit the same stab for a forward - * declaration twice. That is, "(1,2)=xsfoo:" - * will sometimes show up in two different - * places. This is, of course, quite fun. We - * want CTF to work in spite of the compiler, - * so we'll let this one through. - */ - char *c2 = cp + 2; - char *nm; - - if (!strchr("sue", *c2++)) { - expected("tdefdecl/x-redefine", "[sue]", - c2 - 1); - } - - c2 = name(c2, &nm); - if (strcmp(nm, ntdp->t_name) != 0) { - terminate("Stabs error: Attempt to " - "redefine type (%d,%d) as " - "something else: %s\n", - TYPEFILE(h2), TYPENUM(h2), - c2 - 1); - } - free(nm); - - h2 = faketypenumber++; - ntdp = NULL; - } else { - terminate("Stabs error: Attempting to " - "redefine type (%d,%d)\n", TYPEFILE(h2), - TYPENUM(h2)); - } - } - - if (ntdp == NULL) { /* if that type isn't defined yet */ - if (*cp != '=') { - /* record it as unresolved */ - parse_debug(3, NULL, "tdefdecl unres type %d", - h2); - *rtdp = calloc(1, sizeof (**rtdp)); - (*rtdp)->t_type = TYPEDEF_UNRES; - (*rtdp)->t_id = h2; - break; - } else - cp++; - - /* define a new type */ - cp = tdefdecl(cp, h2, rtdp); - if ((*rtdp)->t_id && (*rtdp)->t_id != h2) { - ntdp = calloc(1, sizeof (*ntdp)); - ntdp->t_type = TYPEDEF; - ntdp->t_tdesc = *rtdp; - *rtdp = ntdp; - } - - addhash(*rtdp, h2); - - } else { /* that type is already defined */ - if (ntdp->t_type != TYPEDEF || ntdp->t_name != NULL) { - *rtdp = ntdp; - } else { - parse_debug(3, NULL, - "No duplicate typedef anon for ref"); - *rtdp = ntdp; - } - } - break; - case '*': - ntdp = NULL; - cp = tdefdecl(cp + 1, h, &ntdp); - if (ntdp == NULL) - expected("tdefdecl/*", "id", cp); - - if (!ntdp->t_id) - ntdp->t_id = faketypenumber++; - - *rtdp = xcalloc(sizeof (**rtdp)); - (*rtdp)->t_type = POINTER; - (*rtdp)->t_size = 0; - (*rtdp)->t_id = h; - (*rtdp)->t_tdesc = ntdp; - break; - case 'f': - cp = tdefdecl(cp + 1, h, &ntdp); - *rtdp = xcalloc(sizeof (**rtdp)); - (*rtdp)->t_type = FUNCTION; - (*rtdp)->t_size = 0; - (*rtdp)->t_id = h; - (*rtdp)->t_fndef = xcalloc(sizeof (fndef_t)); - /* - * The 6.1 compiler will sometimes generate incorrect stabs for - * function pointers (it'll get the return type wrong). This - * causes merges to fail. We therefore treat function pointers - * as if they all point to functions that return int. When - * 4432549 is fixed, the lookupname() call below should be - * replaced with `ntdp'. - */ - (*rtdp)->t_fndef->fn_ret = lookupname("int"); - break; - case 'a': - case 'z': - cp++; - if (*cp++ != 'r') - expected("tdefdecl/[az]", "r", cp - 1); - *rtdp = xcalloc(sizeof (**rtdp)); - (*rtdp)->t_type = ARRAY; - (*rtdp)->t_id = h; - cp = arraydef(cp, rtdp); - break; - case 'x': - c = *++cp; - if (c != 's' && c != 'u' && c != 'e') - expected("tdefdecl/x", "[sue]", cp - 1); - cp = name(cp + 1, &w); - - ntdp = xcalloc(sizeof (*ntdp)); - ntdp->t_type = FORWARD; - ntdp->t_name = w; - /* - * We explicitly don't set t_id here - the caller will do it. - * The caller may want to use a real type ID, or they may - * choose to make one up. - */ - - *rtdp = ntdp; - break; - - case 'B': /* volatile */ - cp = tdefdecl(cp + 1, h, &ntdp); - - if (!ntdp->t_id) - ntdp->t_id = faketypenumber++; - - *rtdp = xcalloc(sizeof (**rtdp)); - (*rtdp)->t_type = VOLATILE; - (*rtdp)->t_size = 0; - (*rtdp)->t_tdesc = ntdp; - (*rtdp)->t_id = h; - break; - - case 'k': /* const */ - cp = tdefdecl(cp + 1, h, &ntdp); - - if (!ntdp->t_id) - ntdp->t_id = faketypenumber++; - - *rtdp = xcalloc(sizeof (**rtdp)); - (*rtdp)->t_type = CONST; - (*rtdp)->t_size = 0; - (*rtdp)->t_tdesc = ntdp; - (*rtdp)->t_id = h; - break; - - case 'K': /* restricted */ - cp = tdefdecl(cp + 1, h, &ntdp); - - if (!ntdp->t_id) - ntdp->t_id = faketypenumber++; - - *rtdp = xcalloc(sizeof (**rtdp)); - (*rtdp)->t_type = RESTRICT; - (*rtdp)->t_size = 0; - (*rtdp)->t_tdesc = ntdp; - (*rtdp)->t_id = h; - break; - - case 'u': - case 's': - cp++; - - *rtdp = xcalloc(sizeof (**rtdp)); - (*rtdp)->t_name = NULL; - cp = soudef(cp, (type == 'u') ? UNION : STRUCT, rtdp); - break; - default: - expected("tdefdecl", "<type code>", cp); - } - return (cp); -} - -static char * -intrinsic(char *cp, tdesc_t **rtdp) -{ - intr_t *intr = xcalloc(sizeof (intr_t)); - tdesc_t *tdp; - int width, fmt, i; - - switch (*cp++) { - case 'b': - intr->intr_type = INTR_INT; - if (*cp == 's') - intr->intr_signed = 1; - else if (*cp != 'u') - expected("intrinsic/b", "[su]", cp); - cp++; - - if (strchr("cbv", *cp)) - intr->intr_iformat = *cp++; - - cp = number(cp, &width); - if (*cp++ != ';') - expected("intrinsic/b", "; (post-width)", cp - 1); - - cp = number(cp, &intr->intr_offset); - if (*cp++ != ';') - expected("intrinsic/b", "; (post-offset)", cp - 1); - - cp = number(cp, &intr->intr_nbits); - break; - - case 'R': - intr->intr_type = INTR_REAL; - for (fmt = 0, i = 0; isdigit(*(cp + i)); i++) - fmt = fmt * 10 + (*(cp + i) - '0'); - - if (fmt < 1 || fmt > CTF_FP_MAX) - expected("intrinsic/R", "number <= CTF_FP_MAX", cp); - - intr->intr_fformat = fmt; - cp += i; - - if (*cp++ != ';') - expected("intrinsic/R", ";", cp - 1); - cp = number(cp, &width); - - intr->intr_nbits = width * 8; - break; - } - - tdp = xcalloc(sizeof (*tdp)); - tdp->t_type = INTRINSIC; - tdp->t_size = width; - tdp->t_name = NULL; - tdp->t_intr = intr; - parse_debug(3, NULL, "intrinsic: size=%d", width); - *rtdp = tdp; - - return (cp); -} - -static tdesc_t * -bitintrinsic(tdesc_t *template, int nbits) -{ - tdesc_t *newtdp = xcalloc(sizeof (tdesc_t)); - - newtdp->t_name = xstrdup(template->t_name); - newtdp->t_id = faketypenumber++; - newtdp->t_type = INTRINSIC; - newtdp->t_size = template->t_size; - newtdp->t_intr = xmalloc(sizeof (intr_t)); - bcopy(template->t_intr, newtdp->t_intr, sizeof (intr_t)); - newtdp->t_intr->intr_nbits = nbits; - - return (newtdp); -} - -static char * -offsize(char *cp, mlist_t *mlp) -{ - int offset, size; - - if (*cp == ',') - cp++; - cp = number(cp, &offset); - if (*cp++ != ',') - expected("offsize/2", ",", cp - 1); - cp = number(cp, &size); - if (*cp++ != ';') - expected("offsize/3", ";", cp - 1); - mlp->ml_offset = offset; - mlp->ml_size = size; - return (cp); -} - -static tdesc_t * -find_intrinsic(tdesc_t *tdp) -{ - for (;;) { - switch (tdp->t_type) { - case TYPEDEF: - case VOLATILE: - case CONST: - case RESTRICT: - tdp = tdp->t_tdesc; - break; - - default: - return (tdp); - } - } -} - -static char * -soudef(char *cp, stabtype_t type, tdesc_t **rtdp) -{ - mlist_t *mlp, **prev; - char *w; - int h; - int size; - tdesc_t *tdp, *itdp; - - cp = number(cp, &size); - (*rtdp)->t_size = size; - (*rtdp)->t_type = type; /* s or u */ - - /* - * An '@' here indicates a bitmask follows. This is so the - * compiler can pass information to debuggers about how structures - * are passed in the v9 world. We don't need this information - * so we skip over it. - */ - if (cp[0] == '@') { - cp += 3; - } - - parse_debug(3, cp, "soudef: %s size=%d", tdesc_name(*rtdp), - (*rtdp)->t_size); - - prev = &((*rtdp)->t_members); - /* now fill up the fields */ - while ((*cp != '\0') && (*cp != ';')) { /* signifies end of fields */ - mlp = xcalloc(sizeof (*mlp)); - *prev = mlp; - cp = name(cp, &w); - mlp->ml_name = w; - cp = id(cp, &h); - /* - * find the tdesc struct in the hash table for this type - * and stick a ptr in here - */ - tdp = lookup(h); - if (tdp == NULL) { /* not in hash list */ - parse_debug(3, NULL, " defines %s (%d)", w, h); - if (*cp++ != '=') { - tdp = unres_new(h); - parse_debug(3, NULL, - " refers to %s (unresolved %d)", - (w ? w : "anon"), h); - } else { - cp = tdefdecl(cp, h, &tdp); - - if (tdp->t_id && tdp->t_id != h) { - tdesc_t *ntdp = xcalloc(sizeof (*ntdp)); - - ntdp->t_type = TYPEDEF; - ntdp->t_tdesc = tdp; - tdp = ntdp; - } - - addhash(tdp, h); - parse_debug(4, cp, - " soudef now looking at "); - cp++; - } - } else { - parse_debug(3, NULL, " refers to %s (%d, %s)", - w ? w : "anon", h, tdesc_name(tdp)); - } - - cp = offsize(cp, mlp); - - itdp = find_intrinsic(tdp); - if (itdp->t_type == INTRINSIC) { - if (mlp->ml_size != itdp->t_intr->intr_nbits) { - parse_debug(4, cp, "making %d bit intrinsic " - "from %s", mlp->ml_size, tdesc_name(itdp)); - mlp->ml_type = bitintrinsic(itdp, mlp->ml_size); - } else - mlp->ml_type = tdp; - } else if (itdp->t_type == TYPEDEF_UNRES) { - list_add(&typedbitfldmems, mlp); - mlp->ml_type = tdp; - } else { - mlp->ml_type = tdp; - } - - /* cp is now pointing to next field */ - prev = &mlp->ml_next; - } - return (cp); -} - -static char * -arraydef(char *cp, tdesc_t **rtdp) -{ - int start, end, h; - - cp = id(cp, &h); - if (*cp++ != ';') - expected("arraydef/1", ";", cp - 1); - - (*rtdp)->t_ardef = xcalloc(sizeof (ardef_t)); - (*rtdp)->t_ardef->ad_idxtype = lookup(h); - - cp = number(cp, &start); /* lower */ - if (*cp++ != ';') - expected("arraydef/2", ";", cp - 1); - - if (*cp == 'S') { - /* - * variable length array - treat as null dimensioned - * - * For VLA variables on sparc, SS12 generated stab entry - * looks as follows: - * .stabs "buf:(0,28)=zr(0,4);0;S-12;(0,1)", 0x80, 0, 0, -16 - * Whereas SS12u1 generated stab entry looks like this: - * .stabs "buf:(0,28)=zr(0,4);0;S0;(0,1)", 0x80, 0, 0, 0 - * On x86, both versions generate the first type of entry. - * We should be able to parse both. - */ - cp++; - if (*cp == '-') - cp++; - cp = number(cp, &end); - end = start; - } else { - /* - * normal fixed-dimension array - * Stab entry for this looks as follows : - * .stabs "x:(0,28)=ar(0,4);0;9;(0,3)", 0x80, 0, 40, 0 - */ - cp = number(cp, &end); /* upper */ - } - - if (*cp++ != ';') - expected("arraydef/3", ";", cp - 1); - (*rtdp)->t_ardef->ad_nelems = end - start + 1; - cp = tdefdecl(cp, h, &((*rtdp)->t_ardef->ad_contents)); - - parse_debug(3, cp, "defined array idx type %d %d-%d next ", - h, start, end); - - return (cp); -} - -static void -enumdef(char *cp, tdesc_t **rtdp) -{ - elist_t *elp, **prev; - char *w; - - (*rtdp)->t_type = ENUM; - (*rtdp)->t_emem = NULL; - - prev = &((*rtdp)->t_emem); - while (*cp != ';') { - elp = xcalloc(sizeof (*elp)); - elp->el_next = NULL; - *prev = elp; - cp = name(cp, &w); - elp->el_name = w; - cp = number(cp, &elp->el_number); - parse_debug(3, NULL, "enum %s: %s=%d", tdesc_name(*rtdp), - elp->el_name, elp->el_number); - prev = &elp->el_next; - if (*cp++ != ',') - expected("enumdef", ",", cp - 1); - } -} - -tdesc_t * -lookup_name(tdesc_t **hash, const char *name) -{ - int bucket = compute_sum(name); - tdesc_t *tdp, *ttdp = NULL; - - for (tdp = hash[bucket]; tdp != NULL; tdp = tdp->t_next) { - if (tdp->t_name != NULL && strcmp(tdp->t_name, name) == 0) { - if (tdp->t_type == STRUCT || tdp->t_type == UNION || - tdp->t_type == ENUM || tdp->t_type == INTRINSIC) - return (tdp); - if (tdp->t_type == TYPEDEF) - ttdp = tdp; - } - } - return (ttdp); -} - -tdesc_t * -lookupname(const char *name) -{ - return (lookup_name(name_table, name)); -} - -/* - * Add a node to the hash queues. - */ -static void -addhash(tdesc_t *tdp, int num) -{ - int hash = HASH(num); - tdesc_t *ttdp; - char added_num = 0, added_name = 0; - - /* - * If it already exists in the hash table don't add it again - * (but still check to see if the name should be hashed). - */ - ttdp = lookup(num); - - if (ttdp == NULL) { - tdp->t_id = num; - tdp->t_hash = hash_table[hash]; - hash_table[hash] = tdp; - added_num = 1; - } - - if (tdp->t_name != NULL) { - ttdp = lookupname(tdp->t_name); - if (ttdp == NULL) { - hash = compute_sum(tdp->t_name); - tdp->t_next = name_table[hash]; - name_table[hash] = tdp; - added_name = 1; - } - } - if (!added_num && !added_name) { - terminate("stabs: broken hash\n"); - } -} - -static int -compute_sum(const char *w) -{ - char c; - int sum; - - for (sum = 0; (c = *w) != '\0'; sum += c, w++) - ; - return (HASH(sum)); -} - -static void -reset(void) -{ - longjmp(resetbuf, 1); -} - -void -check_hash(void) -{ - tdesc_t *tdp; - int i; - - printf("checking hash\n"); - for (i = 0; i < BUCKETS; i++) { - if (hash_table[i]) { - for (tdp = hash_table[i]->t_hash; - tdp && tdp != hash_table[i]; - tdp = tdp->t_hash) - continue; - if (tdp) { - terminate("cycle in hash bucket %d\n", i); - return; - } - } - - if (name_table[i]) { - for (tdp = name_table[i]->t_next; - tdp && tdp != name_table[i]; - tdp = tdp->t_next) - continue; - if (tdp) { - terminate("cycle in name bucket %d\n", i); - return; - } - } - } - printf("done\n"); -} - -/*ARGSUSED1*/ -static int -resolve_typed_bitfields_cb(mlist_t *ml, void *private) -{ - tdesc_t *tdp = ml->ml_type; - - debug(3, "Resolving typed bitfields (member %s)\n", - (ml->ml_name ? ml->ml_name : "(anon)")); - - while (tdp) { - switch (tdp->t_type) { - case INTRINSIC: - if (ml->ml_size != tdp->t_intr->intr_nbits) { - debug(3, "making %d bit intrinsic from %s", - ml->ml_size, tdesc_name(tdp)); - ml->ml_type = bitintrinsic(tdp, ml->ml_size); - } else { - debug(3, "using existing %d bit %s intrinsic", - ml->ml_size, tdesc_name(tdp)); - ml->ml_type = tdp; - } - return (1); - - case POINTER: - case TYPEDEF: - case VOLATILE: - case CONST: - case RESTRICT: - tdp = tdp->t_tdesc; - break; - - default: - return (1); - } - } - - terminate("type chain for bitfield member %s has a NULL", ml->ml_name); - /*NOTREACHED*/ - return (0); -} - -void -resolve_typed_bitfields(void) -{ - (void) list_iter(typedbitfldmems, - (int (*)())resolve_typed_bitfields_cb, NULL); -} diff --git a/usr/src/tools/ctf/cvt/stabs.c b/usr/src/tools/ctf/cvt/stabs.c deleted file mode 100644 index db6c8ae111..0000000000 --- a/usr/src/tools/ctf/cvt/stabs.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * Copyright (c) 2018, Joyent, Inc. - */ - -/* - * Routines used to read stabs data from a file, and to build a tdata structure - * based on the interesting parts of that data. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <fcntl.h> -#include <unistd.h> -#include <assert.h> -#include <string.h> -#include <libgen.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/param.h> - -#include "ctftools.h" -#include "list.h" -#include "stack.h" -#include "memory.h" -#include "traverse.h" - -const char *curhdr; - -/* - * The stabs generator will sometimes reference types before they've been - * defined. If this is the case, a TYPEDEF_UNRES tdesc will be generated. - * Note that this is different from a forward declaration, in which the - * stab is defined, but is defined as something that doesn't exist yet. - * When we have read all of the stabs from the file, we can go back and - * fix up all of the unresolved types. We should be able to fix all of them. - */ -/*ARGSUSED2*/ -static int -resolve_tou_node(tdesc_t *node, tdesc_t **nodep, void *private) -{ - tdesc_t *new; - - debug(3, "Trying to resolve %s (%d)\n", tdesc_name(node), node->t_id); - new = lookup(node->t_id); - - if (new == NULL) { - terminate("Couldn't resolve type %d\n", node->t_id); - } - - debug(3, " Resolving to %d\n", new->t_id); - - *nodep = new; - - return (1); -} - -/*ARGSUSED*/ -static int -resolve_fwd_node(tdesc_t *node, tdesc_t **nodep, void *private) -{ - tdesc_t *new = lookupname(node->t_name); - - debug(3, "Trying to unforward %s (%d)\n", tdesc_name(node), node->t_id); - - if (!new || (new->t_type != STRUCT && new->t_type != UNION)) - return (0); - - debug(3, " Unforwarded to %d\n", new->t_id); - - *nodep = new; - - return (1); -} - -static tdtrav_cb_f resolve_cbs[] = { - NULL, - NULL, /* intrinsic */ - NULL, /* pointer */ - NULL, /* array */ - NULL, /* function */ - NULL, /* struct */ - NULL, /* union */ - NULL, /* enum */ - resolve_fwd_node, /* forward */ - NULL, /* typedef */ - resolve_tou_node, /* typedef unres */ - NULL, /* volatile */ - NULL, /* const */ - NULL, /* restrict */ -}; - -static void -resolve_nodes(tdata_t *td) -{ - debug(2, "Resolving unresolved stabs\n"); - - (void) iitraverse_hash(td->td_iihash, &td->td_curvgen, resolve_cbs, - NULL, NULL, td); -} - -static char * -concat(char *s1, char *s2, int s2strip) -{ - int savelen = strlen(s2) - s2strip; - int newlen = (s1 ? strlen(s1) : 0) + savelen + 1; - char *out; - - out = xrealloc(s1, newlen); - if (s1) - strncpy(out + strlen(out), s2, savelen); - else - strncpy(out, s2, savelen); - - out[newlen - 1] = '\0'; - - return (out); -} - -/* - * N_FUN stabs come with their arguments in promoted form. In order to get the - * actual arguments, we need to wait for the N_PSYM stabs that will come towards - * the end of the function. These routines free the arguments (fnarg_free) we - * got from the N_FUN stab and add (fnarg_add) the ones from the N_PSYM stabs. - */ -static void -fnarg_add(iidesc_t *curfun, iidesc_t *arg) -{ - curfun->ii_nargs++; - - if (curfun->ii_nargs == 1) - curfun->ii_args = xmalloc(sizeof (tdesc_t *) * FUNCARG_DEF); - else if (curfun->ii_nargs > FUNCARG_DEF) { - curfun->ii_args = xrealloc(curfun->ii_args, - sizeof (tdesc_t *) * curfun->ii_nargs); - } - - curfun->ii_args[curfun->ii_nargs - 1] = arg->ii_dtype; - arg->ii_dtype = NULL; -} - -static void -fnarg_free(iidesc_t *ii) -{ - ii->ii_nargs = 0; - free(ii->ii_args); - ii->ii_args = NULL; -} - -/* - * Read the stabs from the stab ELF section, and turn them into a tdesc tree, - * assembled under an iidesc list. - */ -int -stabs_read(tdata_t *td, Elf *elf, const char *file) -{ - Elf_Scn *scn; - Elf_Data *data; - stab_t *stab; - stk_t *file_stack; - iidesc_t *iidescp; - iidesc_t *curfun = NULL; - char curpath[MAXPATHLEN]; - char *curfile = NULL; - char *str; - char *fstr = NULL, *ofstr = NULL; - int stabidx, stabstridx; - int nstabs, rc, i; - int scope = 0; - - if (!((stabidx = findelfsecidx(elf, file, ".stab.excl")) >= 0 && - (stabstridx = findelfsecidx(elf, file, ".stab.exclstr")) >= 0) && - !((stabidx = findelfsecidx(elf, file, ".stab")) >= 0 && - (stabstridx = findelfsecidx(elf, file, ".stabstr")) >= 0)) { - errno = ENOENT; - return (-1); - } - - file_stack = stack_new(free); - - stack_push(file_stack, (void *)file); - curhdr = file; - - debug(3, "Found stabs in %d, strings in %d\n", stabidx, stabstridx); - - scn = elf_getscn(elf, stabidx); - data = elf_rawdata(scn, NULL); - nstabs = data->d_size / sizeof (stab_t); - - parse_init(td); - for (i = 0; i < nstabs; i++) { - stab = &((stab_t *)data->d_buf)[i]; - - /* We don't want any local definitions */ - if (stab->n_type == N_LBRAC) { - scope++; - debug(3, "stab %d: opening scope (%d)\n", i + 1, scope); - continue; - } else if (stab->n_type == N_RBRAC) { - scope--; - debug(3, "stab %d: closing scope (%d)\n", i + 1, scope); - continue; - } else if (stab->n_type == N_EINCL) { - /* - * There's a bug in the 5.2 (Taz) compilers that causes - * them to emit an extra N_EINCL if there's no actual - * text in the file being compiled. To work around this - * bug, we explicitly check to make sure we're not - * trying to pop a stack that only has the outer scope - * on it. - */ - if (stack_level(file_stack) != 1) { - str = (char *)stack_pop(file_stack); - free(str); - curhdr = (char *)stack_peek(file_stack); - } - } - - /* We only care about a subset of the stabs */ - if (!(stab->n_type == N_FUN || stab->n_type == N_GSYM || - stab->n_type == N_LCSYM || stab->n_type == N_LSYM || - stab->n_type == N_PSYM || stab->n_type == N_ROSYM || - stab->n_type == N_RSYM || - stab->n_type == N_STSYM || stab->n_type == N_BINCL || - stab->n_type == N_SO || stab->n_type == N_OPT)) - continue; - - if ((str = elf_strptr(elf, stabstridx, - (size_t)stab->n_strx)) == NULL) { - terminate("%s: Can't find string at %u for stab %d\n", - file, stab->n_strx, i); - } - - if (stab->n_type == N_BINCL) { - curhdr = xstrdup(str); - stack_push(file_stack, (void *)curhdr); - continue; - } else if (stab->n_type == N_SO) { - if (str[strlen(str) - 1] != '/') { - strcpy(curpath, str); - curfile = basename(curpath); - } - continue; - } else if (stab->n_type == N_OPT) { - if (strcmp(str, "gcc2_compiled.") == 0) { - terminate("%s: GCC-generated stabs are " - "unsupported. Use DWARF instead.\n", file); - } - continue; - } - - if (str[strlen(str) - 1] == '\\') { - int offset = 1; - /* - * There's a bug in the compilers that causes them to - * generate \ for continuations with just -g (this is - * ok), and \\ for continuations with -g -O (this is - * broken). This bug is "fixed" in the 6.2 compilers - * via the elimination of continuation stabs. - */ - if (str[strlen(str) - 2] == '\\') - offset = 2; - fstr = concat(fstr, str, offset); - continue; - } else - fstr = concat(fstr, str, 0); - - debug(3, "%4d: .stabs \"%s\", %#x, %d, %hd, %d (from %s)\n", i, - fstr, stab->n_type, 0, stab->n_desc, - stab->n_value, curhdr); - - if (debug_level >= 3) - check_hash(); - - /* - * Sometimes the compiler stutters, and emits the same stab - * twice. This is bad for the parser, which will attempt to - * redefine the type IDs indicated in the stabs. This is - * compiler bug 4433511. - */ - if (ofstr && strcmp(fstr, ofstr) == 0) { - debug(3, "Stutter stab\n"); - free(fstr); - fstr = NULL; - continue; - } - - if (ofstr) - free(ofstr); - ofstr = fstr; - - iidescp = NULL; - - if ((rc = parse_stab(stab, fstr, &iidescp)) < 0) { - terminate("%s: Couldn't parse stab \"%s\" " - "(source file %s)\n", file, str, curhdr); - } - - if (rc == 0) - goto parse_loop_end; - - /* Make sure the scope tracking is working correctly */ - assert(stab->n_type != N_FUN || (iidescp->ii_type != II_GFUN && - iidescp->ii_type != II_SFUN) || scope == 0); - - /* - * The only things we care about that are in local scope are - * the N_PSYM stabs. - */ - if (scope && stab->n_type != N_PSYM) { - iidesc_free(iidescp); - goto parse_loop_end; - } - - switch (iidescp->ii_type) { - case II_SFUN: - iidescp->ii_owner = xstrdup(curfile); - /*FALLTHROUGH*/ - case II_GFUN: - curfun = iidescp; - fnarg_free(iidescp); - iidesc_add(td->td_iihash, iidescp); - break; - - case II_SVAR: - iidescp->ii_owner = xstrdup(curfile); - /*FALLTHROUGH*/ - case II_GVAR: - case II_TYPE: - case II_SOU: - iidesc_add(td->td_iihash, iidescp); - break; - - case II_PSYM: - fnarg_add(curfun, iidescp); - iidesc_free(iidescp); - break; - default: - aborterr("invalid ii_type %d for stab type %d", - iidescp->ii_type, stab->n_type); - } - -parse_loop_end: - fstr = NULL; - } - - if (ofstr) - free(ofstr); - - resolve_nodes(td); - resolve_typed_bitfields(); - parse_finish(td); - - cvt_fixstabs(td); - cvt_fixups(td, elf_ptrsz(elf)); - - return (0); -} diff --git a/usr/src/tools/ctf/cvt/stack.c b/usr/src/tools/ctf/cvt/stack.c deleted file mode 100644 index 7c36cd5ef1..0000000000 --- a/usr/src/tools/ctf/cvt/stack.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright (c) 2001 by Sun Microsystems, Inc. - * All rights reserved. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Routines for manipulating stacks - */ - -#include <stdio.h> -#include <assert.h> -#include <stdlib.h> - -#include "stack.h" -#include "memory.h" - -#define STACK_SEEDSIZE 5 - -struct stk { - int st_nument; - int st_top; - void **st_data; - - void (*st_free)(void *); -}; - -stk_t * -stack_new(void (*freep)(void *)) -{ - stk_t *sp; - - sp = xmalloc(sizeof (stk_t)); - sp->st_nument = STACK_SEEDSIZE; - sp->st_top = -1; - sp->st_data = xmalloc(sizeof (void *) * sp->st_nument); - sp->st_free = freep; - - return (sp); -} - -void -stack_free(stk_t *sp) -{ - int i; - - if (sp->st_free) { - for (i = 0; i <= sp->st_top; i++) - sp->st_free(sp->st_data[i]); - } - free(sp->st_data); - free(sp); -} - -void * -stack_pop(stk_t *sp) -{ - assert(sp->st_top >= 0); - - return (sp->st_data[sp->st_top--]); -} - -void * -stack_peek(stk_t *sp) -{ - if (sp->st_top == -1) - return (NULL); - - return (sp->st_data[sp->st_top]); -} - -void -stack_push(stk_t *sp, void *data) -{ - sp->st_top++; - - if (sp->st_top == sp->st_nument) { - sp->st_nument += STACK_SEEDSIZE; - sp->st_data = xrealloc(sp->st_data, - sizeof (void *) * sp->st_nument); - } - - sp->st_data[sp->st_top] = data; -} - -int -stack_level(stk_t *sp) -{ - return (sp->st_top + 1); -} diff --git a/usr/src/tools/ctf/cvt/stack.h b/usr/src/tools/ctf/cvt/stack.h deleted file mode 100644 index 7dca7cfb10..0000000000 --- a/usr/src/tools/ctf/cvt/stack.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright (c) 2001 by Sun Microsystems, Inc. - * All rights reserved. - */ - -#ifndef _STACK_H -#define _STACK_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Routines for manipulating stacks - */ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct stk stk_t; - -stk_t *stack_new(void (*)(void *)); -void stack_free(stk_t *); -void *stack_pop(stk_t *); -void *stack_peek(stk_t *); -void stack_push(stk_t *, void *); -int stack_level(stk_t *); - -#ifdef __cplusplus -} -#endif - -#endif /* _STACK_H */ diff --git a/usr/src/tools/ctf/cvt/strtab.c b/usr/src/tools/ctf/cvt/strtab.c deleted file mode 100644 index ba6b7d86d0..0000000000 --- a/usr/src/tools/ctf/cvt/strtab.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright (c) 2001 by Sun Microsystems, Inc. - * All rights reserved. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/types.h> -#include <sys/sysmacros.h> -#include <strings.h> -#include <stdlib.h> -#include <stdio.h> - -#include "strtab.h" -#include "memory.h" - -#define STRTAB_HASHSZ 211 /* use a prime number of hash buckets */ -#define STRTAB_BUFSZ (64 * 1024) /* use 64K data buffers by default */ - -static void -strtab_grow(strtab_t *sp) -{ - sp->str_nbufs++; - sp->str_bufs = xrealloc(sp->str_bufs, sp->str_nbufs * sizeof (char *)); - sp->str_ptr = xmalloc(sp->str_bufsz); - sp->str_bufs[sp->str_nbufs - 1] = sp->str_ptr; -} - -void -strtab_create(strtab_t *sp) -{ - sp->str_hash = xcalloc(STRTAB_HASHSZ * sizeof (strhash_t *)); - sp->str_hashsz = STRTAB_HASHSZ; - sp->str_bufs = NULL; - sp->str_ptr = NULL; - sp->str_nbufs = 0; - sp->str_bufsz = STRTAB_BUFSZ; - sp->str_nstrs = 1; - sp->str_size = 1; - - strtab_grow(sp); - *sp->str_ptr++ = '\0'; -} - -void -strtab_destroy(strtab_t *sp) -{ - strhash_t *hp, *hq; - ulong_t i; - - for (i = 0; i < sp->str_hashsz; i++) { - for (hp = sp->str_hash[i]; hp != NULL; hp = hq) { - hq = hp->str_next; - free(hp); - } - } - - for (i = 0; i < sp->str_nbufs; i++) - free(sp->str_bufs[i]); - - free(sp->str_hash); - free(sp->str_bufs); -} - -static ulong_t -strtab_hash(const char *key, size_t *len) -{ - ulong_t g, h = 0; - const char *p; - size_t n = 0; - - for (p = key; *p != '\0'; p++, n++) { - h = (h << 4) + *p; - - if ((g = (h & 0xf0000000)) != 0) { - h ^= (g >> 24); - h ^= g; - } - } - - *len = n; - return (h); -} - -static int -strtab_compare(strtab_t *sp, strhash_t *hp, const char *str, size_t len) -{ - ulong_t b = hp->str_buf; - const char *buf = hp->str_data; - size_t resid, n; - int rv; - - while (len != 0) { - if (buf == sp->str_bufs[b] + sp->str_bufsz) - buf = sp->str_bufs[++b]; - - resid = sp->str_bufs[b] + sp->str_bufsz - buf; - n = MIN(resid, len); - - if ((rv = strncmp(buf, str, n)) != 0) - return (rv); - - buf += n; - str += n; - len -= n; - } - - return (0); -} - -static void -strtab_copyin(strtab_t *sp, const char *str, size_t len) -{ - ulong_t b = sp->str_nbufs - 1; - size_t resid, n; - - while (len != 0) { - if (sp->str_ptr == sp->str_bufs[b] + sp->str_bufsz) { - strtab_grow(sp); - b++; - } - - resid = sp->str_bufs[b] + sp->str_bufsz - sp->str_ptr; - n = MIN(resid, len); - bcopy(str, sp->str_ptr, n); - - sp->str_ptr += n; - str += n; - len -= n; - } -} - -size_t -strtab_insert(strtab_t *sp, const char *str) -{ - strhash_t *hp; - size_t len; - ulong_t h; - - if (str == NULL || str[0] == '\0') - return (0); /* we keep a \0 at offset 0 to simplify things */ - - h = strtab_hash(str, &len) % sp->str_hashsz; - - /* - * If the string is already in our hash table, just return the offset - * of the existing string element and do not add a duplicate string. - */ - for (hp = sp->str_hash[h]; hp != NULL; hp = hp->str_next) { - if (strtab_compare(sp, hp, str, len + 1) == 0) - return (hp->str_off); - } - - /* - * Create a new hash bucket, initialize it, and insert it at the front - * of the hash chain for the appropriate bucket. - */ - hp = xmalloc(sizeof (strhash_t)); - - hp->str_data = sp->str_ptr; - hp->str_buf = sp->str_nbufs - 1; - hp->str_off = sp->str_size; - hp->str_len = len; - hp->str_next = sp->str_hash[h]; - - sp->str_hash[h] = hp; - - /* - * Now copy the string data into our buffer list, and then update - * the global counts of strings and bytes. Return str's byte offset. - */ - strtab_copyin(sp, str, len + 1); - sp->str_nstrs++; - sp->str_size += len + 1; - - return (hp->str_off); -} - -size_t -strtab_size(const strtab_t *sp) -{ - return (sp->str_size); -} - -ssize_t -strtab_write(const strtab_t *sp, - ssize_t (*func)(const void *, size_t, void *), void *priv) -{ - ssize_t res, total = 0; - ulong_t i; - size_t n; - - for (i = 0; i < sp->str_nbufs; i++, total += res) { - if (i == sp->str_nbufs - 1) - n = sp->str_ptr - sp->str_bufs[i]; - else - n = sp->str_bufsz; - - if ((res = func(sp->str_bufs[i], n, priv)) <= 0) - break; - } - - if (total == 0 && sp->str_size != 0) - return (-1); - - return (total); -} - -void -strtab_print(const strtab_t *sp) -{ - const strhash_t *hp; - ulong_t i; - - for (i = 0; i < sp->str_hashsz; i++) { - for (hp = sp->str_hash[i]; hp != NULL; hp = hp->str_next) { - const char *buf = hp->str_data; - ulong_t b = hp->str_buf; - size_t resid, len, n; - - (void) printf("[%lu] %lu \"", (ulong_t)hp->str_off, b); - - for (len = hp->str_len; len != 0; len -= n) { - if (buf == sp->str_bufs[b] + sp->str_bufsz) - buf = sp->str_bufs[++b]; - - resid = sp->str_bufs[b] + sp->str_bufsz - buf; - n = MIN(resid, len); - - (void) printf("%.*s", (int)n, buf); - buf += n; - } - - (void) printf("\"\n"); - } - } -} diff --git a/usr/src/tools/ctf/cvt/strtab.h b/usr/src/tools/ctf/cvt/strtab.h deleted file mode 100644 index 7176e07378..0000000000 --- a/usr/src/tools/ctf/cvt/strtab.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright (c) 2001 by Sun Microsystems, Inc. - * All rights reserved. - */ - -#ifndef _STRTAB_H -#define _STRTAB_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/types.h> - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct strhash { - const char *str_data; /* pointer to actual string data */ - ulong_t str_buf; /* index of string data buffer */ - size_t str_off; /* offset in bytes of this string */ - size_t str_len; /* length in bytes of this string */ - struct strhash *str_next; /* next string in hash chain */ -} strhash_t; - -typedef struct strtab { - strhash_t **str_hash; /* array of hash buckets */ - ulong_t str_hashsz; /* size of hash bucket array */ - char **str_bufs; /* array of buffer pointers */ - char *str_ptr; /* pointer to current buffer location */ - ulong_t str_nbufs; /* size of buffer pointer array */ - size_t str_bufsz; /* size of individual buffer */ - ulong_t str_nstrs; /* total number of strings in strtab */ - size_t str_size; /* total size of strings in bytes */ -} strtab_t; - -extern void strtab_create(strtab_t *); -extern void strtab_destroy(strtab_t *); -extern size_t strtab_insert(strtab_t *, const char *); -extern size_t strtab_size(const strtab_t *); -extern ssize_t strtab_write(const strtab_t *, - ssize_t (*)(const void *, size_t, void *), void *); -extern void strtab_print(const strtab_t *); - -#ifdef __cplusplus -} -#endif - -#endif /* _STRTAB_H */ diff --git a/usr/src/tools/ctf/cvt/tdata.c b/usr/src/tools/ctf/cvt/tdata.c deleted file mode 100644 index ca71168bcf..0000000000 --- a/usr/src/tools/ctf/cvt/tdata.c +++ /dev/null @@ -1,479 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * Routines for manipulating tdesc and tdata structures - */ - -#include <stdio.h> -#include <stdlib.h> -#include <strings.h> -#include <pthread.h> - -#include "ctftools.h" -#include "memory.h" -#include "traverse.h" - -/* - * The layout hash is used during the equivalency checking. We have a node in - * the child graph that may be equivalent to a node in the parent graph. To - * find the corresponding node (if any) in the parent, we need a quick way to - * get to all nodes in the parent that look like the node in the child. Since a - * large number of nodes don't have names, we need to incorporate the layout of - * the node into the hash. If we don't, we'll end up with the vast majority of - * nodes in bucket zero, with one or two nodes in each of the remaining buckets. - * - * There are a couple of constraints, both of which concern forward - * declarations. Recall that a forward declaration tdesc is equivalent to a - * tdesc that actually defines the structure or union. As such, we cannot - * incorporate anything into the hash for a named struct or union node that - * couldn't be found by looking at the forward, and vice versa. - */ -int -tdesc_layouthash(int nbuckets, void *node) -{ - tdesc_t *tdp = node; - char *name = NULL; - ulong_t h = 0; - - if (tdp->t_name) - name = tdp->t_name; - else { - switch (tdp->t_type) { - case POINTER: - case TYPEDEF: - case VOLATILE: - case CONST: - case RESTRICT: - name = tdp->t_tdesc->t_name; - break; - case FUNCTION: - h = tdp->t_fndef->fn_nargs + - tdp->t_fndef->fn_vargs; - name = tdp->t_fndef->fn_ret->t_name; - break; - case ARRAY: - h = tdp->t_ardef->ad_nelems; - name = tdp->t_ardef->ad_contents->t_name; - break; - case STRUCT: - case UNION: - /* - * Unnamed structures, which cannot have forward - * declarations pointing to them. We can therefore - * incorporate the name of the first member into - * the hash value, assuming there are any. - */ - if (tdp->t_members != NULL) - name = tdp->t_members->ml_name; - break; - case ENUM: - /* Use the first element in the hash value */ - name = tdp->t_emem->el_name; - break; - default: - /* - * Intrinsics, forwards, and typedefs all have - * names. - */ - warning("Unexpected unnamed %d tdesc (ID %d)\n", - tdp->t_type, tdp->t_id); - } - } - - if (name) - return (hash_name(nbuckets, name)); - - return (h % nbuckets); -} - -int -tdesc_layoutcmp(void *arg1, void *arg2) -{ - tdesc_t *tdp1 = arg1, *tdp2 = arg2; - - if (tdp1->t_name == NULL) { - if (tdp2->t_name == NULL) - return (0); - else - return (-1); - } else if (tdp2->t_name == NULL) - return (1); - else - return (strcmp(tdp1->t_name, tdp2->t_name)); -} - -int -tdesc_idhash(int nbuckets, void *data) -{ - tdesc_t *tdp = data; - - return (tdp->t_id % nbuckets); -} - -int -tdesc_idcmp(void *arg1, void *arg2) -{ - tdesc_t *tdp1 = arg1, *tdp2 = arg2; - - if (tdp1->t_id == tdp2->t_id) - return (0); - else - return (tdp1->t_id > tdp2->t_id ? 1 : -1); -} - -int -tdesc_namehash(int nbuckets, void *data) -{ - tdesc_t *tdp = data; - ulong_t h, g; - char *c; - - if (tdp->t_name == NULL) - return (0); - - for (h = 0, c = tdp->t_name; *c; c++) { - h = (h << 4) + *c; - if ((g = (h & 0xf0000000)) != 0) { - h ^= (g >> 24); - h ^= g; - } - } - - return (h % nbuckets); -} - -int -tdesc_namecmp(void *arg1, void *arg2) -{ - tdesc_t *tdp1 = arg1, *tdp2 = arg2; - - return (!streq(tdp1->t_name, tdp2->t_name)); -} - -/*ARGSUSED1*/ -int -tdesc_print(void *data, void *private) -{ - tdesc_t *tdp = data; - - printf("%7d %s\n", tdp->t_id, tdesc_name(tdp)); - - return (1); -} - -static void -free_intr(tdesc_t *tdp) -{ - free(tdp->t_intr); -} - -static void -free_ardef(tdesc_t *tdp) -{ - free(tdp->t_ardef); -} - -static void -free_mlist(tdesc_t *tdp) -{ - mlist_t *ml = tdp->t_members; - mlist_t *oml; - - while (ml) { - oml = ml; - ml = ml->ml_next; - - if (oml->ml_name) - free(oml->ml_name); - free(oml); - } -} - -static void -free_elist(tdesc_t *tdp) -{ - elist_t *el = tdp->t_emem; - elist_t *oel; - - while (el) { - oel = el; - el = el->el_next; - - if (oel->el_name) - free(oel->el_name); - free(oel); - } -} - -static void (*free_cbs[])(tdesc_t *) = { - NULL, - free_intr, - NULL, - free_ardef, - NULL, - free_mlist, - free_mlist, - free_elist, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL -}; - -/*ARGSUSED1*/ -static void -tdesc_free_cb(void *ptr, void *private) -{ - tdesc_t *tdp = ptr; - - if (tdp->t_name) - free(tdp->t_name); - if (free_cbs[tdp->t_type]) - free_cbs[tdp->t_type](tdp); - free(tdp); -} - -void -tdesc_free(tdesc_t *tdp) -{ - tdesc_free_cb(tdp, NULL); -} - -static int -tdata_label_cmp(labelent_t *le1, labelent_t *le2) -{ - return (le1->le_idx - le2->le_idx); -} - -void -tdata_label_add(tdata_t *td, char *label, int idx) -{ - labelent_t *le = xmalloc(sizeof (*le)); - - le->le_name = xstrdup(label); - le->le_idx = (idx == -1 ? td->td_nextid - 1 : idx); - - slist_add(&td->td_labels, le, (int (*)())tdata_label_cmp); -} - -static int -tdata_label_top_cb(void *data, void *arg) -{ - labelent_t *le = data; - labelent_t **topp = arg; - - *topp = le; - - return (1); -} - -labelent_t * -tdata_label_top(tdata_t *td) -{ - labelent_t *top = NULL; - - (void) list_iter(td->td_labels, tdata_label_top_cb, &top); - - return (top); -} - -static int -tdata_label_find_cb(labelent_t *le, labelent_t *tmpl) -{ - return (streq(le->le_name, tmpl->le_name)); -} - -int -tdata_label_find(tdata_t *td, char *label) -{ - labelent_t let; - labelent_t *ret; - - if (streq(label, "BASE")) { - ret = (labelent_t *)list_first(td->td_labels); - return (ret ? ret->le_idx : -1); - } - - let.le_name = label; - - if (!(ret = (labelent_t *)list_find(td->td_labels, &let, - (int (*)())tdata_label_find_cb))) - return (-1); - - return (ret->le_idx); -} - -static int -tdata_label_newmax_cb(void *data, void *arg) -{ - labelent_t *le = data; - int *newmaxp = arg; - - if (le->le_idx > *newmaxp) { - le->le_idx = *newmaxp; - return (1); - } - - return (0); -} - -void -tdata_label_newmax(tdata_t *td, int newmax) -{ - (void) list_iter(td->td_labels, tdata_label_newmax_cb, &newmax); -} - -/*ARGSUSED1*/ -static void -tdata_label_free_cb(labelent_t *le, void *private) -{ - if (le->le_name) - free(le->le_name); - free(le); -} - -void -tdata_label_free(tdata_t *td) -{ - list_free(td->td_labels, (void (*)())tdata_label_free_cb, NULL); - td->td_labels = NULL; -} - -tdata_t * -tdata_new(void) -{ - tdata_t *new = xcalloc(sizeof (tdata_t)); - - new->td_layouthash = hash_new(TDATA_LAYOUT_HASH_SIZE, tdesc_layouthash, - tdesc_layoutcmp); - new->td_idhash = hash_new(TDATA_ID_HASH_SIZE, tdesc_idhash, - tdesc_idcmp); - /* - * This is also traversed as a list, but amortized O(1) - * lookup massively impacts part of the merge phase, so - * we store the iidescs as a hash. - */ - new->td_iihash = hash_new(IIDESC_HASH_SIZE, iidesc_hash, NULL); - new->td_nextid = 1; - new->td_curvgen = 1; - - pthread_mutex_init(&new->td_mergelock, NULL); - - return (new); -} - -void -tdata_free(tdata_t *td) -{ - hash_free(td->td_iihash, iidesc_free_cb, NULL); - hash_free(td->td_layouthash, tdesc_free_cb, NULL); - hash_free(td->td_idhash, NULL, NULL); - list_free(td->td_fwdlist, NULL, NULL); - - tdata_label_free(td); - - free(td->td_parlabel); - free(td->td_parname); - - pthread_mutex_destroy(&td->td_mergelock); - - free(td); -} - -/*ARGSUSED1*/ -static int -build_hashes(tdesc_t *ctdp, tdesc_t **ctdpp, void *private) -{ - tdata_t *td = private; - - hash_add(td->td_idhash, ctdp); - hash_add(td->td_layouthash, ctdp); - - return (1); -} - -static tdtrav_cb_f build_hashes_cbs[] = { - NULL, - build_hashes, /* intrinsic */ - build_hashes, /* pointer */ - build_hashes, /* array */ - build_hashes, /* function */ - build_hashes, /* struct */ - build_hashes, /* union */ - build_hashes, /* enum */ - build_hashes, /* forward */ - build_hashes, /* typedef */ - tdtrav_assert, /* typedef_unres */ - build_hashes, /* volatile */ - build_hashes, /* const */ - build_hashes /* restrict */ -}; - -static void -tdata_build_hashes_common(tdata_t *td, hash_t *hash) -{ - (void) iitraverse_hash(hash, &td->td_curvgen, NULL, NULL, - build_hashes_cbs, td); -} - -void -tdata_build_hashes(tdata_t *td) -{ - tdata_build_hashes_common(td, td->td_iihash); -} - -/* Merge td2 into td1. td2 is destroyed by the merge */ -void -tdata_merge(tdata_t *td1, tdata_t *td2) -{ - td1->td_curemark = MAX(td1->td_curemark, td2->td_curemark); - td1->td_curvgen = MAX(td1->td_curvgen, td2->td_curvgen); - td1->td_nextid = MAX(td1->td_nextid, td2->td_nextid); - - hash_merge(td1->td_iihash, td2->td_iihash); - - /* Add td2's type tree to the hashes */ - tdata_build_hashes_common(td1, td2->td_iihash); - - list_concat(&td1->td_fwdlist, td2->td_fwdlist); - td2->td_fwdlist = NULL; - - slist_merge(&td1->td_labels, td2->td_labels, - (int (*)())tdata_label_cmp); - td2->td_labels = NULL; - - /* free the td2 hashes (data is now part of td1) */ - - hash_free(td2->td_layouthash, NULL, NULL); - td2->td_layouthash = NULL; - - hash_free(td2->td_iihash, NULL, NULL); - td2->td_iihash = NULL; - - tdata_free(td2); -} diff --git a/usr/src/tools/ctf/cvt/traverse.c b/usr/src/tools/ctf/cvt/traverse.c deleted file mode 100644 index b415b35af6..0000000000 --- a/usr/src/tools/ctf/cvt/traverse.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Routines used to traverse tdesc trees, invoking user-supplied callbacks - * as the tree is traversed. - */ - -#include <stdio.h> -#include <assert.h> - -#include "ctftools.h" -#include "traverse.h" -#include "memory.h" - -int (*tddescenders[])(); -int (*tdnops[])(); - -int tdtraverse(tdesc_t *, tdesc_t **, tdtrav_data_t *); - -void -tdtrav_init(tdtrav_data_t *tdtd, int *vgenp, tdtrav_cb_f *firstops, - tdtrav_cb_f *preops, tdtrav_cb_f *postops, void *private) -{ - tdtd->vgen = ++(*vgenp); - tdtd->firstops = firstops ? firstops : tdnops; - tdtd->preops = preops ? preops : tdnops; - tdtd->postops = postops ? postops : tdnops; - tdtd->private = private; -} - -static int -tdtrav_plain(tdesc_t *this, tdtrav_data_t *tdtd) -{ - return (tdtraverse(this->t_tdesc, &this->t_tdesc, tdtd)); -} - -static int -tdtrav_func(tdesc_t *this, tdtrav_data_t *tdtd) -{ - fndef_t *fn = this->t_fndef; - int i, rc; - - if ((rc = tdtraverse(fn->fn_ret, &fn->fn_ret, tdtd)) < 0) - return (rc); - - for (i = 0; i < fn->fn_nargs; i++) { - if ((rc = tdtraverse(fn->fn_args[i], &fn->fn_args[i], - tdtd)) < 0) - return (rc); - } - - return (0); -} - -static int -tdtrav_array(tdesc_t *this, tdtrav_data_t *tdtd) -{ - ardef_t *ardef = this->t_ardef; - int rc; - - if ((rc = tdtraverse(ardef->ad_contents, &ardef->ad_contents, - tdtd)) < 0) - return (rc); - - return (tdtraverse(ardef->ad_idxtype, &ardef->ad_idxtype, tdtd)); -} - -static int -tdtrav_su(tdesc_t *this, tdtrav_data_t *tdtd) -{ - mlist_t *ml; - int rc = 0; - - for (ml = this->t_members; ml; ml = ml->ml_next) { - if ((rc = tdtraverse(ml->ml_type, &ml->ml_type, tdtd)) < 0) - return (rc); - } - - return (rc); -} - -/*ARGSUSED*/ -int -tdtrav_assert(tdesc_t *node, tdesc_t **nodep, void *private) -{ - assert(1 == 0); - - return (-1); -} - -tdtrav_cb_f tdnops[] = { - NULL, - NULL, /* intrinsic */ - NULL, /* pointer */ - NULL, /* array */ - NULL, /* function */ - NULL, /* struct */ - NULL, /* union */ - NULL, /* enum */ - NULL, /* forward */ - NULL, /* typedef */ - NULL, /* typedef_unres */ - NULL, /* volatile */ - NULL, /* const */ - NULL /* restrict */ -}; - -int (*tddescenders[])(tdesc_t *, tdtrav_data_t *) = { - NULL, - NULL, /* intrinsic */ - tdtrav_plain, /* pointer */ - tdtrav_array, /* array */ - tdtrav_func, /* function */ - tdtrav_su, /* struct */ - tdtrav_su, /* union */ - NULL, /* enum */ - NULL, /* forward */ - tdtrav_plain, /* typedef */ - NULL, /* typedef_unres */ - tdtrav_plain, /* volatile */ - tdtrav_plain, /* const */ - tdtrav_plain /* restrict */ -}; - -int -tdtraverse(tdesc_t *this, tdesc_t **thisp, tdtrav_data_t *tdtd) -{ - tdtrav_cb_f travcb; - int (*descender)(); - int descend = 1; - int rc; - - if ((travcb = tdtd->firstops[this->t_type]) != NULL) { - if ((rc = travcb(this, thisp, tdtd->private)) < 0) - return (rc); - else if (rc == 0) - descend = 0; - } - - if (this->t_vgen == tdtd->vgen) - return (1); - this->t_vgen = tdtd->vgen; - - if (descend && (travcb = tdtd->preops[this->t_type]) != NULL) { - if ((rc = travcb(this, thisp, tdtd->private)) < 0) - return (rc); - else if (rc == 0) - descend = 0; - } - - if (descend) { - if ((descender = tddescenders[this->t_type]) != NULL && - (rc = descender(this, tdtd)) < 0) - return (rc); - - if ((travcb = tdtd->postops[this->t_type]) != NULL && - (rc = travcb(this, thisp, tdtd->private)) < 0) - return (rc); - } - - return (1); -} - -int -iitraverse_td(iidesc_t *ii, tdtrav_data_t *tdtd) -{ - int i, rc; - - if ((rc = tdtraverse(ii->ii_dtype, &ii->ii_dtype, tdtd)) < 0) - return (rc); - - for (i = 0; i < ii->ii_nargs; i++) { - if ((rc = tdtraverse(ii->ii_args[i], &ii->ii_args[i], - tdtd)) < 0) - return (rc); - } - - return (1); -} - -int -iitraverse(iidesc_t *ii, int *vgenp, tdtrav_cb_f *firstops, tdtrav_cb_f *preops, - tdtrav_cb_f *postops, void *private) -{ - tdtrav_data_t tdtd; - - tdtrav_init(&tdtd, vgenp, firstops, preops, postops, private); - - return (iitraverse_td(ii, &tdtd)); -} - -int -iitraverse_hash(hash_t *iihash, int *vgenp, tdtrav_cb_f *firstops, - tdtrav_cb_f *preops, tdtrav_cb_f *postops, void *private) -{ - tdtrav_data_t tdtd; - - tdtrav_init(&tdtd, vgenp, firstops, preops, postops, private); - - return (hash_iter(iihash, (int (*)())iitraverse_td, &tdtd)); -} diff --git a/usr/src/tools/ctf/cvt/traverse.h b/usr/src/tools/ctf/cvt/traverse.h deleted file mode 100644 index 0f8396f308..0000000000 --- a/usr/src/tools/ctf/cvt/traverse.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _TRAVERSE_H -#define _TRAVERSE_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Routines used to traverse tdesc trees, invoking user-supplied callbacks - * as the tree is traversed. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "ctftools.h" - -typedef int (*tdtrav_cb_f)(tdesc_t *, tdesc_t **, void *); - -typedef struct tdtrav_data { - int vgen; - - tdtrav_cb_f *firstops; - tdtrav_cb_f *preops; - tdtrav_cb_f *postops; - - void *private; -} tdtrav_data_t; - -void tdtrav_init(tdtrav_data_t *, int *, tdtrav_cb_f *, tdtrav_cb_f *, - tdtrav_cb_f *, void *); -int tdtraverse(tdesc_t *, tdesc_t **, tdtrav_data_t *); - -int iitraverse(iidesc_t *, int *, tdtrav_cb_f *, tdtrav_cb_f *, tdtrav_cb_f *, - void *); -int iitraverse_hash(hash_t *, int *, tdtrav_cb_f *, tdtrav_cb_f *, - tdtrav_cb_f *, void *); -int iitraverse_td(iidesc_t *ii, tdtrav_data_t *); - -int tdtrav_assert(tdesc_t *, tdesc_t **, void *); - -#ifdef __cplusplus -} -#endif - -#endif /* _TRAVERSE_H */ diff --git a/usr/src/tools/ctf/cvt/util.c b/usr/src/tools/ctf/cvt/util.c deleted file mode 100644 index 799ca1279c..0000000000 --- a/usr/src/tools/ctf/cvt/util.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Utility functions - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <libelf.h> -#include <gelf.h> -#include <errno.h> -#include <stdarg.h> -#include <pthread.h> -#include <unistd.h> -#include <sys/param.h> - -#include "ctftools.h" -#include "memory.h" - -static void (*terminate_cleanup)() = NULL; - -/* returns 1 if s1 == s2, 0 otherwise */ -int -streq(const char *s1, const char *s2) -{ - if (s1 == NULL) { - if (s2 != NULL) - return (0); - } else if (s2 == NULL) - return (0); - else if (strcmp(s1, s2) != 0) - return (0); - - return (1); -} - -int -findelfsecidx(Elf *elf, const char *file, const char *tofind) -{ - Elf_Scn *scn = NULL; - GElf_Ehdr ehdr; - GElf_Shdr shdr; - - if (gelf_getehdr(elf, &ehdr) == NULL) - elfterminate(file, "Couldn't read ehdr"); - - while ((scn = elf_nextscn(elf, scn)) != NULL) { - char *name; - - if (gelf_getshdr(scn, &shdr) == NULL) { - elfterminate(file, - "Couldn't read header for section %d", - elf_ndxscn(scn)); - } - - if ((name = elf_strptr(elf, ehdr.e_shstrndx, - (size_t)shdr.sh_name)) == NULL) { - elfterminate(file, - "Couldn't get name for section %d", - elf_ndxscn(scn)); - } - - if (strcmp(name, tofind) == 0) - return (elf_ndxscn(scn)); - } - - return (-1); -} - -size_t -elf_ptrsz(Elf *elf) -{ - GElf_Ehdr ehdr; - - if (gelf_getehdr(elf, &ehdr) == NULL) { - terminate("failed to read ELF header: %s\n", - elf_errmsg(-1)); - } - - if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) - return (4); - else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) - return (8); - else - terminate("unknown ELF class %d\n", ehdr.e_ident[EI_CLASS]); - - /*NOTREACHED*/ - return (0); -} - -/*PRINTFLIKE2*/ -static void -whine(char *type, char *format, va_list ap) -{ - int error = errno; - - fprintf(stderr, "%s: %s: ", type, progname); - vfprintf(stderr, format, ap); - - if (format[strlen(format) - 1] != '\n') - fprintf(stderr, ": %s\n", strerror(error)); -} - -void -set_terminate_cleanup(void (*cleanup)()) -{ - terminate_cleanup = cleanup; -} - -/*PRINTFLIKE1*/ -void -terminate(char *format, ...) -{ - va_list ap; - - va_start(ap, format); - whine("ERROR", format, ap); - va_end(ap); - - if (terminate_cleanup) - terminate_cleanup(); - - if (getenv("CTF_ABORT_ON_TERMINATE") != NULL) - abort(); - exit(1); -} - -/*PRINTFLIKE1*/ -void -aborterr(char *format, ...) -{ - va_list ap; - - va_start(ap, format); - whine("ERROR", format, ap); - va_end(ap); - - abort(); -} - -/*PRINTFLIKE1*/ -void -warning(char *format, ...) -{ - va_list ap; - - va_start(ap, format); - whine("WARNING", format, ap); - va_end(ap); - - if (debug_level >= 3) - terminate("Termination due to warning\n"); -} - -/*PRINTFLIKE2*/ -void -vadebug(int level, char *format, va_list ap) -{ - if (level > debug_level) - return; - - (void) fprintf(DEBUG_STREAM, "DEBUG: "); - (void) vfprintf(DEBUG_STREAM, format, ap); - fflush(DEBUG_STREAM); -} - -/*PRINTFLIKE2*/ -void -debug(int level, char *format, ...) -{ - va_list ap; - - if (level > debug_level) - return; - - va_start(ap, format); - (void) vadebug(level, format, ap); - va_end(ap); -} - -char * -mktmpname(const char *origname, const char *suffix) -{ - char *newname; - - newname = xmalloc(strlen(origname) + strlen(suffix) + 1); - (void) strcpy(newname, origname); - (void) strcat(newname, suffix); - return (newname); -} - -/*PRINTFLIKE2*/ -void -elfterminate(const char *file, const char *fmt, ...) -{ - static char msgbuf[BUFSIZ]; - va_list ap; - - va_start(ap, fmt); - vsnprintf(msgbuf, sizeof (msgbuf), fmt, ap); - va_end(ap); - - terminate("%s: %s: %s\n", file, msgbuf, elf_errmsg(-1)); -} - -const char * -tdesc_name(tdesc_t *tdp) -{ - return (tdp->t_name == NULL ? "(anon)" : tdp->t_name); -} |