This commit was generated by cvs2svn to compensate for changes in r178481,

which included commits to RCS files with non-trunk default branches.
This commit is contained in:
John Birrell 2008-04-25 09:07:28 +00:00
commit 1673e4046d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=178482
40 changed files with 13733 additions and 0 deletions

View File

@ -0,0 +1,72 @@
/*
* 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 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _CTF_HEADERS_H
#define _CTF_HEADERS_H
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Because the ON tools are executed on the system where they are built,
* the tools need to include the headers installed on the build system,
* rather than those in the ON source tree. However, some of the headers
* required by the tools are part of the ON source tree, but not delivered
* as part of Solaris. These include the following:
*
* $(SRC)/lib/libctf/common/libctf.h
* $(SRC)/uts/common/sys/ctf_api.h
* $(SRC)/uts/common/sys/ctf.h
*
* These headers get installed in the proto area in the build environment
* under $(ROOT)/usr/include and $(ROOT)/usr/include/sys. Though these
* headers are not part of the release, in releases including and prior to
* Solaris 9, they did get installed on the build system via bfu. Therefore,
* we can not simply force the order of inclusion with -I/usr/include first
* in Makefile.ctf because we might actually get downlevel versions of the
* ctf headers. Depending on the order of the -I includes, we can also have
* a problem with mismatched headers when building the ctf tools with some
* headers getting pulled in from /usr/include and others from
* $(SRC)/uts/common/sys.
*
* To address the problem, we have done two things:
* 1) Created this header with a specific order of inclusion for the
* ctf headers. Because the <libctf.h> header includes <sys/ctf_api.h>
* which in turn includes <sys/ctf.h> we need to include these in
* reverse order to guarantee that we get the correct versions of
* the headers.
* 2) In $(SRC)/tools/ctf/Makefile.ctf, we order the -I includes such
* that we first search the directories where the ctf headers
* live, followed by /usr/include, followed by $(SRC)/uts/common.
* This last -I include is needed in order to prevent a build failure
* when <sys/ctf_api.h> is included via a nested #include rather than
* an explicit path #include.
*/
#include <uts/common/sys/ctf.h>
#include <uts/common/sys/ctf_api.h>
#include <lib/libctf/common/libctf.h>
#endif /* _CTF_HEADERS_H */

View File

@ -0,0 +1,228 @@
/*
* 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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Routines for manipulating linked lists
*/
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "list.h"
#include "memory.h"
struct list {
void *l_data;
struct list *l_next;
};
/* Add an element to a list */
void
list_add(list_t **list, void *data)
{
list_t *le;
le = xmalloc(sizeof (list_t));
le->l_data = data;
le->l_next = *list;
*list = le;
}
/* Add an element to a sorted list */
void
slist_add(list_t **list, void *data, int (*cmp)(void *, void *))
{
list_t **nextp;
for (nextp = list; *nextp; nextp = &((*nextp)->l_next)) {
if (cmp((*nextp)->l_data, data) > 0)
break;
}
list_add(nextp, data);
}
/*ARGSUSED2*/
static int
list_defcmp(void *d1, void *d2, void *private __unused)
{
return (d1 != d2);
}
void *
list_remove(list_t **list, void *data, int (*cmp)(void *, void *, void *),
void *private)
{
list_t *le, **le2;
void *led;
if (!cmp)
cmp = list_defcmp;
for (le = *list, le2 = list; le; le2 = &le->l_next, le = le->l_next) {
if (cmp(le->l_data, data, private) == 0) {
*le2 = le->l_next;
led = le->l_data;
free(le);
return (led);
}
}
return (NULL);
}
void
list_free(list_t *list, void (*datafree)(void *, void *), void *private)
{
list_t *le;
while (list) {
le = list;
list = list->l_next;
if (le->l_data && datafree)
datafree(le->l_data, private);
free(le);
}
}
/*
* This iterator is specifically designed to tolerate the deletion of the
* node being iterated over.
*/
int
list_iter(list_t *list, int (*func)(void *, void *), void *private)
{
list_t *lnext;
int cumrc = 0;
int cbrc;
while (list) {
lnext = list->l_next;
if ((cbrc = func(list->l_data, private)) < 0)
return (cbrc);
cumrc += cbrc;
list = lnext;
}
return (cumrc);
}
/*ARGSUSED*/
static int
list_count_cb(void *data __unused, void *private __unused)
{
return (1);
}
int
list_count(list_t *list)
{
return (list_iter(list, list_count_cb, NULL));
}
int
list_empty(list_t *list)
{
return (list == NULL);
}
void *
list_find(list_t *list, void *tmpl, int (*cmp)(void *, void *))
{
for (; list; list = list->l_next) {
if (cmp(list->l_data, tmpl) == 0)
return (list->l_data);
}
return (NULL);
}
void *
list_first(list_t *list)
{
return (list ? list->l_data : NULL);
}
void
list_concat(list_t **list1, list_t *list2)
{
list_t *l, *last;
for (l = *list1, last = NULL; l; last = l, l = l->l_next)
continue;
if (last == NULL)
*list1 = list2;
else
last->l_next = list2;
}
/*
* Merges two sorted lists. Equal nodes (as determined by cmp) are retained.
*/
void
slist_merge(list_t **list1p, list_t *list2, int (*cmp)(void *, void *))
{
list_t *list1, *next2;
list_t *last1 = NULL;
if (*list1p == NULL) {
*list1p = list2;
return;
}
list1 = *list1p;
while (list2 != NULL) {
if (cmp(list1->l_data, list2->l_data) > 0) {
next2 = list2->l_next;
if (last1 == NULL) {
/* Insert at beginning */
*list1p = last1 = list2;
list2->l_next = list1;
} else {
list2->l_next = list1;
last1->l_next = list2;
last1 = list2;
}
list2 = next2;
} else {
last1 = list1;
list1 = list1->l_next;
if (list1 == NULL) {
/* Add the rest to the end of list1 */
last1->l_next = list2;
list2 = NULL;
}
}
}
}

View File

@ -0,0 +1,58 @@
/*
* 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-2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _LIST_H
#define _LIST_H
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Routines for manipulating linked lists
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct list list_t;
void list_add(list_t **, void *);
void slist_add(list_t **, void *, int (*)(void *, void *));
void *list_remove(list_t **, void *, int (*)(void *, void *, void *), void *);
void list_free(list_t *, void (*)(void *, void *), void *);
void *list_find(list_t *, void *, int (*)(void *, void *));
void *list_first(list_t *);
int list_iter(list_t *, int (*)(void *, void *), void *);
int list_count(list_t *);
int list_empty(list_t *);
void list_concat(list_t **, list_t *);
void slist_merge(list_t **, list_t *, int (*)(void *, void *));
#ifdef __cplusplus
}
#endif
#endif /* _LIST_H */

View File

@ -0,0 +1,103 @@
/*
* 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-2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Routines for memory management
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "memory.h"
static void
memory_bailout(void)
{
(void) fprintf(stderr, "Out of memory\n");
exit(1);
}
void *
xmalloc(size_t size)
{
void *mem;
if ((mem = malloc(size)) == NULL)
memory_bailout();
return (mem);
}
void *
xcalloc(size_t size)
{
void *mem;
mem = xmalloc(size);
bzero(mem, size);
return (mem);
}
char *
xstrdup(const char *str)
{
char *newstr;
if ((newstr = strdup(str)) == NULL)
memory_bailout();
return (newstr);
}
char *
xstrndup(char *str, size_t len)
{
char *newstr;
if ((newstr = malloc(len + 1)) == NULL)
memory_bailout();
(void) strncpy(newstr, str, len);
newstr[len] = '\0';
return (newstr);
}
void *
xrealloc(void *ptr, size_t size)
{
void *mem;
if ((mem = realloc(ptr, size)) == NULL)
memory_bailout();
return (mem);
}

View File

@ -0,0 +1,52 @@
/*
* 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-2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _MEMORY_H
#define _MEMORY_H
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Routines for memory management
*/
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
void *xmalloc(size_t);
void *xcalloc(size_t);
char *xstrdup(const char *);
char *xstrndup(char *, size_t);
void *xrealloc(void *, size_t);
#ifdef __cplusplus
}
#endif
#endif /* _MEMORY_H */

View File

@ -0,0 +1,62 @@
/*
* 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"
#include <sys/types.h>
#include <string.h>
#include "symbol.h"
int
ignore_symbol(GElf_Sym *sym, const char *name)
{
uchar_t type = GELF_ST_TYPE(sym->st_info);
/*
* As an optimization, we do not output function or data object
* records for undefined or anonymous symbols.
*/
if (sym->st_shndx == SHN_UNDEF || sym->st_name == 0)
return (1);
/*
* _START_ and _END_ are added to the symbol table by the
* linker, and will never have associated type information.
*/
if (strcmp(name, "_START_") == 0 || strcmp(name, "_END_") == 0)
return (1);
/*
* Do not output records for absolute-valued object symbols
* that have value zero. The compiler insists on generating
* things like this for __fsr_init_value settings, etc.
*/
if (type == STT_OBJECT && sym->st_shndx == SHN_ABS &&
sym->st_value == 0)
return (1);
return (0);
}

View File

@ -0,0 +1,44 @@
/*
* 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 _SYMBOL_H
#define _SYMBOL_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <gelf.h>
#ifdef __cplusplus
extern "C" {
#endif
int ignore_symbol(GElf_Sym *sym, const char *name);
#ifdef __cplusplus
}
#endif
#endif /* _SYMBOL_H */

View File

@ -0,0 +1,104 @@
/*
* 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) 1998-2001 by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <errno.h>
#include "utils.h"
/*LINTLIBRARY*/
static const char *pname;
#pragma init(getpname)
const char *
getpname(void)
{
const char *p, *q;
if (pname != NULL)
return (pname);
if ((p = getexecname()) != NULL)
q = strrchr(p, '/');
else
q = NULL;
if (q == NULL)
pname = p;
else
pname = q + 1;
return (pname);
}
void
vwarn(const char *format, va_list alist)
{
int err = errno;
if (pname != NULL)
(void) fprintf(stderr, "%s: ", pname);
(void) vfprintf(stderr, format, alist);
if (strchr(format, '\n') == NULL)
(void) fprintf(stderr, ": %s\n", strerror(err));
}
/*PRINTFLIKE1*/
void
warn(const char *format, ...)
{
va_list alist;
va_start(alist, format);
vwarn(format, alist);
va_end(alist);
}
void
vdie(const char *format, va_list alist)
{
vwarn(format, alist);
exit(E_ERROR);
}
/*PRINTFLIKE1*/
void
die(const char *format, ...)
{
va_list alist;
va_start(alist, format);
vdie(format, alist);
va_end(alist);
}

View File

@ -0,0 +1,53 @@
/*
* 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) 1998-2001 by Sun Microsystems, Inc.
* All rights reserved.
*/
#ifndef _UTILS_H
#define _UTILS_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdarg.h>
#ifdef __cplusplus
extern "C" {
#endif
#define E_SUCCESS 0 /* Exit status for success */
#define E_ERROR 1 /* Exit status for error */
#define E_USAGE 2 /* Exit status for usage error */
extern void vwarn(const char *, va_list);
extern void warn(const char *, ...);
extern void vdie(const char *, va_list);
extern void die(const char *, ...);
extern const char *getpname(void);
#ifdef __cplusplus
}
#endif
#endif /* _UTILS_H */

View File

@ -0,0 +1,215 @@
/*
* 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, void *arg)
{
alist_el_t *el = arg;
uintptr_t num = (uintptr_t)el->ale_name;
return (num % nbuckets);
}
static int
alist_cmp(void *arg1, void *arg2)
{
alist_el_t *el1 = arg1;
alist_el_t *el2 = arg2;
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,
alist_hash, alist_cmp));
}
static void
alist_free_cb(void *arg1, void *arg2)
{
alist_el_t *el = arg1;
alist_t *alist = arg2;
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, 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, *retx;
void *ret;
template.ale_name = name;
if (!hash_find(alist->al_elements, &template, &ret))
return (0);
if (value) {
retx = ret;
*value = retx->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(void *arg1, void *arg2)
{
alist_el_t *el = arg1;
alist_iter_data_t *aid = arg2;
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, 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("%5lu ", (ulong_t)key);
else
printf("%s\n", (char *)key);
printf("Value: ");
if (alist_def_print_cb_value_int == 1)
printf("%5lu\n", (ulong_t)value);
else
printf("%s\n", (char *)key);
return (1);
}
static int
alist_dump_cb(void *node, void *private)
{
int (*printer)(void *, void *) = 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));
}

View File

@ -0,0 +1,57 @@
/*
* 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);
int alist_dump(alist_t *, int (*)(void *, void *));
#ifdef __cplusplus
}
#endif
#endif /* _ASSOC_H */

View File

@ -0,0 +1,92 @@
/*
* 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>
#if defined(sun)
#include <synch.h>
#endif
#include <stdio.h>
#include "barrier.h"
void
barrier_init(barrier_t *bar, int nthreads)
{
pthread_mutex_init(&bar->bar_lock, NULL);
#if defined(sun)
sema_init(&bar->bar_sem, 0, USYNC_THREAD, NULL);
#else
sem_init(&bar->bar_sem, 0, 0);
#endif
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);
#if defined(sun)
sema_wait(&bar->bar_sem);
#else
sem_wait(&bar->bar_sem);
#endif
return (0);
} else {
int i;
/* reset for next use */
bar->bar_numin = 0;
for (i = 1; i < bar->bar_nthr; i++)
#if defined(sun)
sema_post(&bar->bar_sem);
#else
sem_post(&bar->bar_sem);
#endif
pthread_mutex_unlock(&bar->bar_lock);
return (1);
}
}

View File

@ -0,0 +1,62 @@
/*
* 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.
*/
#if defined(sun)
#include <synch.h>
#else
#include <semaphore.h>
typedef sem_t sema_t;
#endif
#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 */

View File

@ -0,0 +1,92 @@
/*
* 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);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,263 @@
/*
* 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"
/*
* 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 char *infile = NULL;
static const char *outfile = NULL;
static int dynsym;
static void
usage(void)
{
(void) fprintf(stderr,
"Usage: %s [-gis] -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 !defined(__FreeBSD__)
if (!outfile) {
fprintf(stderr, "Removing %s\n", infile);
unlink(infile);
}
#endif
}
static void
handle_sig(int sig)
{
terminate("Caught signal %d - exiting\n", sig);
}
static int
file_read(tdata_t *td, char *filename, int ignore_non_c)
{
typedef int (*reader_f)(tdata_t *, Elf *, char *);
static 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;
const char *label = NULL;
int verbose = 0;
int ignore_non_c = 0;
int keep_stabs = 0;
int c;
#if defined(sun)
sighold(SIGINT);
sighold(SIGQUIT);
sighold(SIGTERM);
#endif
progname = basename(argv[0]);
if (getenv("CTFCONVERT_DEBUG_LEVEL"))
debug_level = atoi(getenv("CTFCONVERT_DEBUG_LEVEL"));
if (getenv("CTFCONVERT_DEBUG_PARSE"))
debug_parse = atoi(getenv("CTFCONVERT_DEBUG_PARSE"));
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 'g':
keep_stabs = CTF_KEEP_STABS;
break;
case 'v':
verbose = 1;
break;
default:
usage();
exit(2);
}
}
if (getenv("STRIPSTABS_KEEP_STABS") != NULL)
keep_stabs = CTF_KEEP_STABS;
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);
#if defined(sun)
sigset(SIGINT, handle_sig);
sigset(SIGQUIT, handle_sig);
sigset(SIGTERM, handle_sig);
#else
signal(SIGINT, handle_sig);
signal(SIGQUIT, handle_sig);
signal(SIGTERM, handle_sig);
#endif
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 | keep_stabs);
} else {
char *tmpname = mktmpname(infile, ".ctf");
write_ctf(mstrtd, infile, tmpname, dynsym | keep_stabs);
if (rename(tmpname, infile) != 0)
terminate("Couldn't rename temp file %s", tmpname);
free(tmpname);
}
return (0);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,89 @@
/*
* 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-2003 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;
barrier_t wq_bar1;
barrier_t wq_bar2;
} workqueue_t;
#ifdef __cplusplus
}
#endif
#endif /* _CTFMERGE_H */

View File

@ -0,0 +1,453 @@
/*
* 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
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* 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>
#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 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 (*)(void *, 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(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 */
#define CTF_KEEP_STABS 0x8 /* keep .stabs sections */
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 *, char *);
/* dwarf.c */
int dw_read(tdata_t *, Elf *, 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 *, const 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(const char *, ...);
void aborterr(const char *, ...);
void set_terminate_cleanup(void (*)(void));
void elfterminate(const char *, const char *, ...);
void warning(const char *, ...);
void vadebug(int, const char *, va_list);
void debug(int, const char *, ...);
void watch_dump(int);
void watch_set(void *, int);
#ifdef __cplusplus
}
#endif
#endif /* _CTFTOOLS_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,153 @@
/*
* 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);
}

View File

@ -0,0 +1,54 @@
/*
* 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 */

View File

@ -0,0 +1,279 @@
/*
* 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)
{
const char *strs[2] = { "as", "fdbuffer" };
const char *mems[2] = { "a_objectdir", "fd_shadow" };
const char *acts[2] = { "vnode", "page" };
const 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 < (int) (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)
{
const char *strs[2] = { "vmem", "id_space" };
const 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 < (int) (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(void *arg1, void *arg2)
{
iidesc_t *iidesc = arg1;
struct match *match = arg2;
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, char const *name)
{
struct match match = { NULL, name };
iter_iidescs_by_name(td, name, 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);
}

View File

@ -0,0 +1,291 @@
/*
* 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 *, void *);
void *hd_key;
void *hd_private;
void *hd_ret;
};
static int
hash_def_hash(int nbuckets, void *arg)
{
uintptr_t data = (uintptr_t) arg;
return (data % nbuckets);
}
static int
hash_def_cmp(void *d1, void *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 : hash_def_hash;
hash->h_cmp = cmp ? cmp : 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, void *arg)
{
hash_t *hash = arg;
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,
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, void *arg)
{
struct hash_data *hd = arg;
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], hash_find_list_cb,
&hd));
}
/* stop on first match */
static int
hash_find_first_cb(void *node, void *arg)
{
struct hash_data *hd = arg;
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, 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);
}

View File

@ -0,0 +1,59 @@
/*
* 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 */

View File

@ -0,0 +1,197 @@
/*
* 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 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(void *arg1, void *arg2)
{
iidesc_t *src = arg1;
iidesc_find_t *find = arg2;
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, 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, NULL);
return;
}
hash_add(hash, new);
}
void
iter_iidescs_by_name(tdata_t *td, char const *name,
int (*func)(void *, void *), void *data)
{
iidesc_t tmpdesc;
bzero(&tmpdesc, sizeof(tmpdesc));
tmpdesc.ii_name = xstrdup(name);
(void) hash_match(td->td_iihash, &tmpdesc, func, data);
free(tmpdesc.ii_name);
}
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(void *arg, void *private __unused)
{
iidesc_t *idp = arg;
if (idp->ii_name)
free(idp->ii_name);
if (idp->ii_nargs)
free(idp->ii_args);
if (idp->ii_owner)
free(idp->ii_owner);
free(idp);
}
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));
}

View File

@ -0,0 +1,419 @@
/*
* 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':
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 = NULL;
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 __unused, 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);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,757 @@
/*
* 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 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 __unused, 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(void *arg1, void *arg2)
{
iidesc_t *iidesc = arg1;
iidesc_match_t *match = arg2;
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;
default:
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,
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 *tmpfile1 = NULL;
GElf_Sym tmpsym;
int candidate = 0;
int i;
tmpsym.st_info = 0;
tmpsym.st_name = 0;
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;
tmpfile1 = curfile;
tmpsym = sym;
continue;
}
*curfilep = curfile;
*retsym = sym;
return (1);
}
if (candidate) {
*curfilep = tmpfile1;
*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 keep_stabs = (flags & CTF_KEEP_STABS);
int *secxlate;
int srcidx, dstidx;
int curnmoff = 0;
int changing = 0;
int pad;
int i;
if (gelf_newehdr(dst, gelf_getclass(src)) == NULL)
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) == NULL)
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 shdr1;
char *sname;
gelf_getshdr(scn, &shdr1);
sname = elf_strptr(src, sehdr.e_shstrndx, shdr1.sh_name);
if (sname == NULL) {
elfterminate(srcname, "Can't find string at %u",
shdr1.sh_name);
}
if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) {
secxlate[srcidx] = -1;
} else if (!keep_stabs &&
(strncmp(sname, ".stab", 5) == 0 ||
strncmp(sname, ".debug", 6) == 0 ||
strncmp(sname, ".rel.debug", 10) == 0 ||
strncmp(sname, ".rela.debug", 11) == 0)) {
secxlate[srcidx] = -1;
} else if (dynsym && shdr1.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 !defined(sun)
if (gelf_update_shdr(dscn, &shdr) == 0)
elfterminate(dstname, "Cannot update sect %s", sname);
#endif
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);
#if defined(sun)
bcopy(sdata, ddata, sizeof (Elf_Data));
#else
/*
* FreeBSD's Elf_Data has private fields which the
* elf_* routines manage. Simply copying the
* entire structure corrupts the data. So we need
* to copy the public fields explictly.
*/
ddata->d_align = sdata->d_align;
ddata->d_off = sdata->d_off;
ddata->d_size = sdata->d_size;
ddata->d_type = sdata->d_type;
ddata->d_version = sdata->d_version;
#endif
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;
if (gelf_getsym(ddata, i, &sym) == NULL)
printf("Could not get symbol %d\n",i);
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 !defined(sun)
if (ddata->d_buf == NULL) {
ddata->d_buf = xmalloc(shdr.sh_size);
bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
}
#endif
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;
ddata->d_off = 0;
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);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,381 @@
/*
* 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 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"
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 __unused)
{
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 __unused)
{
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, 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, 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, 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) {
if (iidescp)
iidesc_free(iidescp, NULL);
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, NULL);
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);
}

View File

@ -0,0 +1,112 @@
/*
* 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);
}

View File

@ -0,0 +1,53 @@
/*
* 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 */

View File

@ -0,0 +1,258 @@
/*
* 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)(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");
}
}
}

View File

@ -0,0 +1,69 @@
/*
* 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 (*)(void *, size_t, void *), void *);
extern void strtab_print(const strtab_t *);
#ifdef __cplusplus
}
#endif
#endif /* _STRTAB_H */

View File

@ -0,0 +1,488 @@
/*
* 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 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.
*/
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));
}
#if defined(sun)
/*ARGSUSED1*/
static int
tdesc_print(void *data, void *private __unused)
{
tdesc_t *tdp = data;
printf("%7d %s\n", tdp->t_id, tdesc_name(tdp));
return (1);
}
#endif
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 *arg, void *private __unused)
{
tdesc_t *tdp = arg;
if (tdp->t_name)
free(tdp->t_name);
if (free_cbs[tdp->t_type])
free_cbs[tdp->t_type](tdp);
free(tdp);
return;
}
void
tdesc_free(tdesc_t *tdp)
{
tdesc_free_cb(tdp, NULL);
}
static int
tdata_label_cmp(void *arg1, void *arg2)
{
labelent_t *le1 = arg1;
labelent_t *le2 = arg2;
return (le1->le_idx - le2->le_idx);
}
void
tdata_label_add(tdata_t *td, const 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, 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(void *arg1, void *arg2)
{
labelent_t *le = arg1;
labelent_t *tmpl = arg2;
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,
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(void *arg, void *private __unused)
{
labelent_t *le = arg;
if (le->le_name)
free(le->le_name);
free(le);
}
void
tdata_label_free(tdata_t *td)
{
list_free(td->td_labels, 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, 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 __unused, 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,
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);
}

View File

@ -0,0 +1,226 @@
/*
* 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[])(tdesc_t *, tdtrav_data_t *);
tdtrav_cb_f tdnops[];
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 < (int) 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 __unused, tdesc_t **nodep __unused, void *private __unused)
{
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)(tdesc_t *, tdtrav_data_t *);
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(void *arg1, void *arg2)
{
iidesc_t *ii = arg1;
tdtrav_data_t *tdtd = arg2;
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, iitraverse_td, &tdtd));
}

View File

@ -0,0 +1,71 @@
/*
* 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(void *, void *);
int tdtrav_assert(tdesc_t *, tdesc_t **, void *);
#ifdef __cplusplus
}
#endif
#endif /* _TRAVERSE_H */

View File

@ -0,0 +1,283 @@
/*
* 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)(void) = 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(const char *type, const 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)(void))
{
terminate_cleanup = cleanup;
}
/*PRINTFLIKE1*/
void
terminate(const 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();
#if defined(__FreeBSD__)
/*
* For the time being just output the termination message, but don't
* return an exit status that would cause the build to fail. We need
* to get as much stuff built as possible before going back and
* figuring out what is wrong with certain files.
*/
exit(0);
#else
exit(1);
#endif
}
/*PRINTFLIKE1*/
void
aborterr(const char *format, ...)
{
va_list ap;
va_start(ap, format);
whine("ERROR", format, ap);
va_end(ap);
#if defined(sun)
abort();
#else
exit(0);
#endif
}
/*PRINTFLIKE1*/
void
warning(const 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, const 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, const 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);
}
char *watch_address = NULL;
int watch_length = 0;
void
watch_set(void *addr, int len)
{
watch_address = addr;
watch_length = len;
}
void
watch_dump(int v)
{
char *p = watch_address;
int i;
if (watch_address == NULL || watch_length == 0)
return;
printf("%d: watch %p len %d\n",v,watch_address,watch_length);
for (i = 0; i < watch_length; i++) {
if (*p >= 0x20 && *p < 0x7f) {
printf(" %c",*p++ & 0xff);
} else {
printf(" %02x",*p++ & 0xff);
}
}
printf("\n");
}

File diff suppressed because it is too large Load Diff