PageRenderTime 48ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/libxl/libxl_save_msgs_gen.pl

https://gitlab.com/wkyu/gxen
Perl | 398 lines | 324 code | 54 blank | 20 comment | 34 complexity | 0893e8945954d6878ecacf6b64ee6097 MD5 | raw file
  1. #!/usr/bin/perl -w
  2. use warnings;
  3. use strict;
  4. use POSIX;
  5. our $debug = 0; # produce copious debugging output at run-time?
  6. our @msgs = (
  7. # flags:
  8. # s - applicable to save
  9. # r - applicable to restore
  10. # c - function pointer in callbacks struct rather than fixed function
  11. # x - function pointer is in struct {save,restore}_callbacks
  12. # and its null-ness needs to be passed through to the helper's xc
  13. # W - needs a return value; callback is synchronous
  14. # A - needs a return value; callback is asynchronous
  15. [ 1, 'sr', "log", [qw(uint32_t level
  16. uint32_t errnoval
  17. STRING context
  18. STRING formatted)] ],
  19. [ 2, 'sr', "progress", [qw(STRING context
  20. STRING doing_what),
  21. 'unsigned long', 'done',
  22. 'unsigned long', 'total'] ],
  23. [ 3, 'scxW', "suspend", [] ],
  24. [ 4, 'scxW', "postcopy", [] ],
  25. [ 5, 'scxA', "checkpoint", [] ],
  26. [ 6, 'scxA', "switch_qemu_logdirty", [qw(int domid
  27. unsigned enable)] ],
  28. # toolstack_save done entirely `by hand'
  29. [ 7, 'rcxW', "toolstack_restore", [qw(uint32_t domid
  30. BLOCK tsdata)] ],
  31. [ 8, 'r', "restore_results", ['unsigned long', 'store_mfn',
  32. 'unsigned long', 'console_mfn',
  33. 'unsigned long', 'genidad'] ],
  34. [ 9, 'srW', "complete", [qw(int retval
  35. int errnoval)] ],
  36. );
  37. #----------------------------------------
  38. our %cbs;
  39. our %func;
  40. our %func_ah;
  41. our @outfuncs;
  42. our %out_decls;
  43. our %out_body;
  44. our %msgnum_used;
  45. die unless @ARGV==1;
  46. die if $ARGV[0] =~ m/^-/;
  47. our ($intendedout) = @ARGV;
  48. $intendedout =~ m/([a-z]+)\.([ch])$/ or die;
  49. my ($want_ah, $ch) = ($1, $2);
  50. my $declprefix = '';
  51. foreach my $ah (qw(callout helper)) {
  52. $out_body{$ah} .=
  53. <<END_BOTH.($ah eq 'callout' ? <<END_CALLOUT : <<END_HELPER);
  54. #include "libxl_osdeps.h"
  55. #include <assert.h>
  56. #include <string.h>
  57. #include <stdint.h>
  58. #include <limits.h>
  59. END_BOTH
  60. #include "libxl_internal.h"
  61. END_CALLOUT
  62. #include "_libxl_save_msgs_${ah}.h"
  63. #include <xenctrl.h>
  64. #include <xenguest.h>
  65. END_HELPER
  66. }
  67. die $want_ah unless defined $out_body{$want_ah};
  68. sub f_decl ($$$$) {
  69. my ($name, $ah, $c_rtype, $c_decl) = @_;
  70. $out_decls{$name} = "${declprefix}$c_rtype $name$c_decl;\n";
  71. $func{$name} = "$c_rtype $name$c_decl\n{\n" . ($func{$name} || '');
  72. $func_ah{$name} = $ah;
  73. }
  74. sub f_more ($$) {
  75. my ($name, $addbody) = @_;
  76. $func{$name} ||= '';
  77. $func{$name} .= $addbody;
  78. push @outfuncs, $name;
  79. }
  80. our $libxl = "libxl__srm";
  81. our $callback = "${libxl}_callout_callback";
  82. our $receiveds = "${libxl}_callout_received";
  83. our $sendreply = "${libxl}_callout_sendreply";
  84. our $getcallbacks = "${libxl}_callout_get_callbacks";
  85. our $enumcallbacks = "${libxl}_callout_enumcallbacks";
  86. sub cbtype ($) { "${libxl}_".$_[0]."_autogen_callbacks"; };
  87. f_decl($sendreply, 'callout', 'void', "(int r, void *user)");
  88. our $helper = "helper";
  89. our $encode = "${helper}_stub";
  90. our $allocbuf = "${helper}_allocbuf";
  91. our $transmit = "${helper}_transmitmsg";
  92. our $getreply = "${helper}_getreply";
  93. our $setcallbacks = "${helper}_setcallbacks";
  94. f_decl($allocbuf, 'helper', 'unsigned char *', '(int len, void *user)');
  95. f_decl($transmit, 'helper', 'void',
  96. '(unsigned char *msg_freed, int len, void *user)');
  97. f_decl($getreply, 'helper', 'int', '(void *user)');
  98. sub typeid ($) { my ($t) = @_; $t =~ s/\W/_/; return $t; };
  99. $out_body{'callout'} .= <<END;
  100. static int bytes_get(const unsigned char **msg,
  101. const unsigned char *const endmsg,
  102. void *result, int rlen)
  103. {
  104. if (endmsg - *msg < rlen) return 0;
  105. memcpy(result,*msg,rlen);
  106. *msg += rlen;
  107. return 1;
  108. }
  109. END
  110. $out_body{'helper'} .= <<END;
  111. static void bytes_put(unsigned char *const buf, int *len,
  112. const void *value, int vlen)
  113. {
  114. assert(vlen < INT_MAX/2 - *len);
  115. if (buf)
  116. memcpy(buf + *len, value, vlen);
  117. *len += vlen;
  118. }
  119. END
  120. foreach my $simpletype (qw(int uint16_t uint32_t unsigned), 'unsigned long') {
  121. my $typeid = typeid($simpletype);
  122. $out_body{'callout'} .= <<END;
  123. static int ${typeid}_get(const unsigned char **msg,
  124. const unsigned char *const endmsg,
  125. $simpletype *result)
  126. {
  127. return bytes_get(msg, endmsg, result, sizeof(*result));
  128. }
  129. END
  130. $out_body{'helper'} .= <<END;
  131. static void ${typeid}_put(unsigned char *const buf, int *len,
  132. const $simpletype value)
  133. {
  134. bytes_put(buf, len, &value, sizeof(value));
  135. }
  136. END
  137. }
  138. $out_body{'callout'} .= <<END;
  139. static int BLOCK_get(const unsigned char **msg,
  140. const unsigned char *const endmsg,
  141. const uint8_t **result, uint32_t *result_size)
  142. {
  143. if (!uint32_t_get(msg,endmsg,result_size)) return 0;
  144. if (endmsg - *msg < *result_size) return 0;
  145. *result = (const void*)*msg;
  146. *msg += *result_size;
  147. return 1;
  148. }
  149. static int STRING_get(const unsigned char **msg,
  150. const unsigned char *const endmsg,
  151. const char **result)
  152. {
  153. const uint8_t *data;
  154. uint32_t datalen;
  155. if (!BLOCK_get(msg,endmsg,&data,&datalen)) return 0;
  156. if (datalen == 0) return 0;
  157. if (data[datalen-1] != '\\0') return 0;
  158. *result = (const void*)data;
  159. return 1;
  160. }
  161. END
  162. $out_body{'helper'} .= <<END;
  163. static void BLOCK_put(unsigned char *const buf,
  164. int *len,
  165. const uint8_t *bytes, uint32_t size)
  166. {
  167. uint32_t_put(buf, len, size);
  168. bytes_put(buf, len, bytes, size);
  169. }
  170. static void STRING_put(unsigned char *const buf,
  171. int *len,
  172. const char *string)
  173. {
  174. size_t slen = strlen(string);
  175. assert(slen < INT_MAX / 4);
  176. assert(slen < (uint32_t)0x40000000);
  177. BLOCK_put(buf, len, (const void*)string, slen+1);
  178. }
  179. END
  180. foreach my $sr (qw(save restore)) {
  181. f_decl("${getcallbacks}_${sr}", 'callout',
  182. "const ".cbtype($sr)." *",
  183. "(void *data)");
  184. f_decl("${receiveds}_${sr}", 'callout', 'int',
  185. "(const unsigned char *msg, uint32_t len, void *user)");
  186. f_decl("${enumcallbacks}_${sr}", 'callout', 'unsigned',
  187. "(const ".cbtype($sr)." *cbs)");
  188. f_more("${enumcallbacks}_${sr}", " unsigned cbflags = 0;\n");
  189. f_decl("${setcallbacks}_${sr}", 'helper', 'void',
  190. "(struct ${sr}_callbacks *cbs, unsigned cbflags)");
  191. f_more("${receiveds}_${sr}",
  192. <<END_ALWAYS.($debug ? <<END_DEBUG : '').<<END_ALWAYS);
  193. const unsigned char *const endmsg = msg + len;
  194. uint16_t mtype;
  195. if (!uint16_t_get(&msg,endmsg,&mtype)) return 0;
  196. END_ALWAYS
  197. fprintf(stderr,"libxl callout receiver: got len=%u mtype=%u\\n",len,mtype);
  198. END_DEBUG
  199. switch (mtype) {
  200. END_ALWAYS
  201. $cbs{$sr} = "typedef struct ".cbtype($sr)." {\n";
  202. }
  203. foreach my $msginfo (@msgs) {
  204. my ($msgnum, $flags, $name, $args) = @$msginfo;
  205. die if $msgnum_used{$msgnum}++;
  206. my $f_more_sr = sub {
  207. my ($contents_spec, $fnamebase) = @_;
  208. $fnamebase ||= "${receiveds}";
  209. foreach my $sr (qw(save restore)) {
  210. $sr =~ m/^./;
  211. next unless $flags =~ m/$&/;
  212. my $contents = (!ref $contents_spec) ? $contents_spec :
  213. $contents_spec->($sr);
  214. f_more("${fnamebase}_${sr}", $contents);
  215. }
  216. };
  217. $f_more_sr->(" case $msgnum: { /* $name */\n");
  218. if ($flags =~ m/W/) {
  219. $f_more_sr->(" int r;\n");
  220. }
  221. my $c_rtype_helper = $flags =~ m/[WA]/ ? 'int' : 'void';
  222. my $c_rtype_callout = $flags =~ m/W/ ? 'int' : 'void';
  223. my $c_decl = '(';
  224. my $c_callback_args = '';
  225. f_more("${encode}_$name",
  226. <<END_ALWAYS.($debug ? <<END_DEBUG : '').<<END_ALWAYS);
  227. unsigned char *buf = 0;
  228. int len = 0, allocd = 0;
  229. END_ALWAYS
  230. fprintf(stderr,"libxl-save-helper: encoding $name\\n");
  231. END_DEBUG
  232. for (;;) {
  233. uint16_t_put(buf, &len, $msgnum /* $name */);
  234. END_ALWAYS
  235. my @args = @$args;
  236. my $c_recv = '';
  237. my ($argtype, $arg);
  238. while (($argtype, $arg, @args) = @args) {
  239. my $typeid = typeid($argtype);
  240. my $c_args = "$arg";
  241. my $c_get_args = "&$arg";
  242. if ($argtype eq 'STRING') {
  243. $c_decl .= "const char *$arg, ";
  244. $f_more_sr->(" const char *$arg;\n");
  245. } elsif ($argtype eq 'BLOCK') {
  246. $c_decl .= "const uint8_t *$arg, uint32_t ${arg}_size, ";
  247. $c_args .= ", ${arg}_size";
  248. $c_get_args .= ",&${arg}_size";
  249. $f_more_sr->(" const uint8_t *$arg;\n".
  250. " uint32_t ${arg}_size;\n");
  251. } else {
  252. $c_decl .= "$argtype $arg, ";
  253. $f_more_sr->(" $argtype $arg;\n");
  254. }
  255. $c_callback_args .= "$c_args, ";
  256. $c_recv.=
  257. " if (!${typeid}_get(&msg,endmsg,$c_get_args)) return 0;\n";
  258. f_more("${encode}_$name", " ${typeid}_put(buf, &len, $c_args);\n");
  259. }
  260. $f_more_sr->($c_recv);
  261. $c_decl .= "void *user)";
  262. $c_callback_args .= "user";
  263. $f_more_sr->(" if (msg != endmsg) return 0;\n");
  264. my $c_callback;
  265. if ($flags !~ m/c/) {
  266. $c_callback = "${callback}_$name";
  267. } else {
  268. $f_more_sr->(sub {
  269. my ($sr) = @_;
  270. $cbs{$sr} .= " $c_rtype_callout (*${name})$c_decl;\n";
  271. return
  272. " const ".cbtype($sr)." *const cbs =\n".
  273. " ${getcallbacks}_${sr}(user);\n";
  274. });
  275. $c_callback = "cbs->${name}";
  276. }
  277. my $c_make_callback = "$c_callback($c_callback_args)";
  278. if ($flags !~ m/W/) {
  279. $f_more_sr->(" $c_make_callback;\n");
  280. } else {
  281. $f_more_sr->(" r = $c_make_callback;\n".
  282. " $sendreply(r, user);\n");
  283. f_decl($sendreply, 'callout', 'void', '(int r, void *user)');
  284. }
  285. if ($flags =~ m/x/) {
  286. my $c_v = "(1u<<$msgnum)";
  287. my $c_cb = "cbs->$name";
  288. $f_more_sr->(" if ($c_cb) cbflags |= $c_v;\n", $enumcallbacks);
  289. $f_more_sr->(" $c_cb = (cbflags & $c_v) ? ${encode}_${name} : 0;\n",
  290. $setcallbacks);
  291. }
  292. $f_more_sr->(" return 1;\n }\n\n");
  293. f_decl("${callback}_$name", 'callout', $c_rtype_callout, $c_decl);
  294. f_decl("${encode}_$name", 'helper', $c_rtype_helper, $c_decl);
  295. f_more("${encode}_$name",
  296. " if (buf) break;
  297. buf = ${helper}_allocbuf(len, user);
  298. assert(buf);
  299. allocd = len;
  300. len = 0;
  301. }
  302. assert(len == allocd);
  303. ${transmit}(buf, len, user);
  304. ");
  305. if ($flags =~ m/[WA]/) {
  306. f_more("${encode}_$name",
  307. (<<END_ALWAYS.($debug ? <<END_DEBUG : '').<<END_ALWAYS));
  308. int r = ${helper}_getreply(user);
  309. END_ALWAYS
  310. fprintf(stderr,"libxl-save-helper: $name got reply %d\\n",r);
  311. END_DEBUG
  312. return r;
  313. END_ALWAYS
  314. }
  315. }
  316. print "/* AUTOGENERATED by $0 DO NOT EDIT */\n\n" or die $!;
  317. foreach my $sr (qw(save restore)) {
  318. f_more("${enumcallbacks}_${sr}",
  319. " return cbflags;\n");
  320. f_more("${receiveds}_${sr}",
  321. " default:\n".
  322. " return 0;\n".
  323. " }");
  324. $cbs{$sr} .= "} ".cbtype($sr).";\n\n";
  325. if ($ch eq 'h') {
  326. print $cbs{$sr} or die $!;
  327. print "struct ${sr}_callbacks;\n";
  328. }
  329. }
  330. if ($ch eq 'c') {
  331. foreach my $name (@outfuncs) {
  332. next unless defined $func{$name};
  333. $func{$name} .= "}\n\n";
  334. $out_body{$func_ah{$name}} .= $func{$name};
  335. delete $func{$name};
  336. }
  337. print $out_body{$want_ah} or die $!;
  338. } else {
  339. foreach my $name (sort keys %out_decls) {
  340. next unless $func_ah{$name} eq $want_ah;
  341. print $out_decls{$name} or die $!;
  342. }
  343. }
  344. close STDOUT or die $!;