forth.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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
};