e0ea83ebb1
Summary of changes: - libdtrace changeset: 12902:3bb859a7330c user: Bryan Cantrill <Bryan.Cantrill@Sun.COM> date: Fri Jul 23 17:34:02 2010 -0700 summary: 6679140 asymmetric alloc/dealloc activity can induce dynamic variable drops changeset: 12692:4341b447c069 user: Ali Bahrami <Ali.Bahrami@Oracle.COM> date: Thu Jun 24 18:16:42 2010 -0600 summary: 6916796 OSnet mapfiles should use version 2 link-editor syntax changeset: 12507:501806a754d2 user: Alan Maguire <Alan.Maguire@Sun.COM> date: Thu May 27 17:29:51 2010 -0400 summary: PSARC 2010/106 DTrace TCP and UDP providers changeset: 11798:1e7f1f154004 user: Roger A. Faulkner <Roger.Faulkner@Sun.COM> date: Sun Feb 28 18:42:20 2010 -0800 summary: PSARC 2009/657 delete obsolete system call traps changeset: 11466:d60272412fb0 user: Roger A. Faulkner <Roger.Faulkner@Sun.COM> date: Mon Jan 11 17:42:13 2010 -0800 summary: 6915578 MUTEX_HELD() and RW_LOCK_HELD() macros should be available to Posix threads changeset: 11237:0d23e47ed228 user: Jonathan Haslam <Jonathan.Haslam@Sun.COM> date: Thu Dec 03 13:39:19 2009 +0000 summary: 6795386 macro arguments and globbing in DTrace probe descriptions don't mix changeset: 10791:944abfb5b345 user: Jonathan Haslam <Jonathan.Haslam@Sun.COM> date: Wed Oct 14 11:25:23 2009 +0100 summary: 6886953 large symbols lead to stack exhaustion changeset: 10326:8e3fbeec2d76 user: Siddheshwar Mahesh <Siddheshwar.Mahesh@Sun.COM> date: Mon Aug 17 13:26:49 2009 -0500 summary: 6868411 NFS provider generates error on ci_remote on RDMA operations changeset: 10207:87c40ea3fc4b user: jmcp <James.McPherson@Sun.COM> date: Wed Jul 29 16:56:03 2009 -0700 summary: 6864230 hiho, hiho, it'ch chtime for CH to go changeset: 10044:2643c1cd9e2a user: Priya Krishnan <Priya.Krishnan@Sun.COM> date: Mon Jul 06 21:19:41 2009 -0400 summary: 6855027 iscsit.d breaks dtrace in osol based on snv_117 changeset: 9900:1b86d65a4f9e user: Ali Bahrami <Ali.Bahrami@Sun.COM> date: Thu Jun 18 13:16:39 2009 -0600 summary: 6851224 elf_getshnum() and elf_getshstrndx() incompatible with 2002 ELF gABI agreement changeset: 9885:a3d5e9d9e779 user: Robert Mastors <Robert.Mastors@Sun.COM> date: Tue Jun 16 15:25:25 2009 -0500 summary: 6711844 assert: vp->v_shrlocks == 0L, file: ../../common/fs/vnode.c, line: 2333 changeset: 9881:741c9e4e094c user: Charles Ting <Charles.Ting@Sun.COM> date: Tue Jun 16 14:51:40 2009 -0400 summary: 6849606 SRP DTrace Probe for xfer-done misses completion of READ transfers changeset: 9829:e8059fcaee97 user: Charles Ting <Charles.Ting@Sun.COM> date: Tue Jun 09 10:11:35 2009 -0400 summary: 6804431 Add Dtrace probes to SRPT changeset: 9812:a2990074321f user: Priya Krishnan <Priya.Krishnan@Sun.COM> date: Mon Jun 08 09:49:48 2009 -0400 summary: 6847237 The iscsit.d DTrace translator should include iscsi.d for the definition of iscsiinfo_t changeset: 9721:4f7e194c7c37 user: Priya Krishnan <Priya.Krishnan@Sun.COM> date: Tue May 26 10:40:43 2009 -0400 summary: 6809997 COMSTAR iscsi target DTrace Provider needed changeset: 9625:8aa5731291b4 user: Sam Cramer <Sam.Cramer@Sun.COM> date: Wed May 13 17:10:06 2009 -0700 summary: 6840354 "/usr/lib/dtrace/fc.d", line 59: syntax error near "fct_local_port_t" changeset: 9609:8874cc8d5e3f user: Sam Cramer <Sam.Cramer@Sun.COM> date: Mon May 11 21:02:27 2009 -0700 summary: 6809580 fct DTrace providers needed for qlt changeset: 9578:c4b38ec17f4e user: Sam Cramer <Sam.Cramer@Sun.COM> date: Fri May 08 12:12:40 2009 -0700 summary: 6809580 fct DTrace providers needed for qlt changeset: 9531:dc8924ef7839 user: Rafael Vanoni <rafael.vanoni@sun.com> date: Mon May 04 11:48:15 2009 -0700 summary: 6730130 dtrace missing printf handler for stdev changeset: 9389:750ed3471e90 user: Vamsi Nagineni <Vamsi.Krishna@Sun.COM> date: Fri Apr 17 06:26:47 2009 -0700 summary: 6812050 dtrace should translate curpsinfo->pr_contract changeset: 9085:ff7eb0bace56 user: Ali Bahrami <Ali.Bahrami@Sun.COM> date: Wed Mar 18 13:28:28 2009 -0600 summary: 6813909 generalize eh_frame support to non-amd64 platforms changeset: 8803:8c01b39012c9 user: Jonathan Haslam <Jonathan.Haslam@Sun.COM> date: Fri Feb 13 07:13:13 2009 +0000 summary: PSARC 2008/480 DTrace CPC Provider changeset: 8744:03d5725cda56 user: Ali Bahrami <Ali.Bahrami@Sun.COM> date: Tue Feb 10 09:38:02 2009 -0700 summary: 6798660 Cadmium .NOT file processing problem with CWD relative file paths changeset: 8337:079ecc003ca6 user: Jonathan Haslam <Jonathan.Haslam@Sun.COM> date: Thu Dec 11 11:26:47 2008 +0000 summary: 6750659 drti.o crashes app due to corrupt environment changeset: 7991:d3b751ef3d85 user: Jonathan Haslam <Jonathan.Haslam@Sun.COM> date: Mon Nov 03 10:26:23 2008 +0000 summary: 6738982 Representative thread after DTrace stop() action is incorrect changeset: 7208:568549b138d8 user: vv149972 date: Mon Jul 28 23:14:31 2008 -0700 summary: 6696397 NFS v3 provider reports all UDP clients as 0.0.0.0 changeset: 6878:360e73ea6b0c user: brendan date: Fri Jun 13 19:06:55 2008 -0700 summary: PSARC 2008/302 DTrace IP Provider changeset: 6554:b5817e112852 user: ahl date: Mon May 05 14:38:24 2008 -0700 summary: 6677812 race between dtrace activities in non-local zones ---- - ctf tools: changeset: 12177:800b7f847f1e user: Surya Prakki <Surya.Prakki@Sun.COM> date: Sun Apr 18 23:59:57 2010 -0700 summary: 6941452 ctfconvert fails on VLAs with code generated by SS12u1 changeset: 11432:c1c450bf62f2 user: John Levon <john.levon@sun.com> date: Tue Jan 05 06:57:53 2010 -0800 summary: 6905711 anonymous and empty SOUs crash ctfconvert changeset: 11227:cd2ac59c39f2 user: Ali Bahrami <Ali.Bahrami@Sun.COM> date: Wed Dec 02 15:37:55 2009 -0700 summary: 6900241 ld should track SHT_GROUP sections by symbol name, not section name changeset: 10380:5394a7172e1f user: Ali Bahrami <Ali.Bahrami@Sun.COM> date: Tue Aug 25 13:51:43 2009 -0600 summary: 6866605 SUNWonbld ELF analysis tools need overhaul (fix ctfmerge/libc dependency) changeset: 10207:87c40ea3fc4b user: jmcp <James.McPherson@Sun.COM> date: Wed Jul 29 16:56:03 2009 -0700 summary: 6864230 hiho, hiho, it'ch chtime for CH to go changeset: 10206:51f52702df72 user: John Levon <john.levon@sun.com> date: Wed Jul 29 14:36:30 2009 -0700 summary: 6854065 CTF tools should error out given 1024+-member structures changeset: 7230:429b4f7acf1a user: sn199410 date: Wed Jul 30 16:10:30 2008 -0700 summary: 6575435 ctf tools cannot handle C99 VLAs ("variable length arrays") changeset: 6936:72189fcd99e4 user: sommerfe date: Sun Jun 22 09:13:44 2008 -0700 summary: 6716983 left-for-dead ctfmerge worker threads awake to take out maker ---- - dtrace command utility: changeset: 12507:501806a754d2 user: Alan Maguire <Alan.Maguire@Sun.COM> date: Thu May 27 17:29:51 2010 -0400 summary: PSARC 2010/106 DTrace TCP and UDP providers changeset: 11838:32bb5d254240 user: Liane Praza <Liane.Praza@Sun.COM> date: Tue Mar 02 19:29:26 2010 -0700 summary: PSARC 2010/067 Interim modernization updates changeset: 11270:47a962fe7b45 user: Frank Van Der Linden <Frank.Vanderlinden@Sun.COM> date: Mon Dec 07 13:47:36 2009 -0800 summary: 6907170 fix for 6875656 left out updates to DTrace test suite changeset: 11237:0d23e47ed228 user: Jonathan Haslam <Jonathan.Haslam@Sun.COM> date: Thu Dec 03 13:39:19 2009 +0000 summary: 6795386 macro arguments and globbing in DTrace probe descriptions don't mix changeset: 11153:dec430d20576 user: Frank Van Der Linden <Frank.Vanderlinden@Sun.COM> date: Sun Nov 22 19:22:26 2009 -0800 summary: 6875656 xdt needs to support more XenTrace probes changeset: 11102:b91faef0c984 user: Gavin Maltby <Gavin.Maltby@Sun.COM> date: Thu Nov 19 15:28:11 2009 +1100 summary: PSARC/2009/554 door_xcreate - extended door creation interface for private doors changeset: 11066:cebb50cbe4f9 user: Rafael Vanoni <rafael.vanoni@sun.com> date: Fri Nov 13 01:32:32 2009 -0800 summary: PSARC/2009/396 Tickless Kernel Architecture / lbolt decoupling changeset: 10791:944abfb5b345 user: Jonathan Haslam <Jonathan.Haslam@Sun.COM> date: Wed Oct 14 11:25:23 2009 +0100 summary: 6886953 large symbols lead to stack exhaustion changeset: 10207:87c40ea3fc4b user: jmcp <James.McPherson@Sun.COM> date: Wed Jul 29 16:56:03 2009 -0700 summary: 6864230 hiho, hiho, it'ch chtime for CH to go changeset: 9531:dc8924ef7839 user: Rafael Vanoni <rafael.vanoni@sun.com> date: Mon May 04 11:48:15 2009 -0700 summary: 6730130 dtrace missing printf handler for stdev changeset: 9397:e667d620a75c user: Jonathan Haslam <Jonathan.Haslam@Sun.COM> date: Mon Apr 20 07:58:44 2009 +0100 summary: 6806023 cpc provider event name validation needs to be a bit tighter changeset: 8803:8c01b39012c9 user: Jonathan Haslam <Jonathan.Haslam@Sun.COM> date: Fri Feb 13 07:13:13 2009 +0000 summary: PSARC 2008/480 DTrace CPC Provider changeset: 8605:0189cb9c5358 user: Jonathan Haslam <Jonathan.Haslam@Sun.COM> date: Thu Jan 22 12:09:13 2009 +0000 summary: 6749441 intrstat(1M) shows zeroed values after suspend/resume changeset: 8337:079ecc003ca6 user: Jonathan Haslam <Jonathan.Haslam@Sun.COM> date: Thu Dec 11 11:26:47 2008 +0000 summary: 6750659 drti.o crashes app due to corrupt environment changeset: 8287:771477e4b843 user: John Sonnenschein <John.Sonnenschein@Sun.COM> date: Fri Dec 05 19:08:38 2008 -0800 summary: PSARC 2005/462 Removal of Perl 5.6.1 from Solaris 11 changeset: 7991:d3b751ef3d85 user: Jonathan Haslam <Jonathan.Haslam@Sun.COM> date: Mon Nov 03 10:26:23 2008 +0000 summary: 6738982 Representative thread after DTrace stop() action is incorrect changeset: 7502:da077e5d991e user: Aruna Ramakrishna <aruna@cs.umn.edu> date: Sat Sep 06 05:36:02 2008 -0400 summary: 6706947 tcp_trace should be replaced with dtrace probes. changeset: 7484:a48e950bad22 user: Tom Erickson <tomee@eng.sun.com> date: Wed Sep 03 15:14:25 2008 -0700 summary: 6737926 getAggregate() method fails to specify anonymous aggregation explicitly changeset: 7299:d9a056040774 user: John Beck <John.Beck@Sun.COM> date: Thu Aug 07 12:44:26 2008 -0700 summary: 6734627 protocmp complains about opt/SUNWdtrt/README after TW -> Hg switch changeset: 6998:58787ea78303 user: brendan date: Tue Jul 01 18:28:22 2008 -0700 summary: 6721426 tst.sdtargs.d passes despite dtrace "invalid address" error changeset: 6878:360e73ea6b0c user: brendan date: Fri Jun 13 19:06:55 2008 -0700 summary: PSARC 2008/302 DTrace IP Provider changeset: 6670:1961a43f2335 user: tariq date: Tue May 20 15:08:16 2008 -0700 summary: 6685348 Hypervisor event provider for DTrace changeset: 6554:b5817e112852 user: ahl date: Mon May 05 14:38:24 2008 -0700 summary: 6677812 race between dtrace activities in non-local zones changeset: 6543:465433824d87 user: rie date: Fri May 02 15:01:06 2008 -0700 summary: 6683064 check_rtime could do with some spring cleaning
1211 lines
24 KiB
C
1211 lines
24 KiB
C
/*
|
|
* CDDL HEADER START
|
|
*
|
|
* The contents of this file are subject to the terms of the
|
|
* Common Development and Distribution License (the "License").
|
|
* You may not use this file except in compliance with the License.
|
|
*
|
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
|
* or http://www.opensolaris.org/os/licensing.
|
|
* See the License for the specific language governing permissions
|
|
* and limitations under the License.
|
|
*
|
|
* When distributing Covered Code, include this CDDL HEADER in each
|
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
* If applicable, add the following below this CDDL HEADER, with the
|
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
|
*
|
|
* CDDL HEADER END
|
|
*/
|
|
/*
|
|
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
|
|
*/
|
|
|
|
/*
|
|
* This file is a sewer.
|
|
*/
|
|
|
|
#include <limits.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <strings.h>
|
|
#include <setjmp.h>
|
|
#include <ctype.h>
|
|
#include <uts/common/sys/ctf.h>
|
|
|
|
#include "ctftools.h"
|
|
#include "memory.h"
|
|
#include "list.h"
|
|
|
|
#define HASH(NUM) ((int)(NUM & (BUCKETS - 1)))
|
|
#define BUCKETS 128
|
|
|
|
#define TYPEPAIRMULT 10000
|
|
#define MAKETYPEID(file, num) ((file) * TYPEPAIRMULT + num)
|
|
#define TYPEFILE(tid) ((tid) / TYPEPAIRMULT)
|
|
#define TYPENUM(tid) ((tid) % TYPEPAIRMULT)
|
|
|
|
#define expected(a, b, c) _expected(a, b, c, __LINE__)
|
|
|
|
static int faketypenumber = 100000000;
|
|
|
|
static tdesc_t *hash_table[BUCKETS];
|
|
static tdesc_t *name_table[BUCKETS];
|
|
|
|
list_t *typedbitfldmems;
|
|
|
|
static void reset(void);
|
|
static jmp_buf resetbuf;
|
|
|
|
static char *soudef(char *cp, stabtype_t type, tdesc_t **rtdp);
|
|
static void enumdef(char *cp, tdesc_t **rtdp);
|
|
static int compute_sum(const char *w);
|
|
|
|
static char *number(char *cp, int *n);
|
|
static char *name(char *cp, char **w);
|
|
static char *id(char *cp, int *h);
|
|
static char *whitesp(char *cp);
|
|
static void addhash(tdesc_t *tdp, int num);
|
|
static int tagadd(char *w, int h, tdesc_t *tdp);
|
|
static char *tdefdecl(char *cp, int h, tdesc_t **rtdp);
|
|
static char *intrinsic(char *cp, tdesc_t **rtdp);
|
|
static char *arraydef(char *cp, tdesc_t **rtdp);
|
|
|
|
extern int debug_level;
|
|
int debug_parse = DEBUG_PARSE;
|
|
|
|
/*PRINTFLIKE3*/
|
|
static void
|
|
parse_debug(int level, char *cp, char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
char buf[1024];
|
|
char tmp[32];
|
|
int i;
|
|
|
|
if (level > debug_level || !debug_parse)
|
|
return;
|
|
|
|
if (cp != NULL) {
|
|
for (i = 0; i < 30; i++) {
|
|
if (cp[i] == '\0')
|
|
break;
|
|
if (!iscntrl(cp[i]))
|
|
tmp[i] = cp[i];
|
|
}
|
|
tmp[i] = '\0';
|
|
(void) snprintf(buf, sizeof (buf), "%s [cp='%s']\n", fmt, tmp);
|
|
} else {
|
|
strcpy(buf, fmt);
|
|
strcat(buf, "\n");
|
|
}
|
|
|
|
va_start(ap, fmt);
|
|
vadebug(level, buf, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
/* Report unexpected syntax in stabs. */
|
|
static void
|
|
_expected(
|
|
char *who, /* what function, or part thereof, is reporting */
|
|
char *what, /* what was expected */
|
|
char *where, /* where we were in the line of input */
|
|
int line)
|
|
{
|
|
fprintf(stderr, "%s, expecting \"%s\" at \"%s\"\n", who, what, where);
|
|
fprintf(stderr, "code line: %d, file %s\n", line,
|
|
(curhdr ? curhdr : "NO FILE"));
|
|
reset();
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
parse_init(tdata_t *td)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < BUCKETS; i++) {
|
|
hash_table[i] = NULL;
|
|
name_table[i] = NULL;
|
|
}
|
|
|
|
if (typedbitfldmems != NULL) {
|
|
list_free(typedbitfldmems, NULL, NULL);
|
|
typedbitfldmems = NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
parse_finish(tdata_t *td)
|
|
{
|
|
td->td_nextid = ++faketypenumber;
|
|
}
|
|
|
|
static tdesc_t *
|
|
unres_new(int tid)
|
|
{
|
|
tdesc_t *tdp;
|
|
|
|
tdp = xcalloc(sizeof (*tdp));
|
|
tdp->t_type = TYPEDEF_UNRES;
|
|
tdp->t_id = tid;
|
|
|
|
return (tdp);
|
|
}
|
|
|
|
char *
|
|
read_tid(char *cp, tdesc_t **tdpp)
|
|
{
|
|
tdesc_t *tdp;
|
|
int tid;
|
|
|
|
cp = id(cp, &tid);
|
|
|
|
assert(tid != 0);
|
|
|
|
if (*cp == '=') {
|
|
if (!(cp = tdefdecl(cp + 1, tid, &tdp)))
|
|
return (NULL);
|
|
if (tdp->t_id && tdp->t_id != tid) {
|
|
tdesc_t *ntdp = xcalloc(sizeof (*ntdp));
|
|
|
|
ntdp->t_type = TYPEDEF;
|
|
ntdp->t_tdesc = tdp;
|
|
tdp = ntdp;
|
|
}
|
|
addhash(tdp, tid);
|
|
} else if ((tdp = lookup(tid)) == NULL)
|
|
tdp = unres_new(tid);
|
|
|
|
*tdpp = tdp;
|
|
return (cp);
|
|
}
|
|
|
|
static iitype_t
|
|
parse_fun(char *cp, iidesc_t *ii)
|
|
{
|
|
iitype_t iitype;
|
|
tdesc_t *tdp;
|
|
tdesc_t **args = NULL;
|
|
int nargs = 0;
|
|
int va = 0;
|
|
|
|
/*
|
|
* name:P prototype
|
|
* name:F global function
|
|
* name:f static function
|
|
*/
|
|
switch (*cp++) {
|
|
case 'P':
|
|
iitype = II_NOT; /* not interesting */
|
|
break;
|
|
|
|
case 'F':
|
|
iitype = II_GFUN;
|
|
break;
|
|
|
|
case 'f':
|
|
iitype = II_SFUN;
|
|
break;
|
|
|
|
default:
|
|
expected("parse_nfun", "[PfF]", cp - 1);
|
|
}
|
|
|
|
if (!(cp = read_tid(cp, &tdp)))
|
|
return (-1);
|
|
|
|
if (*cp)
|
|
args = xmalloc(sizeof (tdesc_t *) * FUNCARG_DEF);
|
|
|
|
while (*cp && *++cp) {
|
|
if (*cp == '0') {
|
|
va = 1;
|
|
continue;
|
|
}
|
|
|
|
nargs++;
|
|
if (nargs > FUNCARG_DEF)
|
|
args = xrealloc(args, sizeof (tdesc_t *) * nargs);
|
|
if (!(cp = read_tid(cp, &args[nargs - 1])))
|
|
return (-1);
|
|
}
|
|
|
|
ii->ii_type = iitype;
|
|
ii->ii_dtype = tdp;
|
|
ii->ii_nargs = nargs;
|
|
ii->ii_args = args;
|
|
ii->ii_vargs = va;
|
|
|
|
return (iitype);
|
|
}
|
|
|
|
static iitype_t
|
|
parse_sym(char *cp, iidesc_t *ii)
|
|
{
|
|
tdesc_t *tdp;
|
|
iitype_t iitype;
|
|
|
|
/*
|
|
* name:G global variable
|
|
* name:S static variable
|
|
*/
|
|
switch (*cp++) {
|
|
case 'G':
|
|
iitype = II_GVAR;
|
|
break;
|
|
case 'S':
|
|
iitype = II_SVAR;
|
|
break;
|
|
case 'p':
|
|
iitype = II_PSYM;
|
|
break;
|
|
case '(':
|
|
cp--;
|
|
/*FALLTHROUGH*/
|
|
case 'r':
|
|
case 'V':
|
|
iitype = II_NOT; /* not interesting */
|
|
break;
|
|
default:
|
|
expected("parse_sym", "[GprSV(]", cp - 1);
|
|
}
|
|
|
|
if (!(cp = read_tid(cp, &tdp)))
|
|
return (-1);
|
|
|
|
ii->ii_type = iitype;
|
|
ii->ii_dtype = tdp;
|
|
|
|
return (iitype);
|
|
}
|
|
|
|
static iitype_t
|
|
parse_type(char *cp, iidesc_t *ii)
|
|
{
|
|
tdesc_t *tdp, *ntdp;
|
|
int tid;
|
|
|
|
if (*cp++ != 't')
|
|
expected("parse_type", "t (type)", cp - 1);
|
|
|
|
cp = id(cp, &tid);
|
|
if ((tdp = lookup(tid)) == NULL) {
|
|
if (*cp++ != '=')
|
|
expected("parse_type", "= (definition)", cp - 1);
|
|
|
|
(void) tdefdecl(cp, tid, &tdp);
|
|
|
|
if (tdp->t_id == tid) {
|
|
assert(tdp->t_type != TYPEDEF);
|
|
assert(!lookup(tdp->t_id));
|
|
|
|
if (!streq(tdp->t_name, ii->ii_name)) {
|
|
ntdp = xcalloc(sizeof (*ntdp));
|
|
ntdp->t_name = xstrdup(ii->ii_name);
|
|
ntdp->t_type = TYPEDEF;
|
|
ntdp->t_tdesc = tdp;
|
|
tdp->t_id = faketypenumber++;
|
|
tdp = ntdp;
|
|
}
|
|
} else if (tdp->t_id == 0) {
|
|
assert(tdp->t_type == FORWARD ||
|
|
tdp->t_type == INTRINSIC);
|
|
|
|
if (tdp->t_name && !streq(tdp->t_name, ii->ii_name)) {
|
|
ntdp = xcalloc(sizeof (*ntdp));
|
|
ntdp->t_name = xstrdup(ii->ii_name);
|
|
ntdp->t_type = TYPEDEF;
|
|
ntdp->t_tdesc = tdp;
|
|
tdp->t_id = faketypenumber++;
|
|
tdp = ntdp;
|
|
}
|
|
} else if (tdp->t_id != tid) {
|
|
ntdp = xcalloc(sizeof (*ntdp));
|
|
ntdp->t_name = xstrdup(ii->ii_name);
|
|
ntdp->t_type = TYPEDEF;
|
|
ntdp->t_tdesc = tdp;
|
|
tdp = ntdp;
|
|
}
|
|
|
|
if (tagadd(ii->ii_name, tid, tdp) < 0)
|
|
return (-1);
|
|
}
|
|
|
|
ii->ii_type = II_TYPE;
|
|
ii->ii_dtype = tdp;
|
|
return (II_TYPE);
|
|
}
|
|
|
|
static iitype_t
|
|
parse_sou(char *cp, iidesc_t *idp)
|
|
{
|
|
tdesc_t *rtdp;
|
|
int tid;
|
|
|
|
if (*cp++ != 'T')
|
|
expected("parse_sou", "T (sou)", cp - 1);
|
|
|
|
cp = id(cp, &tid);
|
|
if (*cp++ != '=')
|
|
expected("parse_sou", "= (definition)", cp - 1);
|
|
|
|
parse_debug(1, NULL, "parse_sou: declaring '%s'", idp->ii_name ?
|
|
idp->ii_name : "(anon)");
|
|
if ((rtdp = lookup(tid)) != NULL) {
|
|
if (idp->ii_name != NULL) {
|
|
if (rtdp->t_name != NULL &&
|
|
strcmp(rtdp->t_name, idp->ii_name) != 0) {
|
|
tdesc_t *tdp;
|
|
|
|
tdp = xcalloc(sizeof (*tdp));
|
|
tdp->t_name = xstrdup(idp->ii_name);
|
|
tdp->t_type = TYPEDEF;
|
|
tdp->t_tdesc = rtdp;
|
|
addhash(tdp, tid); /* for *(x,y) types */
|
|
parse_debug(3, NULL, " %s defined as %s(%d)",
|
|
idp->ii_name, tdesc_name(rtdp), tid);
|
|
} else if (rtdp->t_name == NULL) {
|
|
rtdp->t_name = xstrdup(idp->ii_name);
|
|
addhash(rtdp, tid);
|
|
}
|
|
}
|
|
} else {
|
|
rtdp = xcalloc(sizeof (*rtdp));
|
|
rtdp->t_name = idp->ii_name ? xstrdup(idp->ii_name) : NULL;
|
|
addhash(rtdp, tid);
|
|
}
|
|
|
|
switch (*cp++) {
|
|
case 's':
|
|
(void) soudef(cp, STRUCT, &rtdp);
|
|
break;
|
|
case 'u':
|
|
(void) soudef(cp, UNION, &rtdp);
|
|
break;
|
|
case 'e':
|
|
enumdef(cp, &rtdp);
|
|
break;
|
|
default:
|
|
expected("parse_sou", "<tag type s/u/e>", cp - 1);
|
|
break;
|
|
}
|
|
|
|
idp->ii_type = II_SOU;
|
|
idp->ii_dtype = rtdp;
|
|
return (II_SOU);
|
|
}
|
|
|
|
int
|
|
parse_stab(stab_t *stab, char *cp, iidesc_t **iidescp)
|
|
{
|
|
iidesc_t *ii = NULL;
|
|
iitype_t (*parse)(char *, iidesc_t *);
|
|
int rc;
|
|
|
|
/*
|
|
* set up for reset()
|
|
*/
|
|
if (setjmp(resetbuf))
|
|
return (-1);
|
|
|
|
cp = whitesp(cp);
|
|
ii = iidesc_new(NULL);
|
|
cp = name(cp, &ii->ii_name);
|
|
|
|
switch (stab->n_type) {
|
|
case N_FUN:
|
|
parse = parse_fun;
|
|
break;
|
|
|
|
case N_LSYM:
|
|
if (*cp == 't')
|
|
parse = parse_type;
|
|
else if (*cp == 'T')
|
|
parse = parse_sou;
|
|
else
|
|
parse = parse_sym;
|
|
break;
|
|
|
|
case N_GSYM:
|
|
case N_LCSYM:
|
|
case N_PSYM:
|
|
case N_ROSYM:
|
|
case N_RSYM:
|
|
case N_STSYM:
|
|
parse = parse_sym;
|
|
break;
|
|
default:
|
|
parse_debug(1, cp, "Unknown stab type %#x", stab->n_type);
|
|
bzero(&resetbuf, sizeof (resetbuf));
|
|
return (-1);
|
|
}
|
|
|
|
rc = parse(cp, ii);
|
|
bzero(&resetbuf, sizeof (resetbuf));
|
|
|
|
if (rc < 0 || ii->ii_type == II_NOT) {
|
|
iidesc_free(ii, NULL);
|
|
return (rc);
|
|
}
|
|
|
|
*iidescp = ii;
|
|
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* Check if we have this node in the hash table already
|
|
*/
|
|
tdesc_t *
|
|
lookup(int h)
|
|
{
|
|
int bucket = HASH(h);
|
|
tdesc_t *tdp = hash_table[bucket];
|
|
|
|
while (tdp != NULL) {
|
|
if (tdp->t_id == h)
|
|
return (tdp);
|
|
tdp = tdp->t_hash;
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
static char *
|
|
whitesp(char *cp)
|
|
{
|
|
char c;
|
|
|
|
for (c = *cp++; isspace(c); c = *cp++)
|
|
;
|
|
--cp;
|
|
return (cp);
|
|
}
|
|
|
|
static char *
|
|
name(char *cp, char **w)
|
|
{
|
|
char *new, *orig, c;
|
|
int len;
|
|
|
|
orig = cp;
|
|
c = *cp++;
|
|
if (c == ':')
|
|
*w = NULL;
|
|
else if (isalpha(c) || strchr("_.$#", c)) {
|
|
for (c = *cp++; isalnum(c) || strchr(" _.$#", c); c = *cp++)
|
|
;
|
|
if (c != ':')
|
|
reset();
|
|
len = cp - orig;
|
|
new = xmalloc(len);
|
|
while (orig < cp - 1)
|
|
*new++ = *orig++;
|
|
*new = '\0';
|
|
*w = new - (len - 1);
|
|
} else
|
|
reset();
|
|
|
|
return (cp);
|
|
}
|
|
|
|
static char *
|
|
number(char *cp, int *n)
|
|
{
|
|
char *next;
|
|
|
|
*n = (int)strtol(cp, &next, 10);
|
|
if (next == cp)
|
|
expected("number", "<number>", cp);
|
|
return (next);
|
|
}
|
|
|
|
static char *
|
|
id(char *cp, int *h)
|
|
{
|
|
int n1, n2;
|
|
|
|
if (*cp == '(') { /* SunPro style */
|
|
cp++;
|
|
cp = number(cp, &n1);
|
|
if (*cp++ != ',')
|
|
expected("id", ",", cp - 1);
|
|
cp = number(cp, &n2);
|
|
if (*cp++ != ')')
|
|
expected("id", ")", cp - 1);
|
|
*h = MAKETYPEID(n1, n2);
|
|
} else if (isdigit(*cp)) { /* gcc style */
|
|
cp = number(cp, &n1);
|
|
*h = n1;
|
|
} else {
|
|
expected("id", "(/0-9", cp);
|
|
}
|
|
return (cp);
|
|
}
|
|
|
|
static int
|
|
tagadd(char *w, int h, tdesc_t *tdp)
|
|
{
|
|
tdesc_t *otdp;
|
|
|
|
tdp->t_name = w;
|
|
if (!(otdp = lookup(h)))
|
|
addhash(tdp, h);
|
|
else if (otdp != tdp) {
|
|
warning("duplicate entry\n");
|
|
warning(" old: %s %d (%d,%d)\n", tdesc_name(otdp),
|
|
otdp->t_type, TYPEFILE(otdp->t_id), TYPENUM(otdp->t_id));
|
|
warning(" new: %s %d (%d,%d)\n", tdesc_name(tdp),
|
|
tdp->t_type, TYPEFILE(tdp->t_id), TYPENUM(tdp->t_id));
|
|
return (-1);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static char *
|
|
tdefdecl(char *cp, int h, tdesc_t **rtdp)
|
|
{
|
|
tdesc_t *ntdp;
|
|
char *w;
|
|
int c, h2;
|
|
char type;
|
|
|
|
parse_debug(3, cp, "tdefdecl h=%d", h);
|
|
|
|
/* Type codes */
|
|
switch (type = *cp) {
|
|
case 'b': /* integer */
|
|
case 'R': /* fp */
|
|
cp = intrinsic(cp, rtdp);
|
|
break;
|
|
case '(': /* equiv to another type */
|
|
cp = id(cp, &h2);
|
|
ntdp = lookup(h2);
|
|
|
|
if (ntdp != NULL && *cp == '=') {
|
|
if (ntdp->t_type == FORWARD && *(cp + 1) == 'x') {
|
|
/*
|
|
* The 6.2 compiler, and possibly others, will
|
|
* sometimes emit the same stab for a forward
|
|
* declaration twice. That is, "(1,2)=xsfoo:"
|
|
* will sometimes show up in two different
|
|
* places. This is, of course, quite fun. We
|
|
* want CTF to work in spite of the compiler,
|
|
* so we'll let this one through.
|
|
*/
|
|
char *c2 = cp + 2;
|
|
char *nm;
|
|
|
|
if (!strchr("sue", *c2++)) {
|
|
expected("tdefdecl/x-redefine", "[sue]",
|
|
c2 - 1);
|
|
}
|
|
|
|
c2 = name(c2, &nm);
|
|
if (strcmp(nm, ntdp->t_name) != 0) {
|
|
terminate("Stabs error: Attempt to "
|
|
"redefine type (%d,%d) as "
|
|
"something else: %s\n",
|
|
TYPEFILE(h2), TYPENUM(h2),
|
|
c2 - 1);
|
|
}
|
|
free(nm);
|
|
|
|
h2 = faketypenumber++;
|
|
ntdp = NULL;
|
|
} else {
|
|
terminate("Stabs error: Attempting to "
|
|
"redefine type (%d,%d)\n", TYPEFILE(h2),
|
|
TYPENUM(h2));
|
|
}
|
|
}
|
|
|
|
if (ntdp == NULL) { /* if that type isn't defined yet */
|
|
if (*cp != '=') {
|
|
/* record it as unresolved */
|
|
parse_debug(3, NULL, "tdefdecl unres type %d",
|
|
h2);
|
|
*rtdp = calloc(sizeof (**rtdp), 1);
|
|
(*rtdp)->t_type = TYPEDEF_UNRES;
|
|
(*rtdp)->t_id = h2;
|
|
break;
|
|
} else
|
|
cp++;
|
|
|
|
/* define a new type */
|
|
cp = tdefdecl(cp, h2, rtdp);
|
|
if ((*rtdp)->t_id && (*rtdp)->t_id != h2) {
|
|
ntdp = calloc(sizeof (*ntdp), 1);
|
|
ntdp->t_type = TYPEDEF;
|
|
ntdp->t_tdesc = *rtdp;
|
|
*rtdp = ntdp;
|
|
}
|
|
|
|
addhash(*rtdp, h2);
|
|
|
|
} else { /* that type is already defined */
|
|
if (ntdp->t_type != TYPEDEF || ntdp->t_name != NULL) {
|
|
*rtdp = ntdp;
|
|
} else {
|
|
parse_debug(3, NULL,
|
|
"No duplicate typedef anon for ref");
|
|
*rtdp = ntdp;
|
|
}
|
|
}
|
|
break;
|
|
case '*':
|
|
ntdp = NULL;
|
|
cp = tdefdecl(cp + 1, h, &ntdp);
|
|
if (ntdp == NULL)
|
|
expected("tdefdecl/*", "id", cp);
|
|
|
|
if (!ntdp->t_id)
|
|
ntdp->t_id = faketypenumber++;
|
|
|
|
*rtdp = xcalloc(sizeof (**rtdp));
|
|
(*rtdp)->t_type = POINTER;
|
|
(*rtdp)->t_size = 0;
|
|
(*rtdp)->t_id = h;
|
|
(*rtdp)->t_tdesc = ntdp;
|
|
break;
|
|
case 'f':
|
|
cp = tdefdecl(cp + 1, h, &ntdp);
|
|
*rtdp = xcalloc(sizeof (**rtdp));
|
|
(*rtdp)->t_type = FUNCTION;
|
|
(*rtdp)->t_size = 0;
|
|
(*rtdp)->t_id = h;
|
|
(*rtdp)->t_fndef = xcalloc(sizeof (fndef_t));
|
|
/*
|
|
* The 6.1 compiler will sometimes generate incorrect stabs for
|
|
* function pointers (it'll get the return type wrong). This
|
|
* causes merges to fail. We therefore treat function pointers
|
|
* as if they all point to functions that return int. When
|
|
* 4432549 is fixed, the lookupname() call below should be
|
|
* replaced with `ntdp'.
|
|
*/
|
|
(*rtdp)->t_fndef->fn_ret = lookupname("int");
|
|
break;
|
|
case 'a':
|
|
case 'z':
|
|
cp++;
|
|
if (*cp++ != 'r')
|
|
expected("tdefdecl/[az]", "r", cp - 1);
|
|
*rtdp = xcalloc(sizeof (**rtdp));
|
|
(*rtdp)->t_type = ARRAY;
|
|
(*rtdp)->t_id = h;
|
|
cp = arraydef(cp, rtdp);
|
|
break;
|
|
case 'x':
|
|
c = *++cp;
|
|
if (c != 's' && c != 'u' && c != 'e')
|
|
expected("tdefdecl/x", "[sue]", cp - 1);
|
|
cp = name(cp + 1, &w);
|
|
|
|
ntdp = xcalloc(sizeof (*ntdp));
|
|
ntdp->t_type = FORWARD;
|
|
ntdp->t_name = w;
|
|
/*
|
|
* We explicitly don't set t_id here - the caller will do it.
|
|
* The caller may want to use a real type ID, or they may
|
|
* choose to make one up.
|
|
*/
|
|
|
|
*rtdp = ntdp;
|
|
break;
|
|
|
|
case 'B': /* volatile */
|
|
cp = tdefdecl(cp + 1, h, &ntdp);
|
|
|
|
if (!ntdp->t_id)
|
|
ntdp->t_id = faketypenumber++;
|
|
|
|
*rtdp = xcalloc(sizeof (**rtdp));
|
|
(*rtdp)->t_type = VOLATILE;
|
|
(*rtdp)->t_size = 0;
|
|
(*rtdp)->t_tdesc = ntdp;
|
|
(*rtdp)->t_id = h;
|
|
break;
|
|
|
|
case 'k': /* const */
|
|
cp = tdefdecl(cp + 1, h, &ntdp);
|
|
|
|
if (!ntdp->t_id)
|
|
ntdp->t_id = faketypenumber++;
|
|
|
|
*rtdp = xcalloc(sizeof (**rtdp));
|
|
(*rtdp)->t_type = CONST;
|
|
(*rtdp)->t_size = 0;
|
|
(*rtdp)->t_tdesc = ntdp;
|
|
(*rtdp)->t_id = h;
|
|
break;
|
|
|
|
case 'K': /* restricted */
|
|
cp = tdefdecl(cp + 1, h, &ntdp);
|
|
|
|
if (!ntdp->t_id)
|
|
ntdp->t_id = faketypenumber++;
|
|
|
|
*rtdp = xcalloc(sizeof (**rtdp));
|
|
(*rtdp)->t_type = RESTRICT;
|
|
(*rtdp)->t_size = 0;
|
|
(*rtdp)->t_tdesc = ntdp;
|
|
(*rtdp)->t_id = h;
|
|
break;
|
|
|
|
case 'u':
|
|
case 's':
|
|
cp++;
|
|
|
|
*rtdp = xcalloc(sizeof (**rtdp));
|
|
(*rtdp)->t_name = NULL;
|
|
cp = soudef(cp, (type == 'u') ? UNION : STRUCT, rtdp);
|
|
break;
|
|
default:
|
|
expected("tdefdecl", "<type code>", cp);
|
|
}
|
|
return (cp);
|
|
}
|
|
|
|
static char *
|
|
intrinsic(char *cp, tdesc_t **rtdp)
|
|
{
|
|
intr_t *intr = xcalloc(sizeof (intr_t));
|
|
tdesc_t *tdp;
|
|
int width, fmt, i;
|
|
|
|
switch (*cp++) {
|
|
case 'b':
|
|
intr->intr_type = INTR_INT;
|
|
if (*cp == 's')
|
|
intr->intr_signed = 1;
|
|
else if (*cp != 'u')
|
|
expected("intrinsic/b", "[su]", cp);
|
|
cp++;
|
|
|
|
if (strchr("cbv", *cp))
|
|
intr->intr_iformat = *cp++;
|
|
|
|
cp = number(cp, &width);
|
|
if (*cp++ != ';')
|
|
expected("intrinsic/b", "; (post-width)", cp - 1);
|
|
|
|
cp = number(cp, &intr->intr_offset);
|
|
if (*cp++ != ';')
|
|
expected("intrinsic/b", "; (post-offset)", cp - 1);
|
|
|
|
cp = number(cp, &intr->intr_nbits);
|
|
break;
|
|
|
|
case 'R':
|
|
intr->intr_type = INTR_REAL;
|
|
for (fmt = 0, i = 0; isdigit(*(cp + i)); i++)
|
|
fmt = fmt * 10 + (*(cp + i) - '0');
|
|
|
|
if (fmt < 1 || fmt > CTF_FP_MAX)
|
|
expected("intrinsic/R", "number <= CTF_FP_MAX", cp);
|
|
|
|
intr->intr_fformat = fmt;
|
|
cp += i;
|
|
|
|
if (*cp++ != ';')
|
|
expected("intrinsic/R", ";", cp - 1);
|
|
cp = number(cp, &width);
|
|
|
|
intr->intr_nbits = width * 8;
|
|
break;
|
|
}
|
|
|
|
tdp = xcalloc(sizeof (*tdp));
|
|
tdp->t_type = INTRINSIC;
|
|
tdp->t_size = width;
|
|
tdp->t_name = NULL;
|
|
tdp->t_intr = intr;
|
|
parse_debug(3, NULL, "intrinsic: size=%d", width);
|
|
*rtdp = tdp;
|
|
|
|
return (cp);
|
|
}
|
|
|
|
static tdesc_t *
|
|
bitintrinsic(tdesc_t *template, int nbits)
|
|
{
|
|
tdesc_t *newtdp = xcalloc(sizeof (tdesc_t));
|
|
|
|
newtdp->t_name = xstrdup(template->t_name);
|
|
newtdp->t_id = faketypenumber++;
|
|
newtdp->t_type = INTRINSIC;
|
|
newtdp->t_size = template->t_size;
|
|
newtdp->t_intr = xmalloc(sizeof (intr_t));
|
|
bcopy(template->t_intr, newtdp->t_intr, sizeof (intr_t));
|
|
newtdp->t_intr->intr_nbits = nbits;
|
|
|
|
return (newtdp);
|
|
}
|
|
|
|
static char *
|
|
offsize(char *cp, mlist_t *mlp)
|
|
{
|
|
int offset, size;
|
|
|
|
if (*cp == ',')
|
|
cp++;
|
|
cp = number(cp, &offset);
|
|
if (*cp++ != ',')
|
|
expected("offsize/2", ",", cp - 1);
|
|
cp = number(cp, &size);
|
|
if (*cp++ != ';')
|
|
expected("offsize/3", ";", cp - 1);
|
|
mlp->ml_offset = offset;
|
|
mlp->ml_size = size;
|
|
return (cp);
|
|
}
|
|
|
|
static tdesc_t *
|
|
find_intrinsic(tdesc_t *tdp)
|
|
{
|
|
for (;;) {
|
|
switch (tdp->t_type) {
|
|
case TYPEDEF:
|
|
case VOLATILE:
|
|
case CONST:
|
|
case RESTRICT:
|
|
tdp = tdp->t_tdesc;
|
|
break;
|
|
|
|
default:
|
|
return (tdp);
|
|
}
|
|
}
|
|
}
|
|
|
|
static char *
|
|
soudef(char *cp, stabtype_t type, tdesc_t **rtdp)
|
|
{
|
|
mlist_t *mlp, **prev;
|
|
char *w;
|
|
int h;
|
|
int size;
|
|
tdesc_t *tdp, *itdp;
|
|
|
|
cp = number(cp, &size);
|
|
(*rtdp)->t_size = size;
|
|
(*rtdp)->t_type = type; /* s or u */
|
|
|
|
/*
|
|
* An '@' here indicates a bitmask follows. This is so the
|
|
* compiler can pass information to debuggers about how structures
|
|
* are passed in the v9 world. We don't need this information
|
|
* so we skip over it.
|
|
*/
|
|
if (cp[0] == '@') {
|
|
cp += 3;
|
|
}
|
|
|
|
parse_debug(3, cp, "soudef: %s size=%d", tdesc_name(*rtdp),
|
|
(*rtdp)->t_size);
|
|
|
|
prev = &((*rtdp)->t_members);
|
|
/* now fill up the fields */
|
|
while ((*cp != '\0') && (*cp != ';')) { /* signifies end of fields */
|
|
mlp = xcalloc(sizeof (*mlp));
|
|
*prev = mlp;
|
|
cp = name(cp, &w);
|
|
mlp->ml_name = w;
|
|
cp = id(cp, &h);
|
|
/*
|
|
* find the tdesc struct in the hash table for this type
|
|
* and stick a ptr in here
|
|
*/
|
|
tdp = lookup(h);
|
|
if (tdp == NULL) { /* not in hash list */
|
|
parse_debug(3, NULL, " defines %s (%d)", w, h);
|
|
if (*cp++ != '=') {
|
|
tdp = unres_new(h);
|
|
parse_debug(3, NULL,
|
|
" refers to %s (unresolved %d)",
|
|
(w ? w : "anon"), h);
|
|
} else {
|
|
cp = tdefdecl(cp, h, &tdp);
|
|
|
|
if (tdp->t_id && tdp->t_id != h) {
|
|
tdesc_t *ntdp = xcalloc(sizeof (*ntdp));
|
|
|
|
ntdp->t_type = TYPEDEF;
|
|
ntdp->t_tdesc = tdp;
|
|
tdp = ntdp;
|
|
}
|
|
|
|
addhash(tdp, h);
|
|
parse_debug(4, cp,
|
|
" soudef now looking at ");
|
|
cp++;
|
|
}
|
|
} else {
|
|
parse_debug(3, NULL, " refers to %s (%d, %s)",
|
|
w ? w : "anon", h, tdesc_name(tdp));
|
|
}
|
|
|
|
cp = offsize(cp, mlp);
|
|
|
|
itdp = find_intrinsic(tdp);
|
|
if (itdp->t_type == INTRINSIC) {
|
|
if (mlp->ml_size != itdp->t_intr->intr_nbits) {
|
|
parse_debug(4, cp, "making %d bit intrinsic "
|
|
"from %s", mlp->ml_size, tdesc_name(itdp));
|
|
mlp->ml_type = bitintrinsic(itdp, mlp->ml_size);
|
|
} else
|
|
mlp->ml_type = tdp;
|
|
} else if (itdp->t_type == TYPEDEF_UNRES) {
|
|
list_add(&typedbitfldmems, mlp);
|
|
mlp->ml_type = tdp;
|
|
} else {
|
|
mlp->ml_type = tdp;
|
|
}
|
|
|
|
/* cp is now pointing to next field */
|
|
prev = &mlp->ml_next;
|
|
}
|
|
return (cp);
|
|
}
|
|
|
|
static char *
|
|
arraydef(char *cp, tdesc_t **rtdp)
|
|
{
|
|
int start, end, h;
|
|
|
|
cp = id(cp, &h);
|
|
if (*cp++ != ';')
|
|
expected("arraydef/1", ";", cp - 1);
|
|
|
|
(*rtdp)->t_ardef = xcalloc(sizeof (ardef_t));
|
|
(*rtdp)->t_ardef->ad_idxtype = lookup(h);
|
|
|
|
cp = number(cp, &start); /* lower */
|
|
if (*cp++ != ';')
|
|
expected("arraydef/2", ";", cp - 1);
|
|
|
|
if (*cp == 'S') {
|
|
/*
|
|
* variable length array - treat as null dimensioned
|
|
*
|
|
* For VLA variables on sparc, SS12 generated stab entry
|
|
* looks as follows:
|
|
* .stabs "buf:(0,28)=zr(0,4);0;S-12;(0,1)", 0x80, 0, 0, -16
|
|
* Whereas SS12u1 generated stab entry looks like this:
|
|
* .stabs "buf:(0,28)=zr(0,4);0;S0;(0,1)", 0x80, 0, 0, 0
|
|
* On x86, both versions generate the first type of entry.
|
|
* We should be able to parse both.
|
|
*/
|
|
cp++;
|
|
if (*cp == '-')
|
|
cp++;
|
|
cp = number(cp, &end);
|
|
end = start;
|
|
} else {
|
|
/*
|
|
* normal fixed-dimension array
|
|
* Stab entry for this looks as follows :
|
|
* .stabs "x:(0,28)=ar(0,4);0;9;(0,3)", 0x80, 0, 40, 0
|
|
*/
|
|
cp = number(cp, &end); /* upper */
|
|
}
|
|
|
|
if (*cp++ != ';')
|
|
expected("arraydef/3", ";", cp - 1);
|
|
(*rtdp)->t_ardef->ad_nelems = end - start + 1;
|
|
cp = tdefdecl(cp, h, &((*rtdp)->t_ardef->ad_contents));
|
|
|
|
parse_debug(3, cp, "defined array idx type %d %d-%d next ",
|
|
h, start, end);
|
|
|
|
return (cp);
|
|
}
|
|
|
|
static void
|
|
enumdef(char *cp, tdesc_t **rtdp)
|
|
{
|
|
elist_t *elp, **prev;
|
|
char *w;
|
|
|
|
(*rtdp)->t_type = ENUM;
|
|
(*rtdp)->t_emem = NULL;
|
|
|
|
prev = &((*rtdp)->t_emem);
|
|
while (*cp != ';') {
|
|
elp = xcalloc(sizeof (*elp));
|
|
elp->el_next = NULL;
|
|
*prev = elp;
|
|
cp = name(cp, &w);
|
|
elp->el_name = w;
|
|
cp = number(cp, &elp->el_number);
|
|
parse_debug(3, NULL, "enum %s: %s=%d", tdesc_name(*rtdp),
|
|
elp->el_name, elp->el_number);
|
|
prev = &elp->el_next;
|
|
if (*cp++ != ',')
|
|
expected("enumdef", ",", cp - 1);
|
|
}
|
|
}
|
|
|
|
tdesc_t *
|
|
lookup_name(tdesc_t **hash, const char *name)
|
|
{
|
|
int bucket = compute_sum(name);
|
|
tdesc_t *tdp, *ttdp = NULL;
|
|
|
|
for (tdp = hash[bucket]; tdp != NULL; tdp = tdp->t_next) {
|
|
if (tdp->t_name != NULL && strcmp(tdp->t_name, name) == 0) {
|
|
if (tdp->t_type == STRUCT || tdp->t_type == UNION ||
|
|
tdp->t_type == ENUM || tdp->t_type == INTRINSIC)
|
|
return (tdp);
|
|
if (tdp->t_type == TYPEDEF)
|
|
ttdp = tdp;
|
|
}
|
|
}
|
|
return (ttdp);
|
|
}
|
|
|
|
tdesc_t *
|
|
lookupname(const char *name)
|
|
{
|
|
return (lookup_name(name_table, name));
|
|
}
|
|
|
|
/*
|
|
* Add a node to the hash queues.
|
|
*/
|
|
static void
|
|
addhash(tdesc_t *tdp, int num)
|
|
{
|
|
int hash = HASH(num);
|
|
tdesc_t *ttdp;
|
|
char added_num = 0, added_name = 0;
|
|
|
|
/*
|
|
* If it already exists in the hash table don't add it again
|
|
* (but still check to see if the name should be hashed).
|
|
*/
|
|
ttdp = lookup(num);
|
|
|
|
if (ttdp == NULL) {
|
|
tdp->t_id = num;
|
|
tdp->t_hash = hash_table[hash];
|
|
hash_table[hash] = tdp;
|
|
added_num = 1;
|
|
}
|
|
|
|
if (tdp->t_name != NULL) {
|
|
ttdp = lookupname(tdp->t_name);
|
|
if (ttdp == NULL) {
|
|
hash = compute_sum(tdp->t_name);
|
|
tdp->t_next = name_table[hash];
|
|
name_table[hash] = tdp;
|
|
added_name = 1;
|
|
}
|
|
}
|
|
if (!added_num && !added_name) {
|
|
terminate("stabs: broken hash\n");
|
|
}
|
|
}
|
|
|
|
static int
|
|
compute_sum(const char *w)
|
|
{
|
|
char c;
|
|
int sum;
|
|
|
|
for (sum = 0; (c = *w) != '\0'; sum += c, w++)
|
|
;
|
|
return (HASH(sum));
|
|
}
|
|
|
|
static void
|
|
reset(void)
|
|
{
|
|
longjmp(resetbuf, 1);
|
|
}
|
|
|
|
void
|
|
check_hash(void)
|
|
{
|
|
tdesc_t *tdp;
|
|
int i;
|
|
|
|
printf("checking hash\n");
|
|
for (i = 0; i < BUCKETS; i++) {
|
|
if (hash_table[i]) {
|
|
for (tdp = hash_table[i]->t_hash;
|
|
tdp && tdp != hash_table[i];
|
|
tdp = tdp->t_hash)
|
|
continue;
|
|
if (tdp) {
|
|
terminate("cycle in hash bucket %d\n", i);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (name_table[i]) {
|
|
for (tdp = name_table[i]->t_next;
|
|
tdp && tdp != name_table[i];
|
|
tdp = tdp->t_next)
|
|
continue;
|
|
if (tdp) {
|
|
terminate("cycle in name bucket %d\n", i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
printf("done\n");
|
|
}
|
|
|
|
/*ARGSUSED1*/
|
|
static int
|
|
resolve_typed_bitfields_cb(mlist_t *ml, void *private)
|
|
{
|
|
tdesc_t *tdp = ml->ml_type;
|
|
|
|
debug(3, "Resolving typed bitfields (member %s)\n",
|
|
(ml->ml_name ? ml->ml_name : "(anon)"));
|
|
|
|
while (tdp) {
|
|
switch (tdp->t_type) {
|
|
case INTRINSIC:
|
|
if (ml->ml_size != tdp->t_intr->intr_nbits) {
|
|
debug(3, "making %d bit intrinsic from %s",
|
|
ml->ml_size, tdesc_name(tdp));
|
|
ml->ml_type = bitintrinsic(tdp, ml->ml_size);
|
|
} else {
|
|
debug(3, "using existing %d bit %s intrinsic",
|
|
ml->ml_size, tdesc_name(tdp));
|
|
ml->ml_type = tdp;
|
|
}
|
|
return (1);
|
|
|
|
case POINTER:
|
|
case TYPEDEF:
|
|
case VOLATILE:
|
|
case CONST:
|
|
case RESTRICT:
|
|
tdp = tdp->t_tdesc;
|
|
break;
|
|
|
|
default:
|
|
return (1);
|
|
}
|
|
}
|
|
|
|
terminate("type chain for bitfield member %s has a NULL", ml->ml_name);
|
|
/*NOTREACHED*/
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
resolve_typed_bitfields(void)
|
|
{
|
|
(void) list_iter(typedbitfldmems,
|
|
(int (*)())resolve_typed_bitfields_cb, NULL);
|
|
}
|