This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
perl 5.0 alpha 3
[perl5.git] / c2ph
CommitLineData
79072805
LW
1#!/usr/local/bin/perl
2#
3#
4# c2ph (aka pstruct)
5# Tom Christiansen, <tchrist@convex.com>
6#
7# As pstruct, dump C structures as generated from 'cc -g -S' stabs.
8# As c2ph, do this PLUS generate perl code for getting at the structures.
9#
10# See the usage message for more. If this isn't enough, read the code.
11#
12
13$RCSID = '$RCSfile: c2ph.SH,v $$Revision: 4.1 $$Date: 92/08/07 17:19:10 $';
14
15
16######################################################################
17
18# some handy data definitions. many of these can be reset later.
19
20$bitorder = 'b'; # ascending; set to B for descending bit fields
21
22%intrinsics =
23%template = (
24 'char', 'c',
25 'unsigned char', 'C',
26 'short', 's',
27 'short int', 's',
28 'unsigned short', 'S',
29 'unsigned short int', 'S',
30 'short unsigned int', 'S',
31 'int', 'i',
32 'unsigned int', 'I',
33 'long', 'l',
34 'long int', 'l',
35 'unsigned long', 'L',
36 'unsigned long', 'L',
37 'long unsigned int', 'L',
38 'unsigned long int', 'L',
39 'long long', 'q',
40 'long long int', 'q',
41 'unsigned long long', 'Q',
42 'unsigned long long int', 'Q',
43 'float', 'f',
44 'double', 'd',
45 'pointer', 'p',
46 'null', 'x',
47 'neganull', 'X',
48 'bit', $bitorder,
49);
50
51&buildscrunchlist;
52delete $intrinsics{'neganull'};
53delete $intrinsics{'bit'};
54delete $intrinsics{'null'};
55
56# use -s to recompute sizes
57%sizeof = (
58 'char', '1',
59 'unsigned char', '1',
60 'short', '2',
61 'short int', '2',
62 'unsigned short', '2',
63 'unsigned short int', '2',
64 'short unsigned int', '2',
65 'int', '4',
66 'unsigned int', '4',
67 'long', '4',
68 'long int', '4',
69 'unsigned long', '4',
70 'unsigned long int', '4',
71 'long unsigned int', '4',
72 'long long', '8',
73 'long long int', '8',
74 'unsigned long long', '8',
75 'unsigned long long int', '8',
76 'float', '4',
77 'double', '8',
78 'pointer', '4',
79);
80
81($type_width, $member_width, $offset_width, $size_width) = (20, 20, 6, 5);
82
83($offset_fmt, $size_fmt) = ('d', 'd');
84
85$indent = 2;
86
87$CC = 'cc';
88$CFLAGS = '-g -S';
89$DEFINES = '';
90
91$perl++ if $0 =~ m#/?c2ph$#;
92
93require 'getopts.pl';
94
95eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;
96
97&Getopts('aixdpvtnws:') || &usage(0);
98
99$opt_d && $debug++;
100$opt_t && $trace++;
101$opt_p && $perl++;
102$opt_v && $verbose++;
103$opt_n && ($perl = 0);
104
105if ($opt_w) {
106 ($type_width, $member_width, $offset_width) = (45, 35, 8);
107}
108if ($opt_x) {
109 ($offset_fmt, $offset_width, $size_fmt, $size_width) = ( 'x', '08', 'x', 04 );
110}
111
112eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;
113
114sub PLUMBER {
115 select(STDERR);
116 print "oops, apperent pager foulup\n";
117 $isatty++;
118 &usage(1);
119}
120
121sub usage {
122 local($oops) = @_;
123 unless (-t STDOUT) {
124 select(STDERR);
125 } elsif (!$oops) {
126 $isatty++;
127 $| = 1;
128 print "hit <RETURN> for further explanation: ";
129 <STDIN>;
130 open (PIPE, "|". ($ENV{PAGER} || 'more'));
131 $SIG{PIPE} = PLUMBER;
132 select(PIPE);
133 }
134
135 print "usage: $0 [-dpnP] [var=val] [files ...]\n";
136
137 exit unless $isatty;
138
139 print <<EOF;
140
141Options:
142
143-w wide; short for: type_width=45 member_width=35 offset_width=8
144-x hex; short for: offset_fmt=x offset_width=08 size_fmt=x size_width=04
145
146-n do not generate perl code (default when invoked as pstruct)
147-p generate perl code (default when invoked as c2ph)
148-v generate perl code, with C decls as comments
149
150-i do NOT recompute sizes for intrinsic datatypes
151-a dump information on intrinsics also
152
153-t trace execution
154-d spew reams of debugging output
155
156-slist give comma-separated list a structures to dump
157
158
159Var Name Default Value Meaning
160
161EOF
162
163 &defvar('CC', 'which_compiler to call');
164 &defvar('CFLAGS', 'how to generate *.s files with stabs');
165 &defvar('DEFINES','any extra cflags or cpp defines, like -I, -D, -U');
166
167 print "\n";
168
169 &defvar('type_width', 'width of type field (column 1)');
170 &defvar('member_width', 'width of member field (column 2)');
171 &defvar('offset_width', 'width of offset field (column 3)');
172 &defvar('size_width', 'width of size field (column 4)');
173
174 print "\n";
175
176 &defvar('offset_fmt', 'sprintf format type for offset');
177 &defvar('size_fmt', 'sprintf format type for size');
178
179 print "\n";
180
181 &defvar('indent', 'how far to indent each nesting level');
182
183 print <<'EOF';
184
185 If any *.[ch] files are given, these will be catted together into
186 a temporary *.c file and sent through:
187 $CC $CFLAGS $DEFINES
188 and the resulting *.s groped for stab information. If no files are
189 supplied, then stdin is read directly with the assumption that it
190 contains stab information. All other liens will be ignored. At
191 most one *.s file should be supplied.
192
193EOF
194 close PIPE;
195 exit 1;
196}
197
198sub defvar {
199 local($var, $msg) = @_;
200 printf "%-16s%-15s %s\n", $var, eval "\$$var", $msg;
201}
202
203$recurse = 1;
204
205if (@ARGV) {
206 if (grep(!/\.[csh]$/,@ARGV)) {
207 warn "Only *.[csh] files expected!\n";
208 &usage;
209 }
210 elsif (grep(/\.s$/,@ARGV)) {
211 if (@ARGV > 1) {
212 warn "Only one *.s file allowed!\n";
213 &usage;
214 }
215 }
216 elsif (@ARGV == 1 && $ARGV[0] =~ /\.c$/) {
217 local($dir, $file) = $ARGV[0] =~ m#(.*/)?(.*)$#;
218 $chdir = "cd $dir; " if $dir;
219 &system("$chdir$CC $CFLAGS $DEFINES $file") && exit 1;
220 $ARGV[0] =~ s/\.c$/.s/;
221 }
222 else {
223 $TMP = "/tmp/c2ph.$$.c";
224 &system("cat @ARGV > $TMP") && exit 1;
225 &system("cd /tmp; $CC $CFLAGS $DEFINES $TMP") && exit 1;
226 unlink $TMP;
227 $TMP =~ s/\.c$/.s/;
228 @ARGV = ($TMP);
229 }
230}
231
232if ($opt_s) {
233 for (split(/[\s,]+/, $opt_s)) {
234 $interested{$_}++;
235 }
236}
237
238
239$| = 1 if $debug;
240
241main: {
242
243 if ($trace) {
244 if (-t && !@ARGV) {
245 print STDERR "reading from your keyboard: ";
246 } else {
247 print STDERR "reading from " . (@ARGV ? "@ARGV" : "<STDIN>").": ";
248 }
249 }
250
251STAB: while (<>) {
252 if ($trace && !($. % 10)) {
253 $lineno = $..'';
254 print STDERR $lineno, "\b" x length($lineno);
255 }
256 next unless /^\s*\.stabs\s+/;
257 $line = $_;
258 s/^\s*\.stabs\s+//;
259 &stab;
260 }
261 print STDERR "$.\n" if $trace;
262 unlink $TMP if $TMP;
263
264 &compute_intrinsics if $perl && !$opt_i;
265
266 print STDERR "resolving types\n" if $trace;
267
268 &resolve_types;
269 &adjust_start_addrs;
270
271 $sum = 2 + $type_width + $member_width;
272 $pmask1 = "%-${type_width}s %-${member_width}s";
273 $pmask2 = "%-${sum}s %${offset_width}${offset_fmt}%s %${size_width}${size_fmt}%s";
274
275 if ($perl) {
276 # resolve template -- should be in stab define order, but even this isn't enough.
277 print STDERR "\nbuilding type templates: " if $trace;
278 for $i (reverse 0..$#type) {
279 next unless defined($name = $type[$i]);
280 next unless defined $struct{$name};
281 $build_recursed = 0;
282 &build_template($name) unless defined $template{&psou($name)} ||
283 $opt_s && !$interested{$name};
284 }
285 print STDERR "\n\n" if $trace;
286 }
287
288 print STDERR "dumping structs: " if $trace;
289
290
291 foreach $name (sort keys %struct) {
292 next if $opt_s && !$interested{$name};
293 print STDERR "$name " if $trace;
294
295 undef @sizeof;
296 undef @typedef;
297 undef @offsetof;
298 undef @indices;
299 undef @typeof;
300
301 $mname = &munge($name);
302
303 $fname = &psou($name);
304
305 print "# " if $perl && $verbose;
306 $pcode = '';
307 print "$fname {\n" if !$perl || $verbose;
308 $template{$fname} = &scrunch($template{$fname}) if $perl;
309 &pstruct($name,$name,0);
310 print "# " if $perl && $verbose;
311 print "}\n" if !$perl || $verbose;
312 print "\n" if $perl && $verbose;
313
314 if ($perl) {
315 print "$pcode";
316
317 printf("\nsub %-32s { %4d; }\n\n", "${mname}'struct", $countof{$name});
318
319 print <<EOF;
320sub ${mname}'typedef {
321 local(\$${mname}'index) = shift;
322 defined \$${mname}'index
323 ? \$${mname}'typedef[\$${mname}'index]
324 : \$${mname}'typedef;
325}
326EOF
327
328 print <<EOF;
329sub ${mname}'sizeof {
330 local(\$${mname}'index) = shift;
331 defined \$${mname}'index
332 ? \$${mname}'sizeof[\$${mname}'index]
333 : \$${mname}'sizeof;
334}
335EOF
336
337 print <<EOF;
338sub ${mname}'offsetof {
339 local(\$${mname}'index) = shift;
340 defined \$${mname}index
341 ? \$${mname}'offsetof[\$${mname}'index]
342 : \$${mname}'sizeof;
343}
344EOF
345
346 print <<EOF;
347sub ${mname}'typeof {
348 local(\$${mname}'index) = shift;
349 defined \$${mname}index
350 ? \$${mname}'typeof[\$${mname}'index]
351 : '$name';
352}
353EOF
354
355
356 print "\$${mname}'typedef = '" . &scrunch($template{$fname})
357 . "';\n";
358
359 print "\$${mname}'sizeof = $sizeof{$name};\n\n";
360
361
362 print "\@${mname}'indices = (", &squishseq(@indices), ");\n";
363
364 print "\n";
365
366 print "\@${mname}'typedef[\@${mname}'indices] = (",
367 join("\n\t", '', @typedef), "\n );\n\n";
368 print "\@${mname}'sizeof[\@${mname}'indices] = (",
369 join("\n\t", '', @sizeof), "\n );\n\n";
370 print "\@${mname}'offsetof[\@${mname}'indices] = (",
371 join("\n\t", '', @offsetof), "\n );\n\n";
372 print "\@${mname}'typeof[\@${mname}'indices] = (",
373 join("\n\t", '', @typeof), "\n );\n\n";
374
375 $template_printed{$fname}++;
376 $size_printed{$fname}++;
377 }
378 print "\n";
379 }
380
381 print STDERR "\n" if $trace;
382
383 unless ($perl && $opt_a) {
384 print "\n1;\n";
385 exit;
386 }
387
388
389
390 foreach $name (sort bysizevalue keys %intrinsics) {
391 next if $size_printed{$name};
392 print '$',&munge($name),"'sizeof = ", $sizeof{$name}, ";\n";
393 }
394
395 print "\n";
396
397 sub bysizevalue { $sizeof{$a} <=> $sizeof{$b}; }
398
399
400 foreach $name (sort keys %intrinsics) {
401 print '$',&munge($name),"'typedef = '", $template{$name}, "';\n";
402 }
403
404 print "\n1;\n";
405
406 exit;
407}
408
409########################################################################################
410
411
412sub stab {
413 next unless /:[\$\w]+(\(\d+,\d+\))?=[\*\$\w]+/; # (\d+,\d+) is for sun
414 s/"// || next;
415 s/",([x\d]+),([x\d]+),([x\d]+),.*// || next;
416
417 next if /^\s*$/;
418
419 $size = $3 if $3;
420
421
422 $line = $_;
423
424 if (($name, $pdecl) = /^([\$ \w]+):[tT]((\d+)(=[rufs*](\d+))+)$/) {
425 print "$name is a typedef for some funky pointers: $pdecl\n" if $debug;
426 &pdecl($pdecl);
427 next;
428 }
429
430
431
432 if (/(([ \w]+):t(\d+|\(\d+,\d+\)))=r?(\d+|\(\d+,\d+\))(;\d+;\d+;)?/) {
433 local($ident) = $2;
434 push(@intrinsics, $ident);
435 $typeno = &typeno($3);
436 $type[$typeno] = $ident;
437 print STDERR "intrinsic $ident in new type $typeno\n" if $debug;
438 next;
439 }
440
441 if (($name, $typeordef, $typeno, $extra, $struct, $_)
442 = /^([\$ \w]+):([ustT])(\d+|\(\d+,\d+\))(=[rufs*](\d+))?(.*)$/)
443 {
444 $typeno = &typeno($typeno); # sun foolery
445 }
446 elsif (/^[\$\w]+:/) {
447 next; # variable
448 }
449 else {
450 warn "can't grok stab: <$_> in: $line " if $_;
451 next;
452 }
453
454 #warn "got size $size for $name\n";
455 $sizeof{$name} = $size if $size;
456
457 s/;[-\d]*;[-\d]*;$//; # we don't care about ranges
458
459 $typenos{$name} = $typeno;
460
461 unless (defined $type[$typeno]) {
462 &panic("type 0??") unless $typeno;
463 $type[$typeno] = $name unless defined $type[$typeno];
464 printf "new type $typeno is $name" if $debug;
465 if ($extra =~ /\*/ && defined $type[$struct]) {
466 print ", a typedef for a pointer to " , $type[$struct] if $debug;
467 }
468 } else {
469 printf "%s is type %d", $name, $typeno if $debug;
470 print ", a typedef for " , $type[$typeno] if $debug;
471 }
472 print "\n" if $debug;
473 #next unless $extra =~ /[su*]/;
474
475 #$type[$struct] = $name;
476
477 if ($extra =~ /[us*]/) {
478 &sou($name, $extra);
479 $_ = &sdecl($name, $_, 0);
480 }
481 elsif (/^=ar/) {
482 print "it's a bare array typedef -- that's pretty sick\n" if $debug;
483 $_ = "$typeno$_";
484 $scripts = '';
485 $_ = &adecl($_,1);
486
487 }
488 elsif (s/((\w+):t(\d+|\(\d+,\d+\)))?=r?(;\d+;\d+;)?//) { # the ?'s are for gcc
489 push(@intrinsics, $2);
490 $typeno = &typeno($3);
491 $type[$typeno] = $2;
492 print STDERR "intrinsic $2 in new type $typeno\n" if $debug;
493 }
494 elsif (s/^=e//) { # blessed by thy compiler; mine won't do this
495 &edecl;
496 }
497 else {
498 warn "Funny remainder for $name on line $_ left in $line " if $_;
499 }
500}
501
502sub typeno { # sun thinks types are (0,27) instead of just 27
503 local($_) = @_;
504 s/\(\d+,(\d+)\)/$1/;
505 $_;
506}
507
508sub pstruct {
509 local($what,$prefix,$base) = @_;
510 local($field, $fieldname, $typeno, $count, $offset, $entry);
511 local($fieldtype);
512 local($type, $tname);
513 local($mytype, $mycount, $entry2);
514 local($struct_count) = 0;
515 local($pad, $revpad, $length, $prepad, $lastoffset, $lastlength, $fmt);
516 local($bits,$bytes);
517 local($template);
518
519
520 local($mname) = &munge($name);
521
522 sub munge {
523 local($_) = @_;
524 s/[\s\$\.]/_/g;
525 $_;
526 }
527
528 local($sname) = &psou($what);
529
530 $nesting++;
531
532 for $field (split(/;/, $struct{$what})) {
533 $pad = $prepad = 0;
534 $entry = '';
535 ($fieldname, $typeno, $count, $offset, $length) = split(/,/, $field);
536
537 $type = $type[$typeno];
538
539 $type =~ /([^[]*)(\[.*\])?/;
540 $mytype = $1;
541 $count .= $2;
542 $fieldtype = &psou($mytype);
543
544 local($fname) = &psou($name);
545
546 if ($build_templates) {
547
548 $pad = ($offset - ($lastoffset + $lastlength))/8
549 if defined $lastoffset;
550
551 if (! $finished_template{$sname}) {
552 if ($isaunion{$what}) {
553 $template{$sname} .= 'X' x $revpad . ' ' if $revpad;
554 } else {
555 $template{$sname} .= 'x' x $pad . ' ' if $pad;
556 }
557 }
558
559 $template = &fetch_template($type) x
560 ($count ? &scripts2count($count) : 1);
561
562 if (! $finished_template{$sname}) {
563 $template{$sname} .= $template;
564 }
565
566 $revpad = $length/8 if $isaunion{$what};
567
568 ($lastoffset, $lastlength) = ($offset, $length);
569
570 } else {
571 print '# ' if $perl && $verbose;
572 $entry = sprintf($pmask1,
573 ' ' x ($nesting * $indent) . $fieldtype,
574 "$prefix.$fieldname" . $count);
575
576 $entry =~ s/(\*+)( )/$2$1/;
577
578 printf $pmask2,
579 $entry,
580 ($base+$offset)/8,
581 ($bits = ($base+$offset)%8) ? ".$bits" : " ",
582 $length/8,
583 ($bits = $length % 8) ? ".$bits": ""
584 if !$perl || $verbose;
585
586
587 if ($perl && $nesting == 1) {
588 $template = &scrunch(&fetch_template($type) x
589 ($count ? &scripts2count($count) : 1));
590 push(@sizeof, int($length/8) .",\t# $fieldname");
591 push(@offsetof, int($offset/8) .",\t# $fieldname");
592 push(@typedef, "'$template', \t# $fieldname");
593 $type =~ s/(struct|union) //;
594 push(@typeof, "'$type" . ($count ? $count : '') .
595 "',\t# $fieldname");
596 }
597
598 print ' ', ' ' x $indent x $nesting, $template
599 if $perl && $verbose;
600
601 print "\n" if !$perl || $verbose;
602
603 }
604 if ($perl) {
605 local($mycount) = defined $struct{$mytype} ? $countof{$mytype} : 1;
606 $mycount *= &scripts2count($count) if $count;
607 if ($nesting==1 && !$build_templates) {
608 $pcode .= sprintf("sub %-32s { %4d; }\n",
609 "${mname}'${fieldname}", $struct_count);
610 push(@indices, $struct_count);
611 }
612 $struct_count += $mycount;
613 }
614
615
616 &pstruct($type, "$prefix.$fieldname", $base+$offset)
617 if $recurse && defined $struct{$type};
618 }
619
620 $countof{$what} = $struct_count unless defined $countof{$whati};
621
622 $template{$sname} .= '$' if $build_templates;
623 $finished_template{$sname}++;
624
625 if ($build_templates && !defined $sizeof{$name}) {
626 local($fmt) = &scrunch($template{$sname});
627 print STDERR "no size for $name, punting with $fmt..." if $debug;
628 eval '$sizeof{$name} = length(pack($fmt, ()))';
629 if ($@) {
630 chop $@;
631 warn "couldn't get size for \$name: $@";
632 } else {
633 print STDERR $sizeof{$name}, "\n" if $debUg;
634 }
635 }
636
637 --$nesting;
638}
639
640
641sub psize {
642 local($me) = @_;
643 local($amstruct) = $struct{$me} ? 'struct ' : '';
644
645 print '$sizeof{\'', $amstruct, $me, '\'} = ';
646 printf "%d;\n", $sizeof{$me};
647}
648
649sub pdecl {
650 local($pdecl) = @_;
651 local(@pdecls);
652 local($tname);
653
654 warn "pdecl: $pdecl\n" if $debug;
655
656 $pdecl =~ s/\(\d+,(\d+)\)/$1/g;
657 $pdecl =~ s/\*//g;
658 @pdecls = split(/=/, $pdecl);
659 $typeno = $pdecls[0];
660 $tname = pop @pdecls;
661
662 if ($tname =~ s/^f//) { $tname = "$tname&"; }
663 #else { $tname = "$tname*"; }
664
665 for (reverse @pdecls) {
666 $tname .= s/^f// ? "&" : "*";
667 #$tname =~ s/^f(.*)/$1&/;
668 print "type[$_] is $tname\n" if $debug;
669 $type[$_] = $tname unless defined $type[$_];
670 }
671}
672
673
674
675sub adecl {
676 ($arraytype, $unknown, $lower, $upper) = ();
677 #local($typeno);
678 # global $typeno, @type
679 local($_, $typedef) = @_;
680
681 while (s/^((\d+)=)?ar(\d+);//) {
682 ($arraytype, $unknown) = ($2, $3);
683 if (s/^(\d+);(\d+);//) {
684 ($lower, $upper) = ($1, $2);
685 $scripts .= '[' . ($upper+1) . ']';
686 } else {
687 warn "can't find array bounds: $_";
688 }
689 }
690 if (s/^([\d*f=]*),(\d+),(\d+);//) {
691 ($start, $length) = ($2, $3);
692 local($whatis) = $1;
693 if ($whatis =~ /^(\d+)=/) {
694 $typeno = $1;
695 &pdecl($whatis);
696 } else {
697 $typeno = $whatis;
698 }
699 } elsif (s/^(\d+)(=[*suf]\d*)//) {
700 local($whatis) = $2;
701
702 if ($whatis =~ /[f*]/) {
703 &pdecl($whatis);
704 } elsif ($whatis =~ /[su]/) { #
705 print "$prefix.$fieldname is an array$scripts anon structs; disgusting\n"
706 if $debug;
707 #$type[$typeno] = $name unless defined $type[$typeno];
708 ##printf "new type $typeno is $name" if $debug;
709 $typeno = $1;
710 $type[$typeno] = "$prefix.$fieldname";
711 local($name) = $type[$typeno];
712 &sou($name, $whatis);
713 $_ = &sdecl($name, $_, $start+$offset);
714 1;
715 $start = $start{$name};
716 $offset = $sizeof{$name};
717 $length = $offset;
718 } else {
719 warn "what's this? $whatis in $line ";
720 }
721 } elsif (/^\d+$/) {
722 $typeno = $_;
723 } else {
724 warn "bad array stab: $_ in $line ";
725 next STAB;
726 }
727 #local($wasdef) = defined($type[$typeno]) && $debug;
728 #if ($typedef) {
729 #print "redefining $type[$typeno] to " if $wasdef;
730 #$type[$typeno] = "$whatis$scripts"; # unless defined $type[$typeno];
731 #print "$type[$typeno]\n" if $wasdef;
732 #} else {
733 #$type[$arraytype] = $type[$typeno] unless defined $type[$arraytype];
734 #}
735 $type[$arraytype] = "$type[$typeno]$scripts" if defined $type[$typeno];
736 print "type[$arraytype] is $type[$arraytype]\n" if $debug;
737 print "$prefix.$fieldname is an array of $type[$arraytype]\n" if $debug;
738 $_;
739}
740
741
742
743sub sdecl {
744 local($prefix, $_, $offset) = @_;
745
746 local($fieldname, $scripts, $type, $arraytype, $unknown,
747 $whatis, $pdecl, $upper,$lower, $start,$length) = ();
748 local($typeno,$sou);
749
750
751SFIELD:
752 while (/^([^;]+);/) {
753 $scripts = '';
754 warn "sdecl $_\n" if $debug;
755 if (s/^([\$\w]+)://) {
756 $fieldname = $1;
757 } elsif (s/(\d+)=([us])(\d+|\(\d+,\d+\))//) { #
758 $typeno = &typeno($1);
759 $type[$typeno] = "$prefix.$fieldname";
760 local($name) = "$prefix.$fieldname";
761 &sou($name,$2);
762 $_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
763 $start = $start{$name};
764 $offset += $sizeof{$name};
765 #print "done with anon, start is $start, offset is $offset\n";
766 #next SFIELD;
767 } else {
768 warn "weird field $_ of $line" if $debug;
769 next STAB;
770 #$fieldname = &gensym;
771 #$_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
772 }
773
774 if (/^\d+=ar/) {
775 $_ = &adecl($_);
776 }
777 elsif (s/^(\d+|\(\d+,\d+\))?,(\d+),(\d+);//) {
778 ($start, $length) = ($2, $3);
779 &panic("no length?") unless $length;
780 $typeno = &typeno($1) if $1;
781 }
782 elsif (s/^((\d+|\(\d+,\d+\))(=[*f](\d+|\(\d+,\d+\)))+),(\d+),(\d+);//) {
783 ($pdecl, $start, $length) = ($1,$5,$6);
784 &pdecl($pdecl);
785 }
786 elsif (s/(\d+)=([us])(\d+|\(\d+,\d+\))//) { # the dratted anon struct
787 ($typeno, $sou) = ($1, $2);
788 $typeno = &typeno($typeno);
789 if (defined($type[$typeno])) {
790 warn "now how did we get type $1 in $fieldname of $line?";
791 } else {
792 print "anon type $typeno is $prefix.$fieldname\n" if $debug;
793 $type[$typeno] = "$prefix.$fieldname" unless defined $type[$typeno];
794 };
795 local($name) = "$prefix.$fieldname";
796 &sou($name,$sou);
797 print "anon ".($isastruct{$name}) ? "struct":"union"." for $prefix.$fieldname\n" if $debug;
798 $type[$typeno] = "$prefix.$fieldname";
799 $_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
800 $start = $start{$name};
801 $length = $sizeof{$name};
802 }
803 else {
804 warn "can't grok stab for $name ($_) in line $line ";
805 next STAB;
806 }
807
808 &panic("no length for $prefix.$fieldname") unless $length;
809 $struct{$name} .= join(',', $fieldname, $typeno, $scripts, $start, $length) . ';';
810 }
811 if (s/;\d*,(\d+),(\d+);//) {
812 local($start, $size) = ($1, $2);
813 $sizeof{$prefix} = $size;
814 print "start of $prefix is $start, size of $sizeof{$prefix}\n" if $debug;
815 $start{$prefix} = $start;
816 }
817 $_;
818}
819
820sub edecl {
821 s/;$//;
822 $enum{$name} = $_;
823 $_ = '';
824}
825
826sub resolve_types {
827 local($sou);
828 for $i (0 .. $#type) {
829 next unless defined $type[$i];
830 $_ = $type[$i];
831 unless (/\d/) {
832 print "type[$i] $type[$i]\n" if $debug;
833 next;
834 }
835 print "type[$i] $_ ==> " if $debug;
836 s/^(\d+)(\**)\&\*(\**)/"$2($3".&type($1) . ')()'/e;
837 s/^(\d+)\&/&type($1)/e;
838 s/^(\d+)/&type($1)/e;
839 s/(\*+)([^*]+)(\*+)/$1$3$2/;
840 s/\((\*+)(\w+)(\*+)\)/$3($1$2)/;
841 s/^(\d+)([\*\[].*)/&type($1).$2/e;
842 #s/(\d+)(\*|(\[[\[\]\d\*]+]\])+)/&type($1).$2/ge;
843 $type[$i] = $_;
844 print "$_\n" if $debug;
845 }
846}
847sub type { &psou($type[$_[0]] || "<UNDEFINED>"); }
848
849sub adjust_start_addrs {
850 for (sort keys %start) {
851 ($basename = $_) =~ s/\.[^.]+$//;
852 $start{$_} += $start{$basename};
853 print "start: $_ @ $start{$_}\n" if $debug;
854 }
855}
856
857sub sou {
858 local($what, $_) = @_;
859 /u/ && $isaunion{$what}++;
860 /s/ && $isastruct{$what}++;
861}
862
863sub psou {
864 local($what) = @_;
865 local($prefix) = '';
866 if ($isaunion{$what}) {
867 $prefix = 'union ';
868 } elsif ($isastruct{$what}) {
869 $prefix = 'struct ';
870 }
871 $prefix . $what;
872}
873
874sub scrunch {
875 local($_) = @_;
876
877 study;
878
879 s/\$//g;
880 s/ / /g;
881 1 while s/(\w) \1/$1$1/g;
882
883 # i wanna say this, but perl resists my efforts:
884 # s/(\w)(\1+)/$2 . length($1)/ge;
885
886 &quick_scrunch;
887
888 s/ $//;
889
890 $_;
891}
892
893sub buildscrunchlist {
894 $scrunch_code = "sub quick_scrunch {\n";
895 for (values %intrinsics) {
896 $scrunch_code .= "\ts/($_{2,})/'$_' . length(\$1)/ge;\n";
897 }
898 $scrunch_code .= "}\n";
899 print "$scrunch_code" if $debug;
900 eval $scrunch_code;
901 &panic("can't eval scrunch_code $@ \nscrunch_code") if $@;
902}
903
904sub fetch_template {
905 local($mytype) = @_;
906 local($fmt);
907 local($count) = 1;
908
909 &panic("why do you care?") unless $perl;
910
911 if ($mytype =~ s/(\[\d+\])+$//) {
912 $count .= $1;
913 }
914
915 if ($mytype =~ /\*/) {
916 $fmt = $template{'pointer'};
917 }
918 elsif (defined $template{$mytype}) {
919 $fmt = $template{$mytype};
920 }
921 elsif (defined $struct{$mytype}) {
922 if (!defined $template{&psou($mytype)}) {
923 &build_template($mytype) unless $mytype eq $name;
924 }
925 elsif ($template{&psou($mytype)} !~ /\$$/) {
926 #warn "incomplete template for $mytype\n";
927 }
928 $fmt = $template{&psou($mytype)} || '?';
929 }
930 else {
931 warn "unknown fmt for $mytype\n";
932 $fmt = '?';
933 }
934
935 $fmt x $count . ' ';
936}
937
938sub compute_intrinsics {
939 local($TMP) = "/tmp/c2ph-i.$$.c";
940 open (TMP, ">$TMP") || die "can't open $TMP: $!";
941 select(TMP);
942
943 print STDERR "computing intrinsic sizes: " if $trace;
944
945 undef %intrinsics;
946
947 print <<'EOF';
948main() {
949 char *mask = "%d %s\n";
950EOF
951
952 for $type (@intrinsics) {
953 next if $type eq 'void';
954 print <<"EOF";
955 printf(mask,sizeof($type), "$type");
956EOF
957 }
958
959 print <<'EOF';
960 printf(mask,sizeof(char *), "pointer");
961 exit(0);
962}
963EOF
964 close TMP;
965
966 select(STDOUT);
967 open(PIPE, "cd /tmp && $CC $TMP && /tmp/a.out|");
968 while (<PIPE>) {
969 chop;
970 split(' ',$_,2);;
971 print "intrinsic $_[1] is size $_[0]\n" if $debug;
972 $sizeof{$_[1]} = $_[0];
973 $intrinsics{$_[1]} = $template{$_[0]};
974 }
975 close(PIPE) || die "couldn't read intrinsics!";
976 unlink($TMP, '/tmp/a.out');
977 print STDERR "done\n" if $trace;
978}
979
980sub scripts2count {
981 local($_) = @_;
982
983 s/^\[//;
984 s/\]$//;
985 s/\]\[/*/g;
986 $_ = eval;
987 &panic("$_: $@") if $@;
988 $_;
989}
990
991sub system {
992 print STDERR "@_\n" if $trace;
993 system @_;
994}
995
996sub build_template {
997 local($name) = @_;
998
999 &panic("already got a template for $name") if defined $template{$name};
1000
1001 local($build_templates) = 1;
1002
1003 local($lparen) = '(' x $build_recursed;
1004 local($rparen) = ')' x $build_recursed;
1005
1006 print STDERR "$lparen$name$rparen " if $trace;
1007 $build_recursed++;
1008 &pstruct($name,$name,0);
1009 print STDERR "TEMPLATE for $name is ", $template{&psou($name)}, "\n" if $debug;
1010 --$build_recursed;
1011}
1012
1013
1014sub panic {
1015
1016 select(STDERR);
1017
1018 print "\npanic: @_\n";
1019
1020 exit 1 if $] <= 4.003; # caller broken
1021
1022 local($i,$_);
1023 local($p,$f,$l,$s,$h,$a,@a,@sub);
1024 for ($i = 0; ($p,$f,$l,$s,$h,$w) = caller($i); $i++) {
1025 @a = @DB'args;
1026 for (@a) {
1027 if (/^StB\000/ && length($_) == length($_main{'_main'})) {
1028 $_ = sprintf("%s",$_);
1029 }
1030 else {
1031 s/'/\\'/g;
1032 s/([^\0]*)/'$1'/ unless /^-?[\d.]+$/;
1033 s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg;
1034 s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg;
1035 }
1036 }
1037 $w = $w ? '@ = ' : '$ = ';
1038 $a = $h ? '(' . join(', ', @a) . ')' : '';
1039 push(@sub, "$w&$s$a from file $f line $l\n");
1040 last if $signal;
1041 }
1042 for ($i=0; $i <= $#sub; $i++) {
1043 last if $signal;
1044 print $sub[$i];
1045 }
1046 exit 1;
1047}
1048
1049sub squishseq {
1050 local($num);
1051 local($last) = -1e8;
1052 local($string);
1053 local($seq) = '..';
1054
1055 while (defined($num = shift)) {
1056 if ($num == ($last + 1)) {
1057 $string .= $seq unless $inseq++;
1058 $last = $num;
1059 next;
1060 } elsif ($inseq) {
1061 $string .= $last unless $last == -1e8;
1062 }
1063
1064 $string .= ',' if defined $string;
1065 $string .= $num;
1066 $last = $num;
1067 $inseq = 0;
1068 }
1069 $string .= $last if $inseq && $last != -e18;
1070 $string;
1071}