summaryrefslogtreecommitdiff
path: root/usr/src/tools/ctf/stabs/common
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/tools/ctf/stabs/common
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/tools/ctf/stabs/common')
-rw-r--r--usr/src/tools/ctf/stabs/common/ctfstabs.c304
-rw-r--r--usr/src/tools/ctf/stabs/common/ctfstabs.h78
-rw-r--r--usr/src/tools/ctf/stabs/common/forth.c388
-rw-r--r--usr/src/tools/ctf/stabs/common/forth.h73
-rw-r--r--usr/src/tools/ctf/stabs/common/fth_enum.c89
-rw-r--r--usr/src/tools/ctf/stabs/common/fth_struct.c485
-rw-r--r--usr/src/tools/ctf/stabs/common/genassym.c334
7 files changed, 1751 insertions, 0 deletions
diff --git a/usr/src/tools/ctf/stabs/common/ctfstabs.c b/usr/src/tools/ctf/stabs/common/ctfstabs.c
new file mode 100644
index 0000000000..3b628d52a5
--- /dev/null
+++ b/usr/src/tools/ctf/stabs/common/ctfstabs.c
@@ -0,0 +1,304 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This program has two modes.
+ *
+ * In the first, or genassym, mode, it generates a header file containing
+ * #define'd values for offsets and other information about requested
+ * structures and arrays. This header file can then be used by assembly
+ * source files to access those structures without having to hard-code the
+ * offsets. The offsets and values in the header file are derived from the
+ * CTF data in a provided object file.
+ *
+ * The second mode creates forthdebug macros for specified structures and
+ * members from an object file. The macros are created using the CTF data in
+ * the object file.
+ *
+ * Forthdebug macros and offsets header files are generated using the same
+ * tool for historical reasons.
+ *
+ * The input and output files, and their interaction with the tool are
+ * shown below:
+ *
+ * --------------- ----------- cc -c -g ------------------
+ * |#includes | -----> |#includes| ------------> |object file with|
+ * |mode-specific| ----------- ctfconvert | CTF data |
+ * | directives| ------------------
+ * --------------- |
+ * | | obj_file
+ * | V
+ * | ------------ ----------
+ * \-------------> |directives| ---------------> |ctfstabs|
+ * ------------ input_template ----------
+ * |
+ * V
+ * ---------------
+ * Mode-specific input and output formats are |mode-specific|
+ * described in forth.c and genassym.c | output |
+ * ---------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "ctf_headers.h"
+#include "utils.h"
+#include "memory.h"
+#include "ctfstabs.h"
+
+#define WORD_LEN 256
+
+static int lineno;
+
+FILE *out;
+ctf_file_t *ctf;
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr, "Usage: %s -t genassym [-m model] "
+ "[-i input_template] [-o output] obj_file\n", getpname());
+ (void) fprintf(stderr, " %s -t forth [-m model] "
+ "[-i input_template] [-o output] obj_file\n", getpname());
+ exit(2);
+}
+
+/*PRINTFLIKE1*/
+int
+parse_warn(char *format, ...)
+{
+ va_list alist;
+
+ (void) fprintf(stderr, "%s: Line %d: ", getpname(), lineno);
+
+ va_start(alist, format);
+ (void) vfprintf(stderr, format, alist);
+ va_end(alist);
+
+ (void) fprintf(stderr, "\n");
+
+ return (-1);
+}
+
+#define READLINE_BUF_INCR 2
+
+/*
+ * Read a line of input into a statically-allocated buffer. If the line
+ * is larger than the buffer, the buffer will be dynamically resized.
+ * Subsequent calls will overwrite the buffer.
+ */
+static char *
+readline(FILE *fp)
+{
+ static char *buf, *bptr;
+ static int buflen;
+
+ if (buflen == 0) {
+ buf = xmalloc(READLINE_BUF_INCR);
+ buflen = READLINE_BUF_INCR;
+ }
+
+ bptr = buf;
+ for (;;) {
+ size_t len, off;
+
+ if (fgets(bptr, buflen - (size_t)(bptr - buf), fp) == NULL)
+ return (NULL);
+
+ len = strlen(bptr);
+
+ if (bptr[len - 1] == '\n')
+ return (buf);
+
+ off = (size_t)((bptr + len) - buf);
+ buflen += READLINE_BUF_INCR;
+ buf = xrealloc(buf, buflen);
+ bptr = buf + off;
+ }
+}
+
+/*
+ * We're only given a type name. Even if it's a struct or a union, we
+ * still only get the struct or union name. We therefore iterate through
+ * the possible prefixes, trying to find the right type.
+ */
+ctf_id_t
+find_type(char *name)
+{
+ char fullname[WORD_LEN];
+ ctf_id_t id;
+
+ if ((id = ctf_lookup_by_name(ctf, name)) != CTF_ERR)
+ return (id);
+
+ (void) snprintf(fullname, WORD_LEN, "struct %s", name);
+ if ((id = ctf_lookup_by_name(ctf, fullname)) != CTF_ERR)
+ return (id);
+
+ (void) snprintf(fullname, WORD_LEN, "union %s", name);
+ if ((id = ctf_lookup_by_name(ctf, fullname)) != CTF_ERR)
+ return (id);
+
+ (void) snprintf(fullname, WORD_LEN, "enum %s", name);
+ if ((id = ctf_lookup_by_name(ctf, fullname)) != CTF_ERR)
+ return (id);
+
+ return (CTF_ERR);
+}
+
+static int
+process_ifile(FILE *tmpl, proc_ops_t *ops)
+{
+ char *line;
+ int skipping;
+ size_t len;
+ int err = 0;
+
+ for (lineno = skipping = 0; (line = readline(tmpl)) != NULL; lineno++) {
+ len = strlen(line) - 1;
+ line[len] = '\0';
+
+ if (len == 0)
+ skipping = 0;
+
+ if (skipping == 1)
+ continue;
+
+ if (ops->po_line(line) < 0) {
+ (void) parse_warn("Error found: skipping to the next "
+ "blank line");
+ err++;
+ skipping = 1;
+ continue;
+ }
+ }
+
+ return (err > 0 ? -1 : 0);
+}
+
+static char *
+get_model(ctf_file_t *ctf)
+{
+ ssize_t lsz;
+ ctf_id_t lid;
+
+ /* Neither of these should fail */
+ if ((lid = ctf_lookup_by_name(ctf, "long")) == CTF_ERR ||
+ (lsz = ctf_type_size(ctf, lid)) == CTF_ERR)
+ die("Couldn't get size of long in object file");
+
+ if (lsz == 8)
+ return ("lp64");
+ else if (lsz == 4)
+ return ("ilp32");
+ else
+ die("Unexpected size of long: %d bytes\n", lsz);
+
+ return (NULL);
+}
+
+int
+main(int argc, char **argv)
+{
+ char *model = NULL, *objfile = NULL, *outfile = NULL, *tmplfile = NULL;
+ proc_ops_t *ops = &ga_ops;
+ FILE *tmpl;
+ int ctferr, c;
+
+ while ((c = getopt(argc, argv, "i:m:o:t:")) != EOF) {
+ switch (c) {
+ case 'i':
+ tmplfile = optarg;
+ break;
+ case 'm':
+ model = optarg;
+ break;
+ case 't':
+ if (strcmp(optarg, "genassym") == 0)
+ ops = &ga_ops;
+ else if (strcmp(optarg, "forth") == 0)
+ ops = &fth_ops;
+ else
+ usage();
+ break;
+
+ case 'o':
+ outfile = optarg;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (argc - optind != 1)
+ usage();
+ objfile = argv[optind];
+
+ if (tmplfile == NULL || strcmp(tmplfile, "-") == 0)
+ tmpl = stdin;
+ else if ((tmpl = fopen(tmplfile, "r")) == NULL)
+ die("Couldn't open template file %s", tmplfile);
+
+ /*
+ * this can fail if ENOENT or if there's no CTF data in the file.
+ */
+ if ((ctf = ctf_open(objfile, &ctferr)) == NULL) {
+ die("Couldn't open object file %s: %s\n", objfile,
+ ctf_errmsg(ctferr));
+ }
+
+ if (model == NULL)
+ model = get_model(ctf);
+ else if (strcmp(model, get_model(ctf)) != 0)
+ die("Model argument %s doesn't match the object file\n", model);
+
+ if (outfile == NULL || strcmp(outfile, "-") == 0)
+ out = stdout;
+ else if ((out = fopen(outfile, "w")) == NULL)
+ die("Couldn't open output file %s for writing", outfile);
+
+ if ((ops->po_init != NULL && ops->po_init(model) < 0) ||
+ (process_ifile(tmpl, ops) < 0) ||
+ (ops->po_fini != NULL && ops->po_fini() < 0)) {
+ (void) fclose(out);
+ (void) unlink(outfile);
+ return (1);
+ }
+
+ return (0);
+}
diff --git a/usr/src/tools/ctf/stabs/common/ctfstabs.h b/usr/src/tools/ctf/stabs/common/ctfstabs.h
new file mode 100644
index 0000000000..80ccc141e9
--- /dev/null
+++ b/usr/src/tools/ctf/stabs/common/ctfstabs.h
@@ -0,0 +1,78 @@
+/*
+ * 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 _CTFSTABS_H
+#define _CTFSTABS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ctf_headers.h"
+
+/*
+ * The file-reading portion of ctfstabs communicates with the type-specific
+ * backends (genassym and forth) via the proc_ops_t, one of which is supplied
+ * by each backend.
+ */
+typedef struct proc_ops {
+ /*
+ * Called prior to reading the input template. A return of -1 signals
+ * an error, and will halt processing.
+ */
+ int (*po_init)(char *);
+
+ /*
+ * Called for each line in the input file. If an error is returned,
+ * also signalled by a return of -1, input lines will be skipped, and
+ * this method will not be called, until a blank line is encountered.
+ */
+ int (*po_line)(char *);
+
+ /*
+ * Called after all input lines have been processed.
+ */
+ int (*po_fini)(void);
+} proc_ops_t;
+
+extern proc_ops_t ga_ops;
+extern proc_ops_t fth_ops;
+
+extern FILE *out; /* the output file */
+extern ctf_file_t *ctf; /* the input object file */
+
+extern int parse_warn(char *, ...);
+extern ctf_id_t find_type(char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CTFSTABS_H */
diff --git a/usr/src/tools/ctf/stabs/common/forth.c b/usr/src/tools/ctf/stabs/common/forth.c
new file mode 100644
index 0000000000..e3b5ca34ec
--- /dev/null
+++ b/usr/src/tools/ctf/stabs/common/forth.c
@@ -0,0 +1,388 @@
+/*
+ * 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"
+
+/*
+ * In this mode, we generate forthdebug macros as requested by the input
+ * template, the format of which is given below.
+ *
+ * These templates have the following elements:
+ *
+ * 1. Macro creation
+ *
+ * Given the name of a structure, union, or enum type, a forthdebug macro
+ * is created that will dump the members of the type. The type can be
+ * specified as a standalone structure, union, or enum, or it can be
+ * described relative to another structure or union as "type.member".
+ *
+ * By default, all struct members, union members, or enum values, as
+ * appropriate, will be printed. An alternate form allows specific members
+ * of struct or union types to be printed. Both forms must be followed by a
+ * blank line. In the specific-member case, an optional format specifier can
+ * be provided that will be used to dump the contents of the member.
+ * Builtins `d' and `x' can be used to dump the member in decimal or
+ * hexadecimal, respectively. Alternatively, a custom formatter can be
+ * specified.
+ *
+ * 2. Model-specific sections
+ *
+ * `model_start' / `model_end' pairs function as an #ifdef for the ctfstabs
+ * tool. They take, as an argument, either `ilp32' or `lp64'. If a 64-bit
+ * macro is being generated (if a 64-bit object file is being used), lines
+ * between `lp64' model pairs will be processed, but lines between `ilp32'
+ * pairs will be omitted. The reverse is true for 32-bit macros.
+ *
+ * 3. Literal sections
+ *
+ * Portions of the input template file enclosed within `forth_start' /
+ * `forth_end' pairs and between `verbatim_begin' / `verbatim_end' pairs
+ * will be copied as-is to the output file.
+ *
+ * 4. Comments
+ *
+ * Lines beginning with backslashes are ignored.
+ *
+ * Example:
+ *
+ * \ dump the `foo' structure
+ * foo
+ *
+ * \ dump the `a' and `b' members of the `bar' structure. dump member `b'
+ * \ in hexadecimal
+ * bar
+ * a
+ * b x
+ *
+ * \ dump the `big' member of the `baz' structure in 64-bit macros, and
+ * \ the `small' member in 32-bit macros.
+ * baz
+ * model_start lp64
+ * big
+ * model_end
+ * model_start ilp32
+ * small
+ * model_end
+ *
+ * \ copy `literal 1' and `literal 2' to the output file
+ * verbatim_begin
+ * literal 1
+ * verbatim_end
+ * forth_start
+ * literal 2
+ * forth_end
+ *
+ * For a more complex example, see common.fdbg.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "ctf_headers.h"
+#include "ctfstabs.h"
+#include "forth.h"
+#include "utils.h"
+#include "memory.h"
+
+char *fth_curtype; /* name of the type being processed */
+static fth_type_ops_t *fth_type_ops; /* see forth.h */
+
+static char *fth_model; /* the current macro type - for model_start */
+static int fth_ignoring; /* in a non-matching model_start/end pair */
+static int fth_copying; /* in a verbatim_* or forth_* pair */
+
+static int
+fth_init(char *model)
+{
+ fth_model = model;
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+fth_null_header(ctf_id_t tid)
+{
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+fth_null_members(char *memfilter, char *format)
+{
+ return (0);
+}
+
+static int
+fth_null_trailer(void)
+{
+ return (0);
+}
+
+static fth_type_ops_t fth_null_ops = {
+ fth_null_header,
+ fth_null_members,
+ fth_null_trailer
+};
+
+/*ARGSUSED2*/
+static int
+find_member_cb(const char *memname, ctf_id_t tid, ulong_t off, void *arg)
+{
+ char *memtofind = arg;
+
+ if (strcmp(memname, memtofind) == 0)
+ return (tid);
+
+ return (0);
+}
+
+/* find the tid of a specified member */
+static ctf_id_t
+find_member(ctf_id_t tid, char *memname)
+{
+ return (ctf_member_iter(ctf, tid, find_member_cb, memname));
+}
+
+/*
+ * Begin a macro.
+ *
+ * Once we figure out the type of the thing that we're supposed to dump (struct,
+ * union, or enum), we select the proper type-specific ops-vector for dumping.
+ */
+static int
+fth_section_init(char *fullname)
+{
+ ctf_id_t ltid = 0, tid;
+ char *curtype, *lpart, *part, *npart;
+ int lkind = 0, kind;
+
+ curtype = xstrdup(fullname);
+ lpart = NULL;
+ part = strtok(fullname, ".");
+
+ /*
+ * First figure out what sort of type we're looking at. Life would be
+ * simple if we were only going to get type names, but it's not - we
+ * could also get `type.member'. In that case, we need to figure out
+ * (and dump) the type of `member' instead.
+ */
+ for (;;) {
+ if (lpart == NULL) {
+ /* First part - the struct name */
+ if ((tid = find_type(part)) == CTF_ERR ||
+ (tid = ctf_type_resolve(ctf, tid)) == CTF_ERR ||
+ (kind = ctf_type_kind(ctf, tid)) == CTF_ERR) {
+ free(curtype);
+ return (parse_warn("Couldn't find %s: %s",
+ part, ctf_errmsg(ctf_errno(ctf))));
+ }
+ } else {
+ /* Second (or more) part - the member name */
+ if (lkind != CTF_K_STRUCT && lkind != CTF_K_UNION) {
+ free(curtype);
+ return (parse_warn("%s isn't a struct/union",
+ lpart));
+ }
+
+ if ((tid = find_member(ltid, part)) <= 0) {
+ free(curtype);
+ return (parse_warn("%s isn't a member of %s",
+ part, lpart));
+ }
+
+ if ((kind = ctf_type_kind(ctf, tid)) == CTF_ERR) {
+ free(curtype);
+ return (parse_warn("Can't get kind for %s",
+ part));
+ }
+ }
+
+ /*
+ * Stop if there aren't any more parts. We use `npart' here
+ * because we don't want to clobber part - we need it later.
+ */
+ if ((npart = strtok(NULL, ".")) == NULL)
+ break;
+
+ lpart = part;
+ ltid = tid;
+ lkind = kind;
+
+ part = npart;
+ }
+
+ /*
+ * Pick the right ops vector for dumping.
+ */
+ switch (kind) {
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ fth_type_ops = &fth_struct_ops;
+ break;
+
+ case CTF_K_ENUM:
+ fth_type_ops = &fth_enum_ops;
+ break;
+
+ default:
+ fth_type_ops = &fth_null_ops;
+ free(curtype);
+ return (parse_warn("%s isn't a struct, union, or enum", part));
+ }
+
+ fth_curtype = curtype;
+
+ return (fth_type_ops->fto_header(tid));
+}
+
+static int
+fth_section_add_member(char *name, char *format)
+{
+ if (fth_curtype == NULL)
+ return (fth_section_init(name));
+
+ if (fth_type_ops->fto_members(name, format) < 0)
+ return (-1);
+
+ return (0);
+}
+
+static int
+fth_section_end(void)
+{
+ if (fth_curtype == NULL)
+ return (0);
+
+ if (fth_type_ops->fto_trailer() < 0)
+ return (-1);
+
+ free(fth_curtype);
+ fth_curtype = NULL;
+
+ return (0);
+}
+
+static int
+fth_process_line(char *line)
+{
+ char *format = NULL;
+ char *word, *name, *c;
+ int nblank = 0;
+ int n;
+
+ if (strlen(line) == 0) {
+ if (fth_section_end() < 0)
+ return (-1);
+
+ if (fth_copying == 1 || nblank++ == 1)
+ (void) fprintf(out, "\n");
+ return (0);
+ } else
+ nblank = 0;
+
+ /* skip comments */
+ if (line[0] == '\\')
+ return (0);
+
+ if (strcmp(line, "model_end") == 0) {
+ fth_ignoring = 0;
+ return (0);
+ }
+
+ if (fth_ignoring == 1)
+ return (0);
+
+ word = "model_start ";
+ if (strncmp(line, word, strlen(word)) == 0) {
+ for (c = line + strlen(word); isspace(*c); c++);
+ if (strlen(c) == strlen(fth_model) &&
+ strncmp(c, fth_model, strlen(fth_model)) == 0)
+ /* EMPTY - match */;
+ else
+ fth_ignoring = 1;
+ return (0);
+ }
+
+ if (strcmp(line, "verbatim_end") == 0 ||
+ strcmp(line, "forth_end") == 0) {
+ char *start = (strcmp(line, "verbatim_end") == 0 ?
+ "verbatim_begin" : "forth_start");
+
+ if (fth_copying == 0) {
+ (void) parse_warn("Found %s without matching %s",
+ line, start);
+ if (fth_curtype != NULL)
+ (void) fth_section_end();
+ return (-1);
+ }
+ fth_copying = 0;
+ return (0);
+ }
+
+ if (fth_copying == 1) {
+ (void) fprintf(out, "%s\n", line);
+ return (0);
+ }
+
+ if (strcmp(line, "verbatim_begin") == 0 ||
+ strcmp(line, "forth_start") == 0) {
+ if (fth_curtype != NULL) {
+ (void) parse_warn("Expected blank line between %s "
+ "macro and %s", fth_curtype, line);
+ return (fth_section_end());
+ }
+
+ fth_copying = 1;
+ return (0);
+ }
+
+ for (n = 1, word = strtok(line, " \t"); word != NULL;
+ word = strtok(NULL, " \t"), n++) {
+ if (n == 1)
+ name = word;
+ else if (n == 2)
+ format = word;
+ else
+ (void) parse_warn("Too many words");
+ }
+
+ return (fth_section_add_member(name, format));
+}
+
+static int
+fth_fini(void)
+{
+ return (fth_section_end());
+}
+
+proc_ops_t fth_ops = {
+ fth_init,
+ fth_process_line,
+ fth_fini
+};
diff --git a/usr/src/tools/ctf/stabs/common/forth.h b/usr/src/tools/ctf/stabs/common/forth.h
new file mode 100644
index 0000000000..a950a648b7
--- /dev/null
+++ b/usr/src/tools/ctf/stabs/common/forth.h
@@ -0,0 +1,73 @@
+/*
+ * 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 _FORTH_H
+#define _FORTH_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ctfstabs.h"
+
+/*
+ * The macros emitted for structs/unions and enums differ, but their
+ * formatting in the input file and construction method is roughly the same.
+ * If any of the ops return -1, the remainder of the type being processed is
+ * skipped, and an error is signaled to the main portion of ctfstabs.
+ */
+typedef struct fth_type_ops {
+ /*
+ * Called to start a definition.
+ */
+ int (*fto_header)(ctf_id_t);
+
+ /*
+ * When a specific-member request for a struct or union type is
+ * encountered, this op will be invoked for each requested member.
+ */
+ int (*fto_members)(char *, char *);
+
+ /*
+ * Invoked when the current open definition is to be finished.
+ */
+ int (*fto_trailer)(void);
+} fth_type_ops_t;
+
+/* forth.c */
+extern char *fth_curtype;
+
+/* fth_struct.c */
+extern fth_type_ops_t fth_enum_ops;
+extern fth_type_ops_t fth_struct_ops;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FORTH_H */
diff --git a/usr/src/tools/ctf/stabs/common/fth_enum.c b/usr/src/tools/ctf/stabs/common/fth_enum.c
new file mode 100644
index 0000000000..47542dcbf3
--- /dev/null
+++ b/usr/src/tools/ctf/stabs/common/fth_enum.c
@@ -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 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Used to dump enums in forth mode.
+ *
+ * Enums are simple - there is no member-specific mode for them. We get
+ * the header op at the start, and we save the type id for dumping later.
+ * If we get the members op, we've been invoked in member-specific mode,
+ * which is a syntax error for an enum. When we ge the trailer op, we
+ * dump all of the members and the trailer thus concluding the enum.
+ */
+
+#include "forth.h"
+
+static ctf_id_t fth_enum_curtid;
+static int fth_enum_curnmems;
+
+static int
+fth_enum_header(ctf_id_t tid)
+{
+ fth_enum_curtid = tid;
+
+ (void) fprintf(out, "\n");
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+fth_enum_members(char *memfilter, char *format)
+{
+ return (parse_warn("Member-specific mode cannot be used for "
+ " enums"));
+}
+
+/*ARGSUSED2*/
+static int
+fth_enum_cb(const char *name, int value, void *arg)
+{
+ (void) fprintf(out, "here ,\" %s\" %x\n", name, value);
+ fth_enum_curnmems++;
+
+ return (0);
+}
+
+static int
+fth_enum_trailer(void)
+{
+ if (ctf_enum_iter(ctf, fth_enum_curtid, fth_enum_cb, NULL) != 0)
+ return (-1);
+
+ (void) fprintf(out, "%x c-enum .%s\n", fth_enum_curnmems, fth_curtype);
+
+ fth_enum_curnmems = 0;
+
+ return (0);
+}
+
+fth_type_ops_t fth_enum_ops = {
+ fth_enum_header,
+ fth_enum_members,
+ fth_enum_trailer
+};
diff --git a/usr/src/tools/ctf/stabs/common/fth_struct.c b/usr/src/tools/ctf/stabs/common/fth_struct.c
new file mode 100644
index 0000000000..d3bd2ef0d1
--- /dev/null
+++ b/usr/src/tools/ctf/stabs/common/fth_struct.c
@@ -0,0 +1,485 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Used to dump structures and unions in forth mode.
+ *
+ * structures and unions are a bit more complicated than enums. To make things
+ * just that much more interesting, we have to dump the members in reverse
+ * order, which is nice. But wait! It gets better! For compatibility reasons,
+ * we need to dump the members in reverse-offset order, even if member-specific
+ * mode was used to request the members in something other than that order.
+ *
+ * The header op prints the macro header and saves the type being printed.
+ *
+ * In member-specific mode, the member op will be invoked for each structure
+ * or union member. The member op adds the member name, format, type ID,
+ * and offset to a list, sorted in reverse order by offset.
+ *
+ * The trailer op is called when the structure or enum is complete. If no
+ * members were specifically requested, then the trailer iterates through all
+ * of the members of the structure, pretending they were. Each member is thus
+ * added, in reverse-offset order, to the list used in specific-member mode.
+ * Either way, we then proceed through the list, dumping each member out with
+ * fth_print_member. Structure and union members are printed out differently,
+ * depending on member type, as follows:
+ *
+ * Integer:
+ * Normal integers: ' <format> <offset> <type>-field <name>
+ * <format> defaults to ".d" for enums, ".x" for others
+ * <offset> is the member offset, in bytes.
+ * <type> is "byte", "short", "long", or "ext" for 8-, 16-, 32-, and
+ * 64-bit integers, respectively.
+ * <name> is the name of the member being printed
+ *
+ * Bitfields: ' <format> <shift> <mask> <offset> bits-field <name>
+ * <format> defaults to ".x"
+ * <shift> is the number of times to right-shift the masked value
+ * <mask> use to extract the bit-field value from the read value
+ * <offset> is the member offset, in bytes
+ * <name> is the name of the member being printed
+ *
+ * Float: Ignored
+ *
+ * Pointer: ' <format> <offset> ptr-field <name>
+ * <format> defaults to .x
+ * <offset> is in bytes
+ * <name> is the name of the member being printed
+ *
+ * Array:
+ * Arrays have a content-type-specific prefix, followed by an array
+ * suffix. The resulting line looks like this if the array contents
+ * type is an integer, a pointer, or an enum:
+ *
+ * ' <fldc> ' <fmt> <sz> <elsz> <off> array-field <name>
+ *
+ * The following is printed for array contents that are arrays:
+ *
+ * ' noop ' .x <sz> <elsz> <off> array-field <name>
+ *
+ * The following is printed for array contents that are structs:
+ *
+ * ' noop ' <fmt> <sz> <elsz> <off> array-field <name>
+ *
+ * <fldc> is "c@", "w@", "l@", or "x@", depending on whether array
+ * elements are 8, 16, 32 or 64 bits wide.
+ * <fmt> defaults to ".x"
+ * <sz> is the size of the array, in bytes
+ * <elsz> is the size of the array elements
+ * <off> is the member offset, in bytes
+ * <name> is the nam eof the member being printed
+ *
+ * Struct/Union: ' <format> <offset> struct-field <name>
+ * <format> defaults to ".x"
+ * <offset> is the member offset, in bytes
+ * <name> is the name of the member being printed
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ctf_headers.h"
+#include "forth.h"
+#include "list.h"
+#include "memory.h"
+
+static ctf_id_t fth_str_curtid;
+static list_t *fth_str_curmems;
+
+/*
+ * Node type for the member-storage list (fth_str_curmems) built by
+ * fth_struct_members()
+ */
+typedef struct fth_str_mem {
+ char *fsm_memname;
+ char *fsm_format;
+ ctf_id_t fsm_tid;
+ ulong_t fsm_off;
+} fth_str_mem_t;
+
+typedef struct fth_struct_members_data {
+ char *fsmd_strname;
+ char *fsmd_memfilter;
+ char *fsmd_format;
+ int fsmd_matched;
+} fth_struct_members_data_t;
+
+static int fth_print_member(fth_str_mem_t *, int);
+
+/* Comparison routined used to insert members into the fth_str_curmems list */
+static int
+fth_struct_memcmp(void *m1, void *m2)
+{
+ fth_str_mem_t *mem1 = m1, *mem2 = m2;
+
+ if (mem1->fsm_off < mem2->fsm_off)
+ return (1);
+ else if (mem1->fsm_off > mem2->fsm_off)
+ return (-1);
+ else
+ return (0);
+}
+
+static void
+fth_free_str_mem(fth_str_mem_t *mem)
+{
+ free(mem->fsm_memname);
+ if (mem->fsm_format)
+ free(mem->fsm_format);
+ free(mem);
+}
+
+static int
+fth_struct_header(ctf_id_t tid)
+{
+ ssize_t sz;
+
+ fth_str_curtid = tid;
+ fth_str_curmems = NULL;
+
+ if ((sz = ctf_type_size(ctf, fth_str_curtid)) == CTF_ERR)
+ return (parse_warn("Can't get size for %s", fth_curtype));
+
+ (void) fprintf(out, "\n");
+ (void) fprintf(out, "vocabulary %s-words\n", fth_curtype);
+ (void) fprintf(out, "h# %x constant %s-sz\n", sz, fth_curtype);
+ (void) fprintf(out, "%x ' %s-words c-struct .%s\n", sz, fth_curtype,
+ fth_curtype);
+ (void) fprintf(out, "also %s-words definitions\n\n", fth_curtype);
+
+ return (0);
+}
+
+/* Print the array prefix for integer and pointer members */
+static int
+fth_print_level(uint_t bits, char *format)
+{
+ if ((bits & (bits - 1)) != 0 ||(bits % 8) != 0 || bits > 64) {
+ return (parse_warn("Unexpected bit size %d in %s",
+ bits, fth_curtype));
+ }
+
+ (void) fprintf(out, "' %c@ ' %s", " cw l x"[bits / 8], format);
+
+ return (0);
+}
+
+/*
+ * Return the format to be used to print the member. If one of the builtin
+ * formats "d" or "x" were specified, return ".d" or ".x", respectively.
+ * Otherwise, use the user-provided format as is, or use the default if none
+ * was provided.
+ */
+static char *
+fth_convert_format(char *format, char *def)
+{
+ static char dot[3] = ".";
+
+ if (format == NULL)
+ return (def);
+ else if (strlen(format) == 1) {
+ dot[1] = *format;
+ return (dot);
+ } else
+ return (format);
+}
+
+static int
+fth_print_integer(const char *memname, ulong_t off, uint_t bits, char *format,
+ int level)
+{
+ format = fth_convert_format(format, ".x");
+
+ if (bits > 64) {
+ return (parse_warn("%s.%s is too large (>8 bytes)",
+ fth_curtype, memname));
+ }
+
+ if (level != 0)
+ return (fth_print_level(bits, format));
+
+ if ((bits % NBBY) != 0 || (bits & (bits - 1)) != 0) {
+ /* bit field */
+ uint_t offset, shift, mask;
+
+ offset = (off / 32) * 4;
+ shift = 32 - ((off % 32) + bits);
+ mask = ((1 << bits) - 1) << shift;
+
+ (void) fprintf(out, "' %s %x %x %x bits-field %s\n",
+ format, shift, mask, offset, memname);
+
+ } else {
+ char *type[] = {
+ NULL, "byte", "short", NULL, "long",
+ NULL, NULL, NULL, "ext"
+ };
+
+ (void) fprintf(out, "' %s %lx %s-field %s\n", format, off / 8,
+ type[bits / 8], memname);
+ }
+
+ return (0);
+}
+
+static int
+fth_print_pointer(const char *memname, ulong_t off, uint_t bits, char *format,
+ int level)
+{
+ format = fth_convert_format(format, ".x");
+
+ if (level != 0)
+ return (fth_print_level(bits, format));
+
+ (void) fprintf(out, "' %s %lx ptr-field %s\n", format, off / 8,
+ memname);
+
+ return (0);
+}
+
+static int
+fth_print_struct(char *memname, ulong_t off, char *format,
+ int level)
+{
+ format = fth_convert_format(format, ".x");
+
+ if (level != 0)
+ (void) fprintf(out, "' noop ' %s", format);
+ else {
+ (void) fprintf(out, "' %s %lx struct-field %s\n", format,
+ off / 8, memname);
+ }
+
+ return (0);
+}
+
+static int
+fth_print_enum(char *memname, ulong_t off, char *format,
+ int level)
+{
+ format = fth_convert_format(format, ".d");
+
+ if (level != 0)
+ (void) fprintf(out, "' l@ ' %s", format);
+ else {
+ (void) fprintf(out, "' %s %lx long-field %s\n", format, off / 8,
+ memname);
+ }
+
+ return (0);
+}
+
+static int
+fth_print_array(char *memname, ctf_id_t tid, ulong_t off, ssize_t sz,
+ char *format, int level)
+{
+ if (level != 0)
+ (void) fprintf(out, "' noop ' .x");
+ else {
+ fth_str_mem_t mem;
+ ctf_arinfo_t ar;
+
+ /*
+ * print the prefix for the array contents type, then print
+ * the array macro
+ */
+
+ if (ctf_array_info(ctf, tid, &ar) == CTF_ERR) {
+ return (parse_warn("Can't read array in %s.%s",
+ fth_curtype, memname));
+ }
+
+ mem.fsm_memname = memname;
+ mem.fsm_format = format;
+ mem.fsm_tid = ar.ctr_contents;
+ mem.fsm_off = off;
+
+ if (fth_print_member(&mem, level + 1) < 0)
+ return (-1);
+
+ (void) fprintf(out, " %x %x %lx array-field %s\n", sz,
+ (sz / ar.ctr_nelems), off / 8, memname);
+ }
+
+ return (0);
+}
+
+/* dump a structure or union member */
+static int
+fth_print_member(fth_str_mem_t *mem, int level)
+{
+ ctf_encoding_t e;
+ ctf_id_t tid;
+ int kind;
+ ssize_t sz;
+
+ if ((tid = ctf_type_resolve(ctf, mem->fsm_tid)) == CTF_ERR) {
+ return (parse_warn("Can't resolve %s.%s", fth_curtype,
+ mem->fsm_memname));
+ }
+
+ if ((kind = ctf_type_kind(ctf, tid)) == CTF_ERR) {
+ return (parse_warn("Can't get kind for %s.%s",
+ fth_curtype, mem->fsm_memname));
+ }
+
+ if ((sz = ctf_type_size(ctf, tid)) == CTF_ERR) {
+ return (parse_warn("Can't get size for %s.%s",
+ fth_curtype, mem->fsm_memname));
+ }
+
+ switch (kind) {
+ case CTF_K_INTEGER:
+ if (ctf_type_encoding(ctf, tid, &e) == CTF_ERR)
+ return (parse_warn("Can't get encoding for %ld", tid));
+
+ return (fth_print_integer(mem->fsm_memname, mem->fsm_off,
+ e.cte_bits, mem->fsm_format, level));
+
+ case CTF_K_FLOAT:
+ (void) parse_warn("Ignoring floating point member %s.%s",
+ fth_curtype, mem->fsm_memname);
+ return (0);
+
+ case CTF_K_POINTER:
+ return (fth_print_pointer(mem->fsm_memname, mem->fsm_off,
+ sz * 8, mem->fsm_format, level));
+
+ case CTF_K_ARRAY:
+ return (fth_print_array(mem->fsm_memname, tid, mem->fsm_off, sz,
+ mem->fsm_format, level));
+
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ return (fth_print_struct(mem->fsm_memname, mem->fsm_off,
+ mem->fsm_format, level));
+
+ case CTF_K_ENUM:
+ return (fth_print_enum(mem->fsm_memname, mem->fsm_off,
+ mem->fsm_format, level));
+
+ case CTF_K_FORWARD:
+ return (parse_warn("Type %ld in %s.%s is undefined", tid,
+ fth_curtype, mem->fsm_memname));
+
+ default:
+ return (parse_warn("Unexpected kind %d for %s.%s", kind,
+ fth_curtype, mem->fsm_memname));
+ }
+}
+
+/*
+ * Add a member to list of members to be printed (fth_str_curmems). If
+ * fsmd_memfilter is non-null, only add this member if its name matches that
+ * in the filter.
+ */
+static int
+fth_struct_members_cb(const char *memname, ctf_id_t tid, ulong_t off, void *arg)
+{
+ fth_struct_members_data_t *fsmd = arg;
+ fth_str_mem_t *mem;
+
+ if (fsmd->fsmd_memfilter != NULL && strcmp(fsmd->fsmd_memfilter,
+ memname) != 0)
+ return (0);
+
+ fsmd->fsmd_matched = 1;
+
+ mem = xcalloc(sizeof (fth_str_mem_t));
+ mem->fsm_memname = xstrdup(memname);
+ if (fsmd->fsmd_format)
+ mem->fsm_format = xstrdup(fsmd->fsmd_format);
+ mem->fsm_tid = tid;
+ mem->fsm_off = off;
+
+ slist_add(&fth_str_curmems, mem, fth_struct_memcmp);
+
+ return (0);
+}
+
+/*
+ * If memfilter is non-null, iterate through the members of this type, causing
+ * every member to be added to the list. Otherwise, use the iterator and
+ * the callback to add only the specified member.
+ */
+static int
+fth_struct_members(char *memfilter, char *format)
+{
+ fth_struct_members_data_t fsmd;
+
+ fsmd.fsmd_strname = fth_curtype;
+ fsmd.fsmd_memfilter = memfilter;
+ fsmd.fsmd_format = format;
+ fsmd.fsmd_matched = 0;
+
+ if (ctf_member_iter(ctf, fth_str_curtid, fth_struct_members_cb,
+ &fsmd) != 0)
+ return (-1);
+
+ if (memfilter != NULL && fsmd.fsmd_matched == 0) {
+ return (parse_warn("Invalid member %s.%s", fth_curtype,
+ memfilter));
+ }
+
+ return (0);
+}
+
+static int
+fth_struct_trailer(void)
+{
+ if (list_count(fth_str_curmems) == 0) {
+ if (fth_struct_members(NULL, NULL) < 0)
+ return (-1);
+ }
+
+ while (!list_empty(fth_str_curmems)) {
+ fth_str_mem_t *mem = list_remove(&fth_str_curmems,
+ list_first(fth_str_curmems), NULL, NULL);
+
+ if (fth_print_member(mem, 0) < 0)
+ return (-1);
+
+ fth_free_str_mem(mem);
+ }
+
+ (void) fprintf(out, "\n");
+ (void) fprintf(out, "kdbg-words definitions\n");
+ (void) fprintf(out, "previous\n");
+ (void) fprintf(out, "\n");
+ (void) fprintf(out, "\\ end %s section\n", fth_curtype);
+ (void) fprintf(out, "\n");
+
+ return (0);
+}
+
+fth_type_ops_t fth_struct_ops = {
+ fth_struct_header,
+ fth_struct_members,
+ fth_struct_trailer
+};
diff --git a/usr/src/tools/ctf/stabs/common/genassym.c b/usr/src/tools/ctf/stabs/common/genassym.c
new file mode 100644
index 0000000000..a7d37f454c
--- /dev/null
+++ b/usr/src/tools/ctf/stabs/common/genassym.c
@@ -0,0 +1,334 @@
+/*
+ * 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"
+
+/*
+ * In this mode, we generate header files containg various #defines which can
+ * be used to access members of various structures, and to walk through arrays.
+ * The input template specifies the structures and members for whom #defines
+ * are to be generated.
+ *
+ * The template has the following elements
+ *
+ * 1. Given the name of a structure or union, #defines can be generated that
+ * describe the type. If requested, #defines that give the size and the
+ * log2 (shift) of the structure will be generated. The latter can only
+ * be requested for structures whose size is a power of two.
+ *
+ * Per-member #defines are also generated. The value of these defines will
+ * be the offsets necessary to access the members they describe. By
+ * default, the name of the #define will be the name of the member, in upper
+ * case, but a user-supplied version can be used instead. If the member is
+ * an array, an extra #define will be generated that will give the increment
+ * needed to access individual array elements. The name of the increment
+ * #define will be identical to that of the member #define, but with an
+ * "_INCR" suffix.
+ *
+ * 2. Literal cpp directives
+ *
+ * Lines beginning with "\#" are copied directly to the output file.
+ *
+ * 3. Comments
+ *
+ * Lines beginning with backslashes (excluding the literal cpp directives
+ * described above) are ignored.
+ *
+ * Example input:
+ *
+ * \ Dump the `foo' structure, creating a size #define called FOO_SIZE, and a
+ * \ shift #define called FOO_SHIFT. `foo' has one member called `mem'.
+ * foo FOO_SIZE FOO_SHIFT
+ *
+ * \ Dump the `a' and `b' members of the `bar' structure. the offset
+ * \ #defines for these members should be `FRED' and `BOB', respectively.
+ * \ Both members are of type `char'
+ * bar
+ * a FRED
+ * b BOB
+ *
+ * Example output:
+ *
+ * #define FOO_SIZE 0x4
+ * #define FOO_SHIFT 0x2
+ * #define FRED 0x0
+ * #define FRED_INCR 0x1
+ * #define BOB 0x4
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+
+#include "ctf_headers.h"
+#include "utils.h"
+#include "ctfstabs.h"
+
+static int
+ga_parse_tokens(char *line, int max, char ***wret)
+{
+ char *c = line;
+ char *word;
+ int n;
+
+ while (isspace(*c))
+ c++;
+
+ for (n = 1, word = strtok(line, " \t"); word != NULL;
+ word = strtok(NULL, " \t"), n++) {
+ if (n > max)
+ return (-1);
+
+ *(wret[n - 1]) = word;
+ }
+
+ return (n - 1);
+}
+
+static int
+ga_parse_common(char *line, int min, int max, char **w1, char **w2, char **w3)
+{
+ char **wret[3];
+ int nread;
+
+ wret[0] = w1;
+ wret[1] = w2;
+ wret[2] = w3;
+
+ if ((nread = ga_parse_tokens(line, max, wret)) < min)
+ return (-1);
+
+ if (nread < 3 && wret[2] != NULL)
+ *wret[2] = (char *)NULL;
+ if (nread < 2 && wret[1] != NULL)
+ *wret[1] = (char *)NULL;
+ if (nread < 1 && wret[0] != NULL)
+ *wret[0] = (char *)NULL;
+
+ return (nread);
+}
+
+/*
+ * Valid format: typename [sizedefname [shiftdefname]]
+ */
+static int
+ga_parse_name(char *line, char **cnp, char **szdp, char **shdp)
+{
+ return (ga_parse_common(line, 1, 3, cnp, szdp, shdp));
+}
+
+/*
+ * Valid format: memname [offdefname]
+ */
+static int
+ga_parse_member(char *line, char **mnp, char **offp)
+{
+ return (ga_parse_common(line, 1, 2, mnp, offp, NULL));
+}
+
+/*
+ * Used to begin a new structure/union block, and to print the optional size
+ * and optional shift constants.
+ */
+static int
+ga_process_name(char *line)
+{
+ char *curname, *sizedef, *shdef;
+ ctf_id_t curtype;
+ ssize_t sz, shift;
+
+ if (ga_parse_name(line, &curname, &sizedef, &shdef) < 0)
+ return (parse_warn("Couldn't parse name"));
+
+ if ((curtype = find_type(curname)) == CTF_ERR)
+ return (parse_warn("Couldn't find type %s", curname));
+
+ if (sizedef != NULL) {
+ if ((sz = ctf_type_size(ctf, curtype)) < 0) {
+ return (parse_warn("Couldn't get size for type %s",
+ curname));
+ } else if (sz == 0) {
+ return (parse_warn("Invalid type size 0 for %s",
+ curname));
+ }
+
+ (void) fprintf(out, "#define\t%s\t0x%x\n", sizedef, sz);
+ }
+
+ if (shdef != NULL) {
+ ssize_t tsz;
+
+ for (shift = -1, tsz = sz; tsz > 0; tsz >>= 1, shift++);
+ if (shift < 0 || 1 << shift != sz) {
+ return (parse_warn("Can't make shift #define: %s size "
+ "(%d) isn't a power of 2", curname, sz));
+ }
+
+ (void) fprintf(out, "#define\t%s\t0x%x\n", shdef, shift);
+ }
+
+ return (curtype);
+}
+
+/*
+ * ga_process_member() and ga_member_cb() are used to print the offset and
+ * possibly array increment values for a given structure member. A specific
+ * member is requested via ga_process_member(), and ga_member_cb() is used
+ * to iterate through the members of the current structure type, looking for
+ * that member. This is not the most efficient way to do things, but the
+ * lists involved are generally short.
+ */
+typedef struct ga_member_cb_data {
+ char *gmcb_memname;
+ char *gmcb_submem;
+ char *gmcb_offdef;
+ size_t gmcb_off;
+} ga_member_cb_data_t;
+
+static int ga_member_find(ctf_id_t, ga_member_cb_data_t *);
+
+static int
+ga_member_cb(const char *name, ctf_id_t type, ulong_t off, void *arg)
+{
+ ga_member_cb_data_t *md = arg;
+ ctf_arinfo_t arinfo;
+ char *label;
+
+ if (strcmp(name, md->gmcb_memname) != 0)
+ return (0);
+
+ md->gmcb_off += off / 8; /* off is in bits */
+
+ if (md->gmcb_submem != NULL) {
+ /*
+ * The user requested foo.bar. We've found foo, and now need to
+ * recurse down to bar.
+ */
+ ga_member_cb_data_t smd;
+
+ smd.gmcb_memname = md->gmcb_submem;
+ smd.gmcb_submem = NULL;
+ smd.gmcb_offdef = md->gmcb_offdef;
+ smd.gmcb_off = md->gmcb_off;
+
+ return (ga_member_find(type, &smd));
+ }
+
+ if (md->gmcb_offdef == NULL) {
+ int i;
+
+ label = md->gmcb_memname;
+ for (i = 0; i < strlen(label); i++)
+ label[i] = toupper(label[i]);
+ } else
+ label = md->gmcb_offdef;
+
+ /* offsets are in bits - we need bytes */
+ (void) fprintf(out, "#define\t%s\t0x%lx\n", label,
+ (ulong_t)md->gmcb_off);
+
+ if ((type = ctf_type_resolve(ctf, type)) == CTF_ERR)
+ return (parse_warn("Couldn't resolve type %s", name));
+
+ if (ctf_array_info(ctf, type, &arinfo) == 0) {
+ ssize_t sz;
+
+ if ((sz = ctf_type_size(ctf, arinfo.ctr_contents)) < 0)
+ return (parse_warn("Couldn't get array elem size"));
+
+ (void) fprintf(out, "#define\t%s_INCR\t0x%x\n", label, sz);
+ }
+
+ return (1);
+}
+
+static int
+ga_member_find(ctf_id_t curtype, ga_member_cb_data_t *md)
+{
+ char *c;
+ int rc;
+
+ if ((c = strchr(md->gmcb_memname, '.')) != NULL)
+ *c++ = NULL;
+ md->gmcb_submem = c;
+
+ if ((rc = ctf_member_iter(ctf, curtype, ga_member_cb, md)) == 0) {
+ return (parse_warn("Couldn't find member named %s",
+ md->gmcb_memname));
+ } else if (rc != 1)
+ return (parse_warn("Can't parse"));
+
+ return (1);
+}
+
+static int
+ga_process_member(ctf_id_t curtype, char *line)
+{
+ ga_member_cb_data_t md = { 0 };
+
+ if (ga_parse_member(line, &md.gmcb_memname, &md.gmcb_offdef) < 0)
+ return (parse_warn("Couldn't parse member"));
+
+ return (ga_member_find(curtype, &md));
+}
+
+static int
+ga_process_line(char *line)
+{
+ static int curtype = -1;
+ int nblank = 0;
+
+ if (strlen(line) == 0) {
+ curtype = -1;
+ if (nblank++ == 1)
+ (void) fprintf(out, "\n");
+ return (1);
+ } else
+ nblank = 0;
+
+ if (line[0] == '\\') {
+ if (line[1] == '#') {
+ /* dump, verbatim, lines that begin with "\#" */
+ (void) fprintf(out, "%s\n", line + 1);
+ }
+ return (1);
+ } else if (line[0] == '#') {
+ return (1);
+ }
+
+ if (curtype == -1)
+ return ((curtype = ga_process_name(line)));
+ else
+ return (ga_process_member(curtype, line));
+}
+
+proc_ops_t ga_ops = {
+ NULL,
+ ga_process_line,
+ NULL
+};