diff options
author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
---|---|---|
committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/tools/ctf/stabs/common | |
download | illumos-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.c | 304 | ||||
-rw-r--r-- | usr/src/tools/ctf/stabs/common/ctfstabs.h | 78 | ||||
-rw-r--r-- | usr/src/tools/ctf/stabs/common/forth.c | 388 | ||||
-rw-r--r-- | usr/src/tools/ctf/stabs/common/forth.h | 73 | ||||
-rw-r--r-- | usr/src/tools/ctf/stabs/common/fth_enum.c | 89 | ||||
-rw-r--r-- | usr/src/tools/ctf/stabs/common/fth_struct.c | 485 | ||||
-rw-r--r-- | usr/src/tools/ctf/stabs/common/genassym.c | 334 |
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 +}; |