MIG codegen: header (.h)

bootstrap_cmds/migcom.tproj/header.c · 597 lines · browse source

Emits the generated header for a subsystem — the __Request__/__Reply__ message structs and the routine prototypes seen in the SDK. This is where the on-the-wire message layout of each stub comes from.

WriteIncludes source
void
WriteIncludes(FILE *file, boolean_t isuser, boolean_t isdef)
{
  if (EmitCountAnnotations) {
  	fprintf(file, "#include <sys/cdefs.h>\n");
  }
  if (isdef) {
    fprintf(file, "#include <mach/port.h>\n");
    fprintf(file, "#include <mach/machine/kern_return.h>\n");
    if (!isuser)
      fprintf(file, "#include <mach/mig_errors.h>\n");
  }
  else {
    fprintf(file, "#include <string.h>\n");
    fprintf(file, "#include <mach/ndr.h>\n");
    fprintf(file, "#include <mach/boolean.h>\n");
    fprintf(file, "#include <mach/kern_return.h>\n");
    fprintf(file, "#include <mach/notify.h>\n");
    fprintf(file, "#include <mach/mach_types.h>\n");
    fprintf(file, "#include <mach/message.h>\n");
    fprintf(file, "#include <mach/mig_errors.h>\n");
    fprintf(file, "#include <mach/port.h>\n");

    if (IsVoucherCodeAllowed && !IsKernelUser && !IsKernelServer) {
      fprintf(file, "\t\n/* BEGIN VOUCHER CODE */\n\n");
      fprintf(file, "#ifndef KERNEL\n");
      fprintf(file, "#if defined(__has_include)\n");
      fprintf(file, "#if __has_include(<mach/mig_voucher_support.h>)\n");
      fprintf(file, "#ifndef USING_VOUCHERS\n");
      fprintf(file, "#define USING_VOUCHERS\n");
… more in source
WriteETAPDefines source
static void
WriteETAPDefines(FILE *file)
{
  statement_t *stat;
  int fnum;
  char *fname;
  int first = TRUE;

  fprintf(file, "\n#ifndef subsystem_to_name_map_%s\n", SubsystemName);
  fprintf(file, "#define subsystem_to_name_map_%s \\\n", SubsystemName);
  for (stat = stats; stat != stNULL; stat = stat->stNext)
    if (stat->stKind == skRoutine) {
      fnum = SubsystemBase + stat->stRoutine->rtNumber;
      fname = stat->stRoutine->rtName;
      if (! first)
        fprintf(file, ",\\\n");
      fprintf(file, "    { \"%s\", %d }", fname, fnum);
      first = FALSE;
    }
  fprintf(file, "\n#endif\n");
}
WriteProlog source
static void
WriteProlog(FILE *file, char *protect, boolean_t more, boolean_t isuser)
{
  if (protect != strNULL) {
    fprintf(file, "#ifndef\t_%s\n", protect);
    fprintf(file, "#define\t_%s\n", protect);
    fprintf(file, "\n");
  }

  fprintf(file, "/* Module %s */\n", SubsystemName);
  fprintf(file, "\n");

  if (more) {
    WriteIncludes(file, isuser, UseSplitHeaders);
  }
  fprintf(file, "#ifdef AUTOTEST\n");
  fprintf(file, "#ifndef FUNCTION_PTR_T\n");
  fprintf(file, "#define FUNCTION_PTR_T\n");
  fprintf(file, "typedef void (*function_ptr_t)");
  fprintf(file, "(mach_port_t, char *%s, mach_msg_type_number_t);\n", EmitCountAnnotations ? "__unsafe_indexable" : "");
  fprintf(file, "typedef struct {\n");
  fprintf(file, "        char            *%s name;\n", EmitCountAnnotations ? "__unsafe_indexable" : "");
  fprintf(file, "        function_ptr_t  function;\n");
  fprintf(file, "} function_table_entry;\n");
  fprintf(file, "typedef function_table_entry   *function_table_t;\n");
  fprintf(file, "#endif /* FUNCTION_PTR_T */\n");
  fprintf(file, "#endif /* AUTOTEST */\n");
  fprintf(file, "\n#ifndef\t%s_MSG_COUNT\n", SubsystemName);
  fprintf(file, "#define\t%s_MSG_COUNT\t%d\n", SubsystemName, rtNumber);
  fprintf(file, "#endif\t/* %s_MSG_COUNT */\n\n", SubsystemName);
… more in source
WriteEpilog source
static void
WriteEpilog(FILE *file, char *protect, boolean_t isuser)
{
  char *defname = isuser ? "__AfterMigUserHeader" : "__AfterMigServerHeader";

  WriteETAPDefines(file);
  fprintf(file, "\n#ifdef %s\n%s\n#endif /* %s */\n", defname, defname, defname);
  if (protect != strNULL) {
    fprintf(file, "\n");
    fprintf(file, "#endif\t /* _%s */\n", protect);
  }
}
WriteUserRoutine source
static void
WriteUserRoutine(FILE *file, routine_t *rt)
{
  fprintf(file, "\n");
  fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName);
  WriteMigExternal(file);
  fprintf(file, "%s %s\n", ReturnTypeStr(rt), rt->rtUserName);
  if (BeLint) {
    fprintf(file, "#if\t%s\n", LintLib);
    fprintf(file, "    (");
    WriteList(file, rt->rtArgs, WriteNameDecl, akbUserArg, ", " , "");
    fprintf(file, ")\n");
    WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ";\n", ";\n");
    fprintf(file, "{ ");
    fprintf(file, "return ");
    fprintf(file, "%s(", rt->rtUserName);
    WriteList(file, rt->rtArgs, WriteNameDecl, akbUserArg, ", ", "");
    fprintf(file, "); }\n");
    fprintf(file, "#else\n");
  }
  if (BeAnsiC) {
    fprintf(file, "(\n");
    WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n");
    fprintf(file, ");\n");
  }
  else {
    fprintf(file, "#if\t%s\n", NewCDecl);
    fprintf(file, "(\n");
    WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n");
    fprintf(file, ");\n");
… more in source
WriteUserRequestUnion source
void
WriteUserRequestUnion(FILE *file, statement_t *stats)
{
  statement_t *stat;

  fprintf(file, "/* union of all requests */\n\n");
  fprintf(file, "#ifndef __RequestUnion__%s%s_subsystem__defined\n", UserPrefix, SubsystemName);
  fprintf(file, "#define __RequestUnion__%s%s_subsystem__defined\n", UserPrefix, SubsystemName);
  fprintf(file, "union __RequestUnion__%s%s_subsystem {\n", UserPrefix, SubsystemName);
  for (stat = stats; stat != stNULL; stat = stat->stNext) {
    if (stat->stKind == skRoutine) {
      routine_t *rt;

      rt = stat->stRoutine;
      fprintf(file, "\t__Request__%s_t Request_%s;\n", rt->rtName, rt->rtUserName);
    }
  }
  fprintf(file, "};\n");
  fprintf(file, "#endif /* !__RequestUnion__%s%s_subsystem__defined */\n", UserPrefix, SubsystemName);
}
WriteUserReplyUnion source
void
WriteUserReplyUnion(FILE *file, statement_t *stats)
{
  statement_t *stat;

  fprintf(file, "/* union of all replies */\n\n");
  fprintf(file, "#ifndef __ReplyUnion__%s%s_subsystem__defined\n", UserPrefix, SubsystemName);
  fprintf(file, "#define __ReplyUnion__%s%s_subsystem__defined\n", UserPrefix, SubsystemName);
  fprintf(file, "union __ReplyUnion__%s%s_subsystem {\n", UserPrefix, SubsystemName);
  for (stat = stats; stat != stNULL; stat = stat->stNext) {
    if (stat->stKind == skRoutine) {
      routine_t *rt;

      rt = stat->stRoutine;
      fprintf(file, "\t__Reply__%s_t Reply_%s;\n", rt->rtName, rt->rtUserName);
    }
  }
  fprintf(file, "};\n");
  fprintf(file, "#endif /* !__RequestUnion__%s%s_subsystem__defined */\n", UserPrefix, SubsystemName);
}
WriteUserHeader source
void
WriteUserHeader(FILE *file, statement_t *stats)
{
  statement_t *stat;
  char *protect = strconcat(SubsystemName, "_user_");

  WriteProlog(file, protect, TRUE, TRUE);
  for (stat = stats; stat != stNULL; stat = stat->stNext)
    switch (stat->stKind) {

      case skImport:
      case skUImport:
      case skDImport:
        WriteImport(file, stat->stFileName);
        break;

      case skRoutine:
      case skSImport:
      case skIImport:
        break;

      default:
        fatal("WriteHeader(): bad statement_kind_t (%d)", (int) stat->stKind);
  }
  fprintf(file, "\n");
  fprintf(file, "#ifdef __BeforeMigUserHeader\n");
  fprintf(file, "__BeforeMigUserHeader\n");
  fprintf(file, "#endif /* __BeforeMigUserHeader */\n");
  fprintf(file, "\n");
  fprintf(file, "#include <sys/cdefs.h>\n");
… more in source
WriteDefinesRoutine source
static void
WriteDefinesRoutine(FILE *file, routine_t *rt)
{
  char *up = (char *)malloc(strlen(rt->rtName)+1);

  up = toupperstr(strcpy(up, rt->rtName));
  fprintf(file, "#define\tMACH_ID_%s\t\t%d\t/* %s() */\n", up, rt->rtNumber + SubsystemBase, rt->rtName);
  if (rt->rtKind == rkRoutine)
    fprintf(file, "#define\tMACH_ID_%s_REPLY\t\t%d\t/* %s() */\n", up, rt->rtNumber + SubsystemBase + 100, rt->rtName);
  fprintf(file, "\n");
}
WriteServerRoutine source
void
WriteServerRoutine(FILE *file, routine_t *rt)
{
  fprintf(file, "\n");
  fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName);
  WriteMigExternal(file);

  // MIG_SERVER_ROUTINE can be defined by system headers to resolve to an attribute that
  // tells the compiler that this is a MIG server routine. Useful for static analysis.
  fprintf(file, "MIG_SERVER_ROUTINE\n%s %s\n", ReturnTypeStr(rt), rt->rtServerName);

  if (BeLint) {
    fprintf(file, "#if\t%s\n", LintLib);
    fprintf(file, "    (");
    WriteList(file, rt->rtArgs, WriteNameDecl, akbServerArg, ", " , "");
    fprintf(file, ")\n");
    WriteList(file, rt->rtArgs, WriteServerVarDecl, akbServerArg, ";\n", ";\n");
    fprintf(file, "{ ");
    fprintf(file, "return ");
    fprintf(file, "%s(", rt->rtServerName);
    WriteList(file, rt->rtArgs, WriteNameDecl, akbServerArg, ", ", "");
    fprintf(file, "); }\n");
    fprintf(file, "#else /* %s */\n",LintLib);
  }
  if (BeAnsiC) {
    fprintf(file, "(\n");
    WriteList(file, rt->rtArgs, WriteServerVarDecl, akbServerArg, ",\n", "\n");
    fprintf(file, ");\n");
  }
  else {
… more in source
WriteDispatcher source
static void
WriteDispatcher(FILE *file)
{
  statement_t *stat;
  int descr_count = 0;
  char *kern_ = "";
  char *k = "";
  char *kernel = "";

  if (UseMachMsg2) {
    kern_ = "kern_";
    k = "k";
    kernel = "kernel ";
  }

  for (stat = stats; stat != stNULL; stat = stat->stNext)
    if (stat->stKind == skRoutine) {
      routine_t *rt = stat->stRoutine;
      descr_count += rtCountArgDescriptors(rt->rtArgs, (int *) 0);
    }
  fprintf(file, "\n");

  WriteMigExternal(file);
  fprintf(file, "boolean_t %s(", ServerDemux);
  fprintf(file, "\n\t\tmach_msg_header_t *InHeadP,");
  if (!UseMachMsg2) {
    fprintf(file, "\n\t\tmach_msg_header_t *OutHeadP");
  } else {
    fprintf(file, "\n\t\tvoid *InDataP,");
    fprintf(file, "\n\t\tmach_msg_max_trailer_t *InTrailerP,");
… more in source
WriteBogusServerRoutineAnnotationDefine source
void
WriteBogusServerRoutineAnnotationDefine(FILE *file) {
  // MIG_SERVER_ROUTINE can be defined by system headers to resolve to
  // an attribute that tells the compiler that this is a MIG server routine.
  // Useful for static analysis.
  fprintf(file, "#ifndef MIG_SERVER_ROUTINE\n");
  fprintf(file, "#define MIG_SERVER_ROUTINE\n");
  fprintf(file, "#endif\n");
  fprintf(file, "\n");
}
WriteServerHeader source
void
WriteServerHeader(FILE *file, statement_t *stats)
{
  statement_t *stat;
  char *protect = strconcat(SubsystemName, "_server_");

  WriteProlog(file, protect, TRUE, FALSE);
  for (stat = stats; stat != stNULL; stat = stat->stNext)
    switch (stat->stKind) {

      case skImport:
      case skSImport:
      case skDImport:
        WriteImport(file, stat->stFileName);
        break;

      case skRoutine:
      case skUImport:
      case skIImport:
        break;

      default:
        fatal("WriteServerHeader(): bad statement_kind_t (%d)", (int) stat->stKind);
  }
  fprintf(file, "\n#ifdef __BeforeMigServerHeader\n");
  fprintf(file, "__BeforeMigServerHeader\n");
  fprintf(file, "#endif /* __BeforeMigServerHeader */\n\n");

  WriteBogusServerRoutineAnnotationDefine(file);
… more in source
WriteInternalRedefine source
static void
WriteInternalRedefine(FILE *file, routine_t *rt)
{
  fprintf(file, "#define %s %s_external\n", rt->rtUserName, rt->rtUserName);
}
WriteInternalHeader source
void
WriteInternalHeader(FILE *file, statement_t *stats)
{
  statement_t *stat;

  for (stat = stats; stat != stNULL; stat = stat->stNext)
    switch (stat->stKind) {

      case skRoutine:
        WriteInternalRedefine(file, stat->stRoutine);
        break;

      case skImport:
      case skUImport:
      case skSImport:
      case skDImport:
      case skIImport:
        break;

      default:
        fatal("WriteInternalHeader(): bad statement_kind_t (%d)", (int) stat->stKind);
  }
}
WriteDefinesHeader source
void
WriteDefinesHeader(FILE *file, statement_t *stats)
{
  statement_t *stat;
  char *protect = strconcat(SubsystemName, "_defines");

  WriteProlog(file, protect, FALSE, FALSE);
  fprintf(file, "\n/*\tDefines related to the Subsystem %s\t*/\n\n", SubsystemName);
  for (stat = stats; stat != stNULL; stat = stat->stNext)
    switch (stat->stKind) {

      case skRoutine:
        WriteDefinesRoutine(file, stat->stRoutine);
        break;

      case skImport:
      case skSImport:
      case skUImport:
        break;

      default:
        fatal("WriteDefinesHeader(): bad statement_kind_t (%d)", (int) stat->stKind);
  }
  WriteEpilog(file, protect, FALSE);
}