ndr_gen.c revision a0b6e447978c306e15941d158bf6939a42ed2726
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <string.h>
#include "ndrgen.h"
#include "y.tab.h"
static void generate_struct(ndr_typeinfo_t *);
static void generate_params(ndr_typeinfo_t *);
static void generate_union(ndr_typeinfo_t *);
static void generate_arg(ndr_node_t *);
static void generate_member_macro(char *, char *, ndr_member_t *,
ndr_typeinfo_t *);
static void generate_member_macro_with_arg(char *, char *, ndr_member_t *,
ndr_typeinfo_t *, ndr_node_t *);
static void generate_prototypes(ndr_typeinfo_t *, char *);
static void generate_member_prototypes(ndr_typeinfo_t *, ndr_member_t *,
char *);
static void generate_member(ndr_typeinfo_t *, ndr_member_t *);
static void generate_aggregate_common_begin(ndr_typeinfo_t *);
static void generate_aggregate_common_finish(ndr_typeinfo_t *);
static void generate_typeinfo_packing(ndr_typeinfo_t *);
static void generate_typeinfo_typeinfo(ndr_typeinfo_t *, int, char *);
void
generate(void)
{
ndr_typeinfo_t *ti;
char fname_type[NDLBUFSZ];
(void) printf("\n");
for (ti = typeinfo_list; ti; ti = ti->next) {
if (ti->is_extern || ti->advice.a_extern) {
type_extern_suffix(ti, fname_type, NDLBUFSZ);
(void) printf(
"extern struct ndr_typeinfo ndt_%s;\n",
fname_type);
continue;
}
switch (ti->type_op) {
case STRUCT_KW:
if (ti->advice.a_operation)
generate_params(ti);
else
generate_struct(ti);
break;
case UNION_KW:
generate_union(ti);
break;
case TYPEDEF_KW:
/* silently skip */
continue;
case STRING_KW:
case STAR:
case LB:
case BASIC_TYPE:
if (!ti->is_referenced) {
type_extern_suffix(ti, fname_type, NDLBUFSZ);
(void) printf("extern ndt_%s\n", fname_type);
type_null_decl(ti, fname_type, NDLBUFSZ);
(void) printf("/* %s */\n", fname_type);
}
break;
default:
continue;
}
}
}
static void
generate_struct(ndr_typeinfo_t *ti)
{
int i;
ndr_member_t *mem;
if (ti->advice.a_no_reorder) {
/* just use generate_params(), which can safely do this */
generate_params(ti);
return;
}
generate_aggregate_common_begin(ti);
(void) printf(" /* do all basic elements first */\n");
for (i = 0; i < ti->n_member; i++) {
mem = &ti->member[i];
if (mem->type->type_op != BASIC_TYPE)
continue;
generate_member(ti, mem);
}
(void) printf("\n");
(void) printf(" /* do all constructed elements w/o pointers */\n");
for (i = 0; i < ti->n_member; i++) {
mem = &ti->member[i];
if (mem->type->type_op == BASIC_TYPE)
continue;
if (mem->type->has_pointers)
continue;
generate_member(ti, mem);
}
(void) printf("\n");
(void) printf(" /* do members with pointers in order */\n");
for (i = 0; i < ti->n_member; i++) {
mem = &ti->member[i];
if (mem->type->type_op == BASIC_TYPE)
continue;
if (!mem->type->has_pointers)
continue;
generate_member(ti, mem);
}
generate_aggregate_common_finish(ti);
}
static void
generate_params(ndr_typeinfo_t *ti)
{
int i;
ndr_member_t *mem;
generate_aggregate_common_begin(ti);
(void) printf(" /* do all members in order */\n");
for (i = 0; i < ti->n_member; i++) {
mem = &ti->member[i];
generate_member(ti, mem);
}
generate_aggregate_common_finish(ti);
}
static void
generate_union(ndr_typeinfo_t *ti)
{
int i;
ndr_member_t *mem;
int have_default = 0;
ndr_node_t *np;
generate_aggregate_common_begin(ti);
(void) printf(" switch (encl_ref->switch_is) {\n");
for (i = 0; i < ti->n_member; i++) {
mem = &ti->member[i];
if ((np = mem->advice.a_case) != 0) {
(void) printf(" case ");
print_node(np->n_a_arg);
(void) printf(":\n");
} else if ((np = mem->advice.a_default) != 0) {
(void) printf(" default:\n");
if (have_default++) {
compile_error("multiple defaults");
}
} else {
compile_error("syntax error");
}
generate_member(ti, mem);
(void) printf(" break;\n\n");
}
if (!have_default) {
(void) printf(" default:\n");
(void) printf(" NDR_SET_ERROR(encl_ref, "
"NDR_ERR_SWITCH_VALUE_INVALID);\n");
(void) printf(" return 0;\n");
(void) printf(" break;\n");
}
(void) printf(" }\n");
(void) printf("\n");
generate_aggregate_common_finish(ti);
}
static void
generate_arg(ndr_node_t *np)
{
ndr_node_t *arg = np;
if (np == NULL) {
compile_error("invalid node pointer <null>");
return;
}
if (np->label != IDENTIFIER && np->label != INTEGER)
arg = np->n_a_arg;
switch (np->label) {
case SIZE_IS_KW:
case LENGTH_IS_KW:
case SWITCH_IS_KW:
(void) printf("val->");
print_field_attr(np);
break;
default:
if (arg->label == IDENTIFIER)
(void) printf("val->%s", arg->n_sym->name);
else
print_node(arg);
break;
}
}
static void
generate_member_macro(char *memkind, char *macro, ndr_member_t *mem,
ndr_typeinfo_t *ti)
{
char fname_type[NDLBUFSZ];
if (!macro)
macro = "";
if (!ti)
ti = mem->type;
type_extern_suffix(ti, fname_type, NDLBUFSZ);
if (memkind) {
(void) printf(" NDR_%sMEMBER%s (%s, %s);\n",
memkind, macro, fname_type, mem->name);
} else {
(void) printf(" NDR_MEMBER%s (%s, %s, %uUL);\n",
macro, fname_type, mem->name, mem->pdu_offset);
}
}
static void
generate_member_macro_with_arg(char *memkind, char *macro,
ndr_member_t *mem, ndr_typeinfo_t *ti, ndr_node_t *np)
{
char fname_type[NDLBUFSZ];
if (!macro)
macro = "_WITH_ARG";
if (!ti)
ti = mem->type;
type_extern_suffix(ti, fname_type, NDLBUFSZ);
if (memkind) {
(void) printf(" NDR_%sMEMBER%s (%s, %s,\n",
memkind, macro, fname_type, mem->name);
} else {
(void) printf(" NDR_MEMBER%s (%s, %s, %uUL,\n",
macro, fname_type, mem->name, mem->pdu_offset);
}
(void) printf("\t\t");
generate_arg(np);
(void) printf(");\n");
}
static void
generate_prototypes(ndr_typeinfo_t *ti, char *fname_type)
{
ndr_member_t *mem;
int i;
if (ti->type_op == STRUCT_KW && ti->advice.a_operation) {
for (i = 0; i < ti->n_member; i++) {
mem = &ti->member[i];
generate_member_prototypes(ti, mem, fname_type);
}
}
}
static void
generate_member_prototypes(ndr_typeinfo_t *ti,
ndr_member_t *mem, char *fname_type)
{
char val_buf[NDLBUFSZ];
ndr_typeinfo_t ptr;
if (mem->type->type_op == UNION_KW) {
if (!mem->advice.a_in && mem->advice.a_out) {
ptr.type_op = STAR;
ptr.type_down = ti;
type_name_decl(&ptr, val_buf, NDLBUFSZ, "val");
(void) printf("\nextern void fixup%s(%s);\n",
fname_type, val_buf);
}
}
}
static void
generate_member(ndr_typeinfo_t *ti, ndr_member_t *mem)
{
static char *fixup[] = {
"/*",
" * Cannot use the canned offsets to unmarshall multiple",
" * entry discriminated unions. The service must provide",
" * this function to patch the offsets at runtime.",
" */"
};
char fname_type[NDLBUFSZ];
ndr_node_t *np;
int is_reference = 0;
char *memkind = 0;
int cond_pending = 0;
int i;
if (ti->advice.a_operation)
memkind = "TOPMOST_";
else if (ti->advice.a_interface)
memkind = "PARAMS_";
if (mem->advice.a_in && !mem->advice.a_out) {
cond_pending = 1;
(void) printf(" if (NDR_DIR_IS_IN) {\n");
}
if (!mem->advice.a_in && mem->advice.a_out) {
cond_pending = 1;
(void) printf(" if (NDR_DIR_IS_OUT) {\n");
}
type_extern_suffix(ti, fname_type, NDLBUFSZ);
switch (mem->type->type_op) {
case BASIC_TYPE:
case STRUCT_KW:
generate_member_macro(memkind, 0, mem, 0);
break;
case UNION_KW:
np = mem->advice.a_switch_is;
if (!mem->advice.a_in && mem->advice.a_out) {
for (i = 0; i < sizeof (fixup)/sizeof (fixup[0]); ++i)
(void) printf("\t%s\n", fixup[i]);
(void) printf("\tfixup%s(val);\n", fname_type);
}
generate_member_macro_with_arg(memkind,
"_WITH_SWITCH_IS", mem, 0, np);
break;
case STAR:
if (mem->advice.a_reference)
is_reference = 1;
else
is_reference = 0;
np = mem->advice.a_size_is;
if (np) {
generate_member_macro_with_arg(memkind,
is_reference ?
"_REF_WITH_SIZE_IS" : "_PTR_WITH_SIZE_IS",
mem, mem->type->type_down, np);
break;
}
np = mem->advice.a_length_is;
if (np) {
generate_member_macro_with_arg(memkind,
is_reference ?
"_REF_WITH_LENGTH_IS" : "_PTR_WITH_LENGTH_IS",
mem, mem->type->type_down, np);
break;
}
generate_member_macro(memkind,
is_reference ? "_REF" : "_PTR",
mem, mem->type->type_down);
break;
case LB:
np = mem->advice.a_size_is;
if (np) {
generate_member_macro_with_arg(memkind,
"_ARR_WITH_SIZE_IS",
mem, mem->type->type_down, np);
break;
}
np = mem->advice.a_length_is;
if (np) {
generate_member_macro_with_arg(memkind,
"_WITH_LENGTH_IS",
mem, mem->type->type_down, np);
break;
}
generate_member_macro_with_arg(memkind,
"_ARR_WITH_DIMENSION",
mem, mem->type->type_down, mem->type->type_dim);
break;
default:
generate_member_macro(memkind, "_???", mem, 0);
break;
}
if (cond_pending)
(void) printf(" }\n");
}
static void
generate_aggregate_common_begin(ndr_typeinfo_t *ti)
{
char val_buf[NDLBUFSZ];
char cast_buf[NDLBUFSZ];
char fname_type[NDLBUFSZ];
ndr_typeinfo_t ptr;
type_extern_suffix(ti, fname_type, NDLBUFSZ);
generate_typeinfo_typeinfo(ti, 0, fname_type);
generate_prototypes(ti, fname_type);
(void) printf("\n");
(void) printf("/*\n * ");
show_advice(&ti->advice, 0);
(void) printf(" */\n");
(void) printf("int\n");
(void) printf("ndr_%s (struct ndr_reference *encl_ref)\n",
fname_type);
(void) printf("{\n");
ptr.type_op = STAR;
ptr.type_down = ti;
type_name_decl(&ptr, val_buf, NDLBUFSZ, "val");
type_null_decl(&ptr, cast_buf, NDLBUFSZ);
(void) printf(" %s = %s encl_ref->datum;\n", val_buf, cast_buf);
(void) printf(" struct ndr_reference myref;\n");
(void) printf("\n");
(void) printf(" (void) bzero(&myref, sizeof (myref));\n");
(void) printf(" myref.enclosing = encl_ref;\n");
(void) printf(" myref.stream = encl_ref->stream;\n");
generate_typeinfo_packing(ti);
(void) printf("\n");
}
/* ARGSUSED */
static void
generate_aggregate_common_finish(ndr_typeinfo_t *ti)
{
(void) printf("\n");
(void) printf(" return 1;\n");
(void) printf("}\n");
}
/*
* Structures are normally 4-byte (dword) aligned but the align directive
* can be used to pack on a 2-byte (word) boundary. An align value of
* zero is taken to mean use default (dword) alignment. Default packing
* doesn't need to be flagged.
*/
static void
generate_typeinfo_packing(ndr_typeinfo_t *ti)
{
ndr_node_t *np;
unsigned long packing;
if ((np = ti->advice.a_align) == NULL)
return;
if ((np = np->n_a_arg) == NULL)
return;
packing = np->n_int;
if ((packing == 0) || (packing == 4)) {
/* default alignment */
return;
}
if (packing != 2) {
fatal_error("invalid align directive: %lu", packing);
/* NOTREACHED */
}
(void) printf(" myref.packed_alignment = %lu;\n", packing);
}
static void
generate_typeinfo_typeinfo(ndr_typeinfo_t *ti, int is_static, char *fname_type)
{
char flags[NDLBUFSZ];
*flags = 0;
if (ti->is_conformant)
(void) strlcat(flags, "|NDR_F_CONFORMANT", NDLBUFSZ);
if (ti->type_op == STRUCT_KW) {
if (ti->advice.a_operation)
(void) strlcat(flags, "|NDR_F_OPERATION", NDLBUFSZ);
else
(void) strlcat(flags, "|NDR_F_STRUCT", NDLBUFSZ);
}
if (ti->type_op == UNION_KW) {
if (ti->advice.a_interface)
(void) strlcat(flags, "|NDR_F_INTERFACE", NDLBUFSZ);
else
(void) strlcat(flags, "|NDR_F_UNION", NDLBUFSZ);
}
if (ti->type_op == STRING_KW)
(void) strlcat(flags, "|NDR_F_STRING", NDLBUFSZ);
if (ti->type_op == LB)
(void) strlcat(flags, "|NDR_F_ARRAY", NDLBUFSZ);
if (ti->type_op == STAR)
(void) strlcat(flags, "|NDR_F_POINTER", NDLBUFSZ);
if (*flags == 0)
(void) strlcpy(flags, "NDR_F_NONE", NDLBUFSZ);
else
(void) strlcpy(flags, flags+1, NDLBUFSZ);
(void) printf("\n\n\n");
if (is_static)
(void) printf("static ");
(void) printf("int ndr_%s (struct ndr_reference *encl_ref);\n",
fname_type);
if (is_static)
(void) printf("static ");
(void) printf("struct ndr_typeinfo ndt_%s = {\n", fname_type);
(void) printf("\t1, /* NDR version */\n");
(void) printf("\t%d, /* alignment */\n", ti->alignment);
(void) printf("\t%s, /* flags */\n", flags);
(void) printf("\tndr_%s, /* ndr_func */\n", fname_type);
(void) printf("\t%d, /* pdu_size_fixed_part */\n",
ti->size_fixed_part);
(void) printf("\t%d, /* pdu_size_variable_part */\n",
ti->size_variable_part);
(void) printf("\t%d, /* c_size_fixed_part */\n",
ti->size_fixed_part);
(void) printf("\t%d, /* c_size_variable_part */\n",
ti->size_variable_part);
(void) printf("};\n\n");
}