fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / src / pbc_dump.c
blob4835cd5651b310f615efa9bc89e5b48986c0c18c
1 /*
2 Copyright (C) 2001-2010, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 pbc_dump - Dump or convert Parrot bytecode (PBC) files
9 =head1 SYNOPSIS
11 pbc_dump [-tdh] [--terse|--disassemble|--header-only] file.pbc
13 pbc_dump -o converted.pbc file.pbc
15 =head1 DESCRIPTION
17 A program to dump pack files to human readable form.
19 =head2 Command-Line Options
21 =over 4
23 =item C<-d>
25 Disassemble bytecode segments.
27 =item C<-h>
29 Dump the bytecode header only.
31 =item C<-t>
33 Terse output.
35 =item C<-D> C--debug> 1-7
37 Display detailed packfile reader debugging information if
38 F<include/parrot/packfile.h> enables TRACE_PACKFILE.
40 1 print general debug info
41 2 print alignment info
42 4 print values
44 =item C<-o converted.pbc>
46 Repacks a PBC file into the platform's native binary format for better
47 efficiency on reading non-native PBCs.
49 =back
51 =head2 Functions
53 =over 4
55 =cut
59 #include "parrot/parrot.h"
60 #include "parrot/embed.h"
61 #include "parrot/oplib/ops.h"
62 #include "parrot/oplib/core_ops.h"
66 =item C<static void const_dump(PARROT_INTERP, const PackFile_Segment *segp)>
68 Dump the constant table.
70 =cut
74 static void
75 const_dump(PARROT_INTERP, const PackFile_Segment *segp)
77 Parrot_io_printf(interp, "%Ss => [\n", segp->name);
78 PackFile_ConstTable_dump(interp, (const PackFile_ConstTable *)segp);
79 Parrot_io_printf(interp, "],\n");
85 =item C<static void fixup_dump(PARROT_INTERP, const PackFile_Segment *segp)>
87 Dump the fixup table.
89 =cut
93 static void
94 fixup_dump(PARROT_INTERP, const PackFile_Segment *segp)
96 Parrot_io_printf(interp, "%Ss => [\n", segp->name);
97 PackFile_Fixup_dump(interp, (const PackFile_FixupTable *)segp);
98 Parrot_io_printf(interp, "],\n");
104 =item C<static void disas_dump(PARROT_INTERP, const PackFile_Segment *self)>
106 Disassemble and dump.
108 =cut
112 static void
113 disas_dump(PARROT_INTERP, const PackFile_Segment *self)
115 const opcode_t *pc = self->data;
117 Parrot_io_printf(interp, "%Ss => [ # %d ops at offs 0x%x\n",
118 self->name, (int)self->size, (int)self->file_offset + 4);
120 while (pc < self->data + self->size) {
121 /* n can't be const; the ADD_OP_VAR_PART macro increments it */
122 size_t n = (size_t)interp->code->op_info_table[*pc]->op_count;
123 size_t i;
125 /* trace_op_dump(interp, self->pf->src, pc); */
126 Parrot_io_printf(interp, " %04x: ", (int)(pc - self->data));
128 for (i = 0; i < 6; ++i)
129 if (i < n)
130 Parrot_io_printf(interp, "%08lx ", (unsigned long)pc[i]);
131 else
132 Parrot_io_printf(interp, " ");
134 Parrot_io_printf(interp, "%s\n",
135 interp->code->op_info_table[*pc]->full_name);
137 ADD_OP_VAR_PART(interp, interp->code, pc, n);
138 pc += n;
141 Parrot_io_printf(interp, "]\n");
147 =item C<static void nums_dump(PARROT_INTERP, const PackFile_Segment *self)>
149 Disassembles and dumps op names and line numbers only.
151 =cut
155 static void
156 nums_dump(PARROT_INTERP, const PackFile_Segment *self)
158 const STRING *debug_name = Parrot_str_concat(interp, self->name,
159 Parrot_str_new_constant(interp, "_DB"));
160 const PackFile_Segment *debug = PackFile_find_segment(interp,
161 self->dir, debug_name, 1);
163 opcode_t * pc = self->data;
164 opcode_t * debug_ops = debug->data;
165 op_info_t ** const op_info = interp->code->op_info_table;
167 while (pc < self->data + self->size) {
168 /* n can't be const; the ADD_OP_VAR_PART macro increments it */
169 size_t n = (size_t)op_info[*pc]->op_count;
171 Parrot_io_printf(interp, " %04x: %s\n",
172 *(debug_ops++), op_info[*pc]->full_name);
174 ADD_OP_VAR_PART(interp, interp->code, pc, n);
175 pc += n;
182 =item C<static void null_dump(PARROT_INTERP, const PackFile_Segment *self)>
184 Produces no output for the given segment type.
186 =cut
190 static void
191 null_dump(SHIM_INTERP, const PackFile_Segment *self)
193 UNUSED(self);
199 =item C<static void null_dir_dump(PARROT_INTERP, const PackFile_Segment *self)>
201 Dumps all of the segments of the given PackFile_Directory, but produces no
202 output for the directory itself.
204 =cut
208 static void
209 null_dir_dump(PARROT_INTERP, const PackFile_Segment *self)
211 const PackFile_Directory * const dir = (const PackFile_Directory *)self;
212 size_t i;
214 for (i = 0; i < dir->num_segments; ++i)
215 self->pf->PackFuncs[dir->segments[i]->type].dump(interp, dir->segments[i]);
221 =item C<static void PackFile_header_dump(PARROT_INTERP, PackFile *pf)>
223 Dump the header.
225 =cut
229 static void
230 PackFile_header_dump(PARROT_INTERP, PackFile *pf)
232 Parrot_io_printf(interp, "HEADER => [\n");
233 Parrot_io_printf(interp, "\twordsize = %d", pf->header->wordsize);
234 Parrot_io_printf(interp, "\t(interpreter's wordsize/INTVAL = %d/%d)\n",
235 sizeof (opcode_t), sizeof (INTVAL));
236 Parrot_io_printf(interp, "\tbyteorder = %d", pf->header->byteorder);
237 Parrot_io_printf(interp, "\t(interpreter's byteorder = %d)\n",
238 PARROT_BIGENDIAN);
239 Parrot_io_printf(interp, "\tfloattype = %d", pf->header->floattype);
240 Parrot_io_printf(interp, "\t(interpreter's NUMVAL_SIZE = %d)\n",
241 NUMVAL_SIZE);
242 Parrot_io_printf(interp, "\tparrot-version %d.%d.%d, "
243 "bytecode-version %d.%d\n",
244 pf->header->major, pf->header->minor, pf->header->patch,
245 pf->header->bc_major, pf->header->bc_minor);
246 Parrot_io_printf(interp, "\tUUID: type = %d, size = %d",
247 pf->header->uuid_type, pf->header->uuid_size);
249 if (pf->header->uuid_size)
250 Parrot_io_printf(interp, ", '%s'\n", pf->header->uuid_data);
251 else
252 Parrot_io_printf(interp, "\n");
254 Parrot_io_printf(interp, "\t%s endianize, %s opcode, %s numval transform\n",
255 pf->need_endianize ? "**need**" : "no",
256 pf->need_wordsize ? "**need**" : "no",
257 pf->fetch_nv ? "**need**" : "no");
259 Parrot_io_printf(interp, "\tdirformat = %d\n", pf->header->dir_format);
260 Parrot_io_printf(interp, "]\n");
266 =item C<static void help(void)>
268 Print out the user help info.
270 =cut
274 static void help(void)
276 printf("pbc_dump - dump or convert parrot bytecode (PBC) files\n");
277 printf("usage:\n");
278 printf("pbc_dump [-tdh] [--terse|--disassemble|--header-only|--line-nums]"
279 " file.pbc\n");
280 printf("pbc_dump -o converted.pbc file.pbc\n\n");
281 printf("\t-d ... disassemble bytecode segments\n");
282 printf("\t-h ... dump header only\n");
283 printf("\t-t ... terse output\n");
284 printf("\t-n ... show ops and line numbers only\n");
286 #if TRACE_PACKFILE
287 printf("\t-D<1-7> --debug debug output\n");
288 printf("\t 1 general info\n");
289 printf("\t 2 alignment\n");
290 printf("\t 4 values\n");
291 #endif
293 printf("\t-o converted.pbc ... repacks a PBC file into "
294 "the platform's native\n");
295 printf("\t binary format for better efficiency on reading "
296 "non native PBCs\n");
297 exit(EXIT_SUCCESS);
301 static struct longopt_opt_decl opt_options[] = {
302 { 'h', 'h', OPTION_optional_FLAG, { "--header-only" } },
303 { '?', '?', OPTION_optional_FLAG, { "--help" } },
304 { 't', 't', OPTION_optional_FLAG, { "--terse" } },
305 { 'n', 'n', OPTION_optional_FLAG, { "--line-nums" } },
306 { 'd', 'd', OPTION_optional_FLAG, { "--disassemble" } },
307 { 'o', 'o', OPTION_required_FLAG, { "--output" } }
309 #if TRACE_PACKFILE
310 { 'D', 'D', OPTION_required_FLAG, { "--debug" } },
311 #endif
317 =item C<int main(int argc, const char **argv)>
319 The run loop. Process the command-line arguments and dump accordingly.
321 =cut
326 main(int argc, const char **argv)
328 PackFile *pf;
329 Interp *interp;
331 const char *file = NULL;
332 int terse = 0;
333 int disas = 0;
334 int convert = 0;
335 int nums_only = 0;
336 int options = PFOPT_UTILS;
338 struct longopt_opt_info opt = LONGOPT_OPT_INFO_INIT;
340 int status;
342 if (argc < 2)
343 help();
345 interp = Parrot_new(NULL);
347 /* init and set top of stack */
348 Parrot_init_stacktop(interp, &status);
350 while ((status = longopt_get(interp, argc, argv, opt_options, &opt)) > 0) {
351 switch (opt.opt_id) {
352 #if TRACE_PACKFILE
353 case 'D':
354 options += atoi(opt.opt_arg) << 2;
355 break;
356 #endif
357 case 'h':
358 options += PFOPT_HEADERONLY;
359 break;
360 case 't':
361 terse = 1;
362 break;
363 case 'd':
364 disas = 1;
365 break;
366 case 'o':
367 file = opt.opt_arg;
368 convert = 1;
369 break;
370 case 'n':
371 nums_only = 1;
372 break;
373 case '?':
374 default:
375 help();
376 break;
380 if (status == -1)
381 help();
383 argc -= opt.opt_index;
384 argv += opt.opt_index;
386 pf = Parrot_pbc_read(interp, *argv, options);
388 if (!pf) {
389 printf("Can't read PBC\n");
390 return 1;
393 Parrot_pbc_load(interp, pf);
395 if (convert) {
396 size_t size = PackFile_pack_size(interp,
397 interp->code->base.pf) * sizeof (opcode_t);
398 opcode_t *pack = (opcode_t *)Parrot_gc_allocate_memory_chunk(interp,
399 size);
400 FILE *fp;
402 if (!pack) {
403 printf("out of mem\n");
404 exit(EXIT_FAILURE);
407 PackFile_pack(interp, interp->code->base.pf, pack);
409 if (STREQ(file, "-"))
410 fp = stdout;
411 else if ((fp = fopen(file, "wb")) == 0) {
412 printf("Couldn't open %s\n", file);
413 exit(EXIT_FAILURE);
416 if ((1 != fwrite(pack, size, 1, fp))) {
417 printf("Couldn't write %s\n", file);
418 exit(EXIT_FAILURE);
421 fclose(fp);
422 Parrot_gc_free_memory_chunk(interp, pack);
423 Parrot_exit(interp, 0);
426 if (!nums_only)
427 PackFile_header_dump(interp, pf);
429 if (options & PFOPT_HEADERONLY)
430 Parrot_exit(interp, 0);
432 /* install a dumper function */
433 if (!terse) {
434 pf->PackFuncs[PF_CONST_SEG].dump = const_dump;
435 pf->PackFuncs[PF_FIXUP_SEG].dump = fixup_dump;
438 if (disas)
439 pf->PackFuncs[PF_BYTEC_SEG].dump = disas_dump;
441 if (nums_only) {
442 int i;
444 for (i = PF_DIR_SEG + 1; i < PF_MAX_SEG; ++i)
445 pf->PackFuncs[i].dump = null_dump;
447 pf->PackFuncs[PF_DIR_SEG].dump = null_dir_dump;
448 pf->PackFuncs[PF_BYTEC_SEG].dump = nums_dump;
451 /* do a directory dump, which dumps segs then */
452 PackFile_Segment_dump(interp, &pf->directory.base);
454 Parrot_exit(interp, 0);
460 =back
462 =head1 SEE ALSO
464 F<src/packdump.c>.
466 =cut
471 * Local variables:
472 * c-file-style: "parrot"
473 * End:
474 * vim: expandtab shiftwidth=4: