gdb/reply_mig_hack.awk - gdb

  1. # Reply server mig-output massager
  2. #
  3. #   Copyright (C) 1995-2015 Free Software Foundation, Inc.
  4. #
  5. #   Written by Miles Bader <miles@gnu.ai.mit.edu>
  6. #
  7. #   This program is free software; you can redistribute it and/or
  8. #   modify it under the terms of the GNU General Public License as
  9. #   published by the Free Software Foundation; either version 3, or (at
  10. #   your option) any later version.
  11. #
  12. #   This program is distributed in the hope that it will be useful, but
  13. #   WITHOUT ANY WARRANTY; without even the implied warranty of
  14. #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15. #   General Public License for more details.
  16. #
  17. #   You should have received a copy of the GNU General Public License
  18. #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19. #
  20. # This awk script hacks the output of mig-generated reply server code
  21. # so that it allows replies with just the error-code in them (as this is
  22. # how mig returns errors).
  23. #
  24. # It is highly, highly, dependent on the exact format of mig output.  Ick.
  25. #

  26. BEGIN { parse_phase = 0; }

  27. /^}/ { parse_phase = 0; }

  28. parse_phase == 0 && /^mig_internal void _X[a-zA-Z0-9_]*_reply/ {
  29.   # The start of a mig server routine.  Reset everything.  Note that we only
  30.   # mess with rpcs that have the suffix `_reply'.
  31.   num_args = 0;
  32.   num_checks = 0;
  33.   parse_phase = 1;
  34.   print; next;
  35. }

  36. parse_phase == 1 && /^[\t ]*typedef struct/ {
  37.   # The first structure in the server routine should describe the arguments
  38.   parse_phase = 2;
  39.   print; next;
  40. }

  41. parse_phase == 2 {
  42.   # The message header field in the args structure, which skip.
  43.   parse_phase = 3;
  44.   print; next;
  45. }

  46. parse_phase == 3 && /}/ {
  47.   # The args structure is over.
  48.   if (num_args > 1)
  49.     parse_phase = 5;
  50.   else
  51.     # There's no extra args that could screw up the normal mechanism for
  52.     # error returns, so we don't have to insert any new code.
  53.     parse_phase = 0;
  54.   print; next;
  55. }

  56. parse_phase == 3 {
  57.   # The type field for an argument.
  58.   arg_type_code_name[num_args] = $2;
  59.   sub (/;$/, "", arg_type_code_name[num_args]) # Get rid of the semi-colon
  60.   parse_phase = 4;
  61.   print; next;
  62. }

  63. parse_phase == 4 {
  64.   # The value field for an argument.
  65.   arg_name[num_args] = $2;
  66.   sub (/;$/, "", arg_name[num_args]) # Get rid of the semi-colon
  67.   arg_type[num_args] = $1;
  68.   num_args++;
  69.   parse_phase = 3;
  70.   print; next;
  71. }

  72. parse_phase == 5 && /^[ \t]*(auto |static |)const mach_msg_type_t/ {
  73.   # The type check structure for an argument.
  74.   arg_check_name[num_checks] = $(NF - 2);
  75.   num_checks++;
  76.   print; next;
  77. }

  78. parse_phase == 5 && /^[ \t]*mig_external kern_return_t/ {
  79.   # The declaration of the user server function for this rpc.
  80.   user_function_name = $3;
  81.   print; next;
  82. }

  83. parse_phase == 5 && /^#if[ \t]TypeCheck/ {
  84.   # Keep going if we have not yet collected the type check structures.
  85.   if (num_checks == 0)
  86.     {
  87.       print; next;
  88.     }

  89.   # The first args type checking statement; we need to insert our chunk of
  90.   # code that bypasses all the type checks if this is an error return, after
  91.   # which we're done until we get to the next function.  Handily, the size
  92.   # of mig's Reply structure is also the size of the alternate Request
  93.   # structure that we want to check for.
  94.   print "\tif (In0P->Head.msgh_size == sizeof (Reply)";
  95.   print "\t    && ! (In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)";
  96.   print "\t    && ! BAD_TYPECHECK(&In0P->" arg_type_code_name[0] ", &" arg_check_name[0] ")";
  97.   print "\t    && In0P->" arg_name[0] " != 0)";
  98.   print "\t  /* Error return, only the error code argument is passed.  */";
  99.   print "\t  {";
  100.   # Force the function into a type that only takes the first two args, via
  101.   # the temp variable SFUN (is there another way to correctly do this cast?).
  102.   # This is possibly bogus, but easier than supplying bogus values for all
  103.   # the other args (we can't just pass 0 for them, as they might not be scalar).
  104.   printf ("\t    kern_return_t (*sfun)(mach_port_t");
  105.   for (i = 0; i < num_args; i++)
  106.     printf (", %s", arg_type[i]);
  107.   printf (") = %s;\n", user_function_name);
  108.   print "\t    OutP->RetCode = (*(kern_return_t (*)(mach_port_t, kern_return_t))sfun) (In0P->Head.msgh_request_port, In0P->" arg_name[0] ");";
  109.   print "\t    return;";
  110.   print "\t  }";
  111.   print "";
  112.   parse_phase = 0;
  113.   print; next;
  114. }

  115. { print; }