* ========== Copyright Header Begin ==========================================
* Hypervisor Software File: stabs.c
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* - Do no alter or remove copyright notices
* - Redistribution and use of this software in source and binary forms, with
* or without modification, are permitted provided that the following
* - Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of Sun Microsystems, Inc. or the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
* MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
* OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
* FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* You acknowledge that this software is not designed, licensed or
* intended for use in the design, construction, operation or maintenance of
* ========== Copyright Header End ============================================
* 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]
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
#pragma ident "@(#)stabs.c 1.2 07/06/07 SMI"
static struct tdesc
*hash_table
[BUCKETS
];
static struct tdesc
*name_table
[BUCKETS
];
static char *get_line(void);
static void parseline(char *cp
);
static char *soudef(char *cp
, enum type type
, struct tdesc
**rtdp
);
static void enumdef(char *cp
, struct tdesc
**rtdp
);
static int compute_sum(char *w
);
static struct tdesc
*lookup(int h
);
static char *number(char *cp
, int *n
);
static char *name(char *cp
, char **w
);
static char *id(char *cp
, int *h
);
static char *offsize(char *cp
, struct mlist
*mlp
);
static char *whitesp(char *cp
);
static void addhash(struct tdesc
*tdp
, int num
);
static void tagadd(char *w
, int h
, struct tdesc
*tdp
);
static void tagdecl(char *cp
, struct tdesc
**rtdp
, int h
, char *w
);
static char *tdefdecl(char *cp
, int h
, struct tdesc
**rtdp
);
static char *intrinsic(char *cp
, struct tdesc
**rtdp
, intr_flags_t flags
);
static char *arraydef(char *cp
, struct tdesc
**rtdp
);
static int line_number
= 0;
static int debug_line
= 0;
static char linebuf
[MAXLINE
];
debug(int level
, char *cp
, char *fmt
, ...)
for (i
= 0; i
< 30; i
++) {
(void) sprintf(buf
, "%s [cp='%s']\n", fmt
, tmp
);
(void) vfprintf(stderr
, buf
, ap
);
/* Report unexpected syntax in stabs. */
char *who
, /* what function, or part thereof, is reporting */
char *what
, /* what was expected */
char *where
) /* where we were in the line of input */
fprintf(stderr
, "%s, input line %d: expecting \"%s\" at \"%s\"\n",
who
, line_number
, what
, where
);
/* Read a line from stdin into linebuf and increment line_number. */
char *cp
= fgets(linebuf
, MAXLINE
, stdin
);
/* For debugging, you can set debug_line to a line to stop on. */
if (line_number
== debug_line
) {
fprintf(stderr
, "Hit debug line number %d\n", line_number
);
/* Get the continuation of the current input line. */
fprintf(stderr
, "expecting continuation line, "
/* Skip to the quoted stuff. */
for (i
= 0; i
< BUCKETS
; i
++) {
* get a line at a time from the .s stabs file and parse.
while ((cp
= get_line()) != NULL
)
* Parse each line of the .s file (stabs entry) gather meaningful information
* like name of type, size, offsets of fields etc.
* Look for lines of the form
* The part in '"' is then parsed.
debug(2, cp
, "parseline");
if (strncmp(cp
, ".stabs", STLEN
) != 0)
* name:type variable (ignored)
* name:Ttype struct tag define
case 'T': /* struct, union, enum */
* The type id and definition follow.
if (ntdp
== NULL
) { /* if that type isn't defined yet */
if (*cp
++ != '=') /* better be defining it now */
expected("parseline/'0-9'", "=", cp
- 1);
cp
= tdefdecl(cp
, h
, &tdp
);
addhash(tdp
, h
); /* for *(x,y) types */
} else { /* that type is already defined */
tdp
= malloc(sizeof (*tdp
));
tdp
->name
= (w
!= NULL
) ? strdup(w
) : NULL
;
addhash(tdp
, h
); /* for *(x,y) types */
debug(3, NULL
, " %s defined as %s(%d)", w
,
(ntdp
->name
!= NULL
) ? ntdp
->name
: "anon", h
);
} else if (*cp
++ != '=') {
expected("parseline", "=", cp
- 1);
* Check if we have this node in the hash table already
struct tdesc
*tdp
= hash_table
[hash
];
for (c
= *cp
++; isspace(c
); c
= *cp
++)
else if (isalpha(c
) || c
== '_') {
for (c
= *cp
++; isalnum(c
) || c
== ' ' || c
== '_'; c
= *cp
++)
*n
= (int)strtol(cp
, &next
, 10);
expected("number", "<number>", cp
);
if (*cp
== '(') { /* SunPro style */
expected("id", ",", cp
- 1);
expected("id", ")", cp
- 1);
} else if (isdigit(*cp
)) { /* gcc style */
expected("id", "(/0-9", cp
);
tagadd(char *w
, int h
, struct tdesc
*tdp
)
fprintf(stderr
, "duplicate entry\n");
fprintf(stderr
, "old: %s %d %d %d\n",
otdp
->name
? otdp
->name
: "NULL",
otdp
->type
, otdp
->id
/ 1000, otdp
->id
% 1000);
fprintf(stderr
, "new: %s %d %d %d\n",
tdp
->name
? tdp
->name
: "NULL",
tdp
->type
, tdp
->id
/ 1000, tdp
->id
% 1000);
tagdecl(char *cp
, struct tdesc
**rtdp
, int h
, char *w
)
debug(1, NULL
, "tagdecl: declaring '%s'", w
? w
: "(anon)");
if ((*rtdp
= lookup(h
)) != NULL
) {
if ((*rtdp
)->name
!= NULL
&&
strcmp((*rtdp
)->name
, w
) != 0) {
tdp
= malloc(sizeof (*tdp
));
addhash(tdp
, h
); /* for *(x,y) types */
debug(3, NULL
, " %s defined as %s(%d)", w
,
((*rtdp
)->name
!= NULL
) ?
(*rtdp
)->name
: "anon", h
);
} else if ((*rtdp
)->name
== NULL
) {
*rtdp
= malloc(sizeof (**rtdp
));
soudef(cp
, STRUCT
, rtdp
);
expected("tagdecl", "<tag type s/u/e>", cp
- 1);
tdefdecl(char *cp
, int h
, struct tdesc
**rtdp
)
debug(3, cp
, "tdefdecl h=%d", h
);
if (c
!= 's' && c
!= 'u')
expected("tdefdecl/b", "[su]", cp
- 1);
flags
= (c
== 'u') ? Intr_unsigned
: Intr_signed
;
cp
= intrinsic(cp
, rtdp
, flags
);
/* skip up to and past ';' */
cp
= intrinsic(cp
, rtdp
, Intr_unknown
);
case '(': /* equiv to another type */
if (ntdp
== NULL
) { /* if that type isn't defined yet */
if (*cp
++ != '=') /* better be defining it now */
expected("tdefdecl/'('", "=", cp
- 1);
cp
= tdefdecl(cp
, h2
, rtdp
);
ntdp
= malloc(sizeof (*ntdp
));
ntdp
->data
.tdesc
= *rtdp
;
} else { /* that type is already defined */
*rtdp
= malloc(sizeof (**rtdp
));
(*rtdp
)->data
.tdesc
= ntdp
;
cp
= tdefdecl(cp
+ 1, h
, &ntdp
);
expected("tdefdecl/*", "id", cp
);
*rtdp
= malloc(sizeof (**rtdp
));
(*rtdp
)->size
= model
->pointersize
;
(*rtdp
)->name
= "pointer";
(*rtdp
)->data
.tdesc
= ntdp
;
cp
= tdefdecl(cp
+ 1, h
, &ntdp
);
*rtdp
= malloc(sizeof (**rtdp
));
(*rtdp
)->type
= FUNCTION
;
(*rtdp
)->size
= model
->pointersize
;
(*rtdp
)->name
= "function";
(*rtdp
)->data
.tdesc
= ntdp
;
expected("tdefdecl/a", "r", cp
- 1);
*rtdp
= malloc(sizeof (**rtdp
));
if (c
!= 's' && c
!= 'u' && c
!= 'e')
expected("tdefdecl/x", "[sue]", cp
- 1);
*rtdp
= malloc(sizeof (**rtdp
));
cp
= tdefdecl(cp
+ 1, h
, &ntdp
);
*rtdp
= malloc(sizeof (**rtdp
));
(*rtdp
)->type
= VOLATILE
;
(*rtdp
)->name
= "volatile";
(*rtdp
)->data
.tdesc
= ntdp
;
cp
= tdefdecl(cp
+ 1, h
, &ntdp
);
*rtdp
= malloc(sizeof (**rtdp
));
(*rtdp
)->data
.tdesc
= ntdp
;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
/* gcc equiv to another type */
if (ntdp
== NULL
) { /* if that type isn't defined yet */
/* better be defining it now */
expected("tdefdecl/'0-9'", "=", cp
- 1);
/* defined in terms of itself */
*rtdp
= malloc(sizeof (**rtdp
));
(*rtdp
)->type
= INTRINSIC
;
cp
= tdefdecl(cp
, h2
, rtdp
);
ntdp
= malloc(sizeof (*ntdp
));
ntdp
->data
.tdesc
= *rtdp
;
} else { /* that type is already defined */
*rtdp
= malloc(sizeof (**rtdp
));
(*rtdp
)->data
.tdesc
= ntdp
;
*rtdp
= malloc(sizeof (**rtdp
));
cp
= soudef(cp
, (type
== 'u') ? UNION
: STRUCT
, rtdp
);
expected("tdefdecl", "<type code>", cp
);
intrinsic(char *cp
, struct tdesc
**rtdp
, intr_flags_t flags
)
tdp
= malloc(sizeof (*tdp
));
debug(3, NULL
, "intrinsic: size=%ld", size
);
soudef(char *cp
, enum type type
, struct tdesc
**rtdp
)
struct mlist
**next_pp
, *prev_p
= NULL
;
(*rtdp
)->type
= type
; /* s or u */
* An '@' here indicates a bitmask follows. This is so the
* compiler can pass information to debuggers about how structures
* are passed in the v9 world. We don't need this information
debug(3, cp
, "soudef: %s size=%d",
(*rtdp
)->name
? (*rtdp
)->name
: "(anonsou)",
next_pp
= &((*rtdp
)->data
.members
.forw
); /* head for forward linklist */
while ((*cp
!= '"') && (*cp
!= ';')) { /* signifies end of fields */
struct mlist
*mlp
= malloc(sizeof (*mlp
));
mlp
->prev
= prev_p
; /* links for the backward list */
*next_pp
= mlp
; /* links for the forward list */
* find the tdesc struct in the hash table for this type
* and stick a ptr in here
if (tdp
== NULL
) { /* not in hash list */
debug(3, NULL
, " defines %s (%d)", w
, h
);
expected("soudef", "=", cp
- 1);
cp
= tdefdecl(cp
, h
, &tdp
);
debug(4, cp
, " soudef now looking at ");
debug(3, NULL
, " refers to %s (%d, %s)",
w
? w
: "anon", h
, tdp
->name
? tdp
->name
: "anon");
cp
= offsize(cp
, mlp
); /* cp is now pointing to next field */
if (*cp
== '\\') /* could be a continuation */
(*rtdp
)->data
.members
.back
= prev_p
; /* head for backward linklist */
offsize(char *cp
, struct mlist
*mlp
)
cp
= number(cp
, &offset
);
expected("offsize/2", ",", cp
- 1);
expected("offsize/3", ";", cp
- 1);
arraydef(char *cp
, struct tdesc
**rtdp
)
expected("arraydef/1", ";", cp
- 1);
(*rtdp
)->data
.ardef
= malloc(sizeof (struct ardef
));
(*rtdp
)->data
.ardef
->indices
= malloc(sizeof (struct element
));
(*rtdp
)->data
.ardef
->indices
->index_type
= lookup(h
);
cp
= number(cp
, &start
); /* lower */
expected("arraydef/2", ";", cp
- 1);
cp
= number(cp
, &end
); /* upper */
expected("arraydef/3", ";", cp
- 1);
(*rtdp
)->data
.ardef
->indices
->range_start
= start
;
(*rtdp
)->data
.ardef
->indices
->range_end
= end
;
cp
= number(cp
, &contents_type
); /* lower */
tdp
= lookup(contents_type
);
(*rtdp
)->data
.ardef
->contents
= tdp
;
expected("arraydef/4", "=", cp
);
cp
= tdefdecl(cp
+ 1, h
, &tdp
);
addhash(tdp
, h
); /* for *(x,y) types */
(*rtdp
)->data
.ardef
->contents
= tdp
;
cp
= tdefdecl(cp
, h
, &((*rtdp
)->data
.ardef
->contents
));
enumdef(char *cp
, struct tdesc
**rtdp
)
struct elist
*elp
, **prev
;
(*rtdp
)->data
.emem
= NULL
;
prev
= &((*rtdp
)->data
.emem
);
elp
= malloc(sizeof (*elp
));
cp
= number(cp
, &elp
->number
);
debug(3, NULL
, "enum %s: %s=%ld",
(*rtdp
)->name
? (*rtdp
)->name
: "(anon enum)",
expected("enumdef", ",", cp
- 1);
* Add a node to the hash queues.
addhash(struct tdesc
*tdp
, int num
)
char added_num
= 0, added_name
= 0;
* If it already exists in the hash table don't add it again
* (but still check to see if the name should be hashed).
tdp
->hash
= hash_table
[hash
];
ttdp
= lookupname(tdp
->name
);
hash
= compute_sum(tdp
->name
);
tdp
->next
= name_table
[hash
];
if (!added_num
&& !added_name
) {
fprintf(stderr
, "stabs: broken hash\n");
int hash
= compute_sum(name
);
struct tdesc
*tdp
, *ttdp
= NULL
;
for (tdp
= name_table
[hash
]; tdp
!= NULL
; tdp
= tdp
->next
) {
if (tdp
->name
!= NULL
&& strcmp(tdp
->name
, name
) == 0) {
if (tdp
->type
== STRUCT
|| tdp
->type
== UNION
||
tdp
->type
== ENUM
|| tdp
->type
== INTRINSIC
)
for (sum
= 0; (c
= *w
) != '\0'; sum
+= c
, w
++)