summaryrefslogtreecommitdiff
path: root/usr/src/tools/ctf/stabs/common/forth.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/tools/ctf/stabs/common/forth.c')
-rw-r--r--usr/src/tools/ctf/stabs/common/forth.c388
1 files changed, 388 insertions, 0 deletions
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
+};