This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Fix bug #24108: Goto +foo broken
[perl5.git] / utils / c2ph.PL
... / ...
CommitLineData
1#!/usr/local/bin/perl
2
3use Config;
4use File::Basename qw(&basename &dirname);
5use Cwd;
6use subs qw(link);
7
8sub link { # This is a cut-down version of installperl:link().
9 my($from,$to) = @_;
10 my($success) = 0;
11
12 eval {
13 CORE::link($from, $to)
14 ? $success++
15 : ($from =~ m#^/afs/# || $to =~ m#^/afs/#)
16 ? die "AFS" # okay inside eval {}
17 : die "Couldn't link $from to $to: $!\n";
18 };
19 if ($@) {
20 warn $@;
21 require File::Copy;
22 File::Copy::copy($from, $to)
23 ? $success++
24 : warn "Couldn't copy $from to $to: $!\n";
25 }
26 $success;
27}
28
29# List explicitly here the variables you want Configure to
30# generate. Metaconfig only looks for shell variables, so you
31# have to mention them as if they were shell variables, not
32# %Config entries. Thus you write
33# $startperl
34# to ensure Configure will look for $Config{startperl}.
35
36# This forces PL files to create target in same directory as PL file.
37# This is so that make depend always knows where to find PL derivatives.
38$origdir = cwd;
39chdir dirname($0);
40$file = basename($0, '.PL');
41$file .= '.com' if $^O eq 'VMS';
42
43open OUT,">$file" or die "Can't create $file: $!";
44
45print "Extracting $file (with variable substitutions)\n";
46
47# In this section, perl variables will be expanded during extraction.
48# You can use $Config{...} to use Configure variables.
49
50print OUT <<"!GROK!THIS!";
51$Config{startperl}
52 eval 'exec $Config{perlpath} -S \$0 \${1+"\$@"}'
53 if \$running_under_some_shell;
54!GROK!THIS!
55
56# In the following, perl variables are not expanded during extraction.
57
58print OUT <<'!NO!SUBS!';
59#
60#
61# c2ph (aka pstruct)
62# Tom Christiansen, <tchrist@convex.com>
63#
64# As pstruct, dump C structures as generated from 'cc -g -S' stabs.
65# As c2ph, do this PLUS generate perl code for getting at the structures.
66#
67# See the usage message for more. If this isn't enough, read the code.
68#
69
70=head1 NAME
71
72c2ph, pstruct - Dump C structures as generated from C<cc -g -S> stabs
73
74=head1 SYNOPSIS
75
76 c2ph [-dpnP] [var=val] [files ...]
77
78=head2 OPTIONS
79
80 Options:
81
82 -w wide; short for: type_width=45 member_width=35 offset_width=8
83 -x hex; short for: offset_fmt=x offset_width=08 size_fmt=x size_width=04
84
85 -n do not generate perl code (default when invoked as pstruct)
86 -p generate perl code (default when invoked as c2ph)
87 -v generate perl code, with C decls as comments
88
89 -i do NOT recompute sizes for intrinsic datatypes
90 -a dump information on intrinsics also
91
92 -t trace execution
93 -d spew reams of debugging output
94
95 -slist give comma-separated list a structures to dump
96
97=head1 DESCRIPTION
98
99The following is the old c2ph.doc documentation by Tom Christiansen
100<tchrist@perl.com>
101Date: 25 Jul 91 08:10:21 GMT
102
103Once upon a time, I wrote a program called pstruct. It was a perl
104program that tried to parse out C structures and display their member
105offsets for you. This was especially useful for people looking at
106binary dumps or poking around the kernel.
107
108Pstruct was not a pretty program. Neither was it particularly robust.
109The problem, you see, was that the C compiler was much better at parsing
110C than I could ever hope to be.
111
112So I got smart: I decided to be lazy and let the C compiler parse the C,
113which would spit out debugger stabs for me to read. These were much
114easier to parse. It's still not a pretty program, but at least it's more
115robust.
116
117Pstruct takes any .c or .h files, or preferably .s ones, since that's
118the format it is going to massage them into anyway, and spits out
119listings like this:
120
121 struct tty {
122 int tty.t_locker 000 4
123 int tty.t_mutex_index 004 4
124 struct tty * tty.t_tp_virt 008 4
125 struct clist tty.t_rawq 00c 20
126 int tty.t_rawq.c_cc 00c 4
127 int tty.t_rawq.c_cmax 010 4
128 int tty.t_rawq.c_cfx 014 4
129 int tty.t_rawq.c_clx 018 4
130 struct tty * tty.t_rawq.c_tp_cpu 01c 4
131 struct tty * tty.t_rawq.c_tp_iop 020 4
132 unsigned char * tty.t_rawq.c_buf_cpu 024 4
133 unsigned char * tty.t_rawq.c_buf_iop 028 4
134 struct clist tty.t_canq 02c 20
135 int tty.t_canq.c_cc 02c 4
136 int tty.t_canq.c_cmax 030 4
137 int tty.t_canq.c_cfx 034 4
138 int tty.t_canq.c_clx 038 4
139 struct tty * tty.t_canq.c_tp_cpu 03c 4
140 struct tty * tty.t_canq.c_tp_iop 040 4
141 unsigned char * tty.t_canq.c_buf_cpu 044 4
142 unsigned char * tty.t_canq.c_buf_iop 048 4
143 struct clist tty.t_outq 04c 20
144 int tty.t_outq.c_cc 04c 4
145 int tty.t_outq.c_cmax 050 4
146 int tty.t_outq.c_cfx 054 4
147 int tty.t_outq.c_clx 058 4
148 struct tty * tty.t_outq.c_tp_cpu 05c 4
149 struct tty * tty.t_outq.c_tp_iop 060 4
150 unsigned char * tty.t_outq.c_buf_cpu 064 4
151 unsigned char * tty.t_outq.c_buf_iop 068 4
152 (*int)() tty.t_oproc_cpu 06c 4
153 (*int)() tty.t_oproc_iop 070 4
154 (*int)() tty.t_stopproc_cpu 074 4
155 (*int)() tty.t_stopproc_iop 078 4
156 struct thread * tty.t_rsel 07c 4
157
158etc.
159
160
161Actually, this was generated by a particular set of options. You can control
162the formatting of each column, whether you prefer wide or fat, hex or decimal,
163leading zeroes or whatever.
164
165All you need to be able to use this is a C compiler than generates
166BSD/GCC-style stabs. The B<-g> option on native BSD compilers and GCC
167should get this for you.
168
169To learn more, just type a bogus option, like B<-\?>, and a long usage message
170will be provided. There are a fair number of possibilities.
171
172If you're only a C programmer, than this is the end of the message for you.
173You can quit right now, and if you care to, save off the source and run it
174when you feel like it. Or not.
175
176
177
178But if you're a perl programmer, then for you I have something much more
179wondrous than just a structure offset printer.
180
181You see, if you call pstruct by its other incybernation, c2ph, you have a code
182generator that translates C code into perl code! Well, structure and union
183declarations at least, but that's quite a bit.
184
185Prior to this point, anyone programming in perl who wanted to interact
186with C programs, like the kernel, was forced to guess the layouts of
187the C structures, and then hardwire these into his program. Of course,
188when you took your wonderfully crafted program to a system where the
189sgtty structure was laid out differently, your program broke. Which is
190a shame.
191
192We've had Larry's h2ph translator, which helped, but that only works on
193cpp symbols, not real C, which was also very much needed. What I offer
194you is a symbolic way of getting at all the C structures. I've couched
195them in terms of packages and functions. Consider the following program:
196
197 #!/usr/local/bin/perl
198
199 require 'syscall.ph';
200 require 'sys/time.ph';
201 require 'sys/resource.ph';
202
203 $ru = "\0" x &rusage'sizeof();
204
205 syscall(&SYS_getrusage, &RUSAGE_SELF, $ru) && die "getrusage: $!";
206
207 @ru = unpack($t = &rusage'typedef(), $ru);
208
209 $utime = $ru[ &rusage'ru_utime + &timeval'tv_sec ]
210 + ($ru[ &rusage'ru_utime + &timeval'tv_usec ]) / 1e6;
211
212 $stime = $ru[ &rusage'ru_stime + &timeval'tv_sec ]
213 + ($ru[ &rusage'ru_stime + &timeval'tv_usec ]) / 1e6;
214
215 printf "you have used %8.3fs+%8.3fu seconds.\n", $utime, $stime;
216
217
218As you see, the name of the package is the name of the structure. Regular
219fields are just their own names. Plus the following accessor functions are
220provided for your convenience:
221
222 struct This takes no arguments, and is merely the number of first-level
223 elements in the structure. You would use this for indexing
224 into arrays of structures, perhaps like this
225
226
227 $usec = $u[ &user'u_utimer
228 + (&ITIMER_VIRTUAL * &itimerval'struct)
229 + &itimerval'it_value
230 + &timeval'tv_usec
231 ];
232
233 sizeof Returns the bytes in the structure, or the member if
234 you pass it an argument, such as
235
236 &rusage'sizeof(&rusage'ru_utime)
237
238 typedef This is the perl format definition for passing to pack and
239 unpack. If you ask for the typedef of a nothing, you get
240 the whole structure, otherwise you get that of the member
241 you ask for. Padding is taken care of, as is the magic to
242 guarantee that a union is unpacked into all its aliases.
243 Bitfields are not quite yet supported however.
244
245 offsetof This function is the byte offset into the array of that
246 member. You may wish to use this for indexing directly
247 into the packed structure with vec() if you're too lazy
248 to unpack it.
249
250 typeof Not to be confused with the typedef accessor function, this
251 one returns the C type of that field. This would allow
252 you to print out a nice structured pretty print of some
253 structure without knoning anything about it beforehand.
254 No args to this one is a noop. Someday I'll post such
255 a thing to dump out your u structure for you.
256
257
258The way I see this being used is like basically this:
259
260 % h2ph <some_include_file.h > /usr/lib/perl/tmp.ph
261 % c2ph some_include_file.h >> /usr/lib/perl/tmp.ph
262 % install
263
264It's a little tricker with c2ph because you have to get the includes right.
265I can't know this for your system, but it's not usually too terribly difficult.
266
267The code isn't pretty as I mentioned -- I never thought it would be a 1000-
268line program when I started, or I might not have begun. :-) But I would have
269been less cavalier in how the parts of the program communicated with each
270other, etc. It might also have helped if I didn't have to divine the makeup
271of the stabs on the fly, and then account for micro differences between my
272compiler and gcc.
273
274Anyway, here it is. Should run on perl v4 or greater. Maybe less.
275
276
277 --tom
278
279=cut
280
281$RCSID = '$Id: c2ph,v 1.7 95/10/28 10:41:47 tchrist Exp Locker: tchrist $';
282
283
284######################################################################
285
286# some handy data definitions. many of these can be reset later.
287
288$bitorder = 'b'; # ascending; set to B for descending bit fields
289
290%intrinsics =
291%template = (
292 'char', 'c',
293 'unsigned char', 'C',
294 'short', 's',
295 'short int', 's',
296 'unsigned short', 'S',
297 'unsigned short int', 'S',
298 'short unsigned int', 'S',
299 'int', 'i',
300 'unsigned int', 'I',
301 'long', 'l',
302 'long int', 'l',
303 'unsigned long', 'L',
304 'unsigned long', 'L',
305 'long unsigned int', 'L',
306 'unsigned long int', 'L',
307 'long long', 'q',
308 'long long int', 'q',
309 'unsigned long long', 'Q',
310 'unsigned long long int', 'Q',
311 'float', 'f',
312 'double', 'd',
313 'pointer', 'p',
314 'null', 'x',
315 'neganull', 'X',
316 'bit', $bitorder,
317);
318
319&buildscrunchlist;
320delete $intrinsics{'neganull'};
321delete $intrinsics{'bit'};
322delete $intrinsics{'null'};
323
324# use -s to recompute sizes
325%sizeof = (
326 'char', '1',
327 'unsigned char', '1',
328 'short', '2',
329 'short int', '2',
330 'unsigned short', '2',
331 'unsigned short int', '2',
332 'short unsigned int', '2',
333 'int', '4',
334 'unsigned int', '4',
335 'long', '4',
336 'long int', '4',
337 'unsigned long', '4',
338 'unsigned long int', '4',
339 'long unsigned int', '4',
340 'long long', '8',
341 'long long int', '8',
342 'unsigned long long', '8',
343 'unsigned long long int', '8',
344 'float', '4',
345 'double', '8',
346 'pointer', '4',
347);
348
349($type_width, $member_width, $offset_width, $size_width) = (20, 20, 6, 5);
350
351($offset_fmt, $size_fmt) = ('d', 'd');
352
353$indent = 2;
354
355$CC = 'cc';
356!NO!SUBS!
357
358if (($Config{gccversion} || '') =~ /^(\d+)\.(\d+)/
359 and ($1 > 3 or ($1 == 3 and $2 >= 2))) {
360 print OUT q/$CFLAGS = '-gstabs -S';/;
361} else {
362 print OUT q/$CFLAGS = '-g -S';/;
363}
364
365print OUT <<'!NO!SUBS!';
366
367$DEFINES = '';
368
369$perl++ if $0 =~ m#/?c2ph$#;
370
371require 'getopts.pl';
372
373use File::Temp 'tempdir';
374
375eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;
376
377&Getopts('aixdpvtnws:') || &usage(0);
378
379$opt_d && $debug++;
380$opt_t && $trace++;
381$opt_p && $perl++;
382$opt_v && $verbose++;
383$opt_n && ($perl = 0);
384
385if ($opt_w) {
386 ($type_width, $member_width, $offset_width) = (45, 35, 8);
387}
388if ($opt_x) {
389 ($offset_fmt, $offset_width, $size_fmt, $size_width) = ( 'x', '08', 'x', 04 );
390}
391
392eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;
393
394sub PLUMBER {
395 select(STDERR);
396 print "oops, apperent pager foulup\n";
397 $isatty++;
398 &usage(1);
399}
400
401sub usage {
402 local($oops) = @_;
403 unless (-t STDOUT) {
404 select(STDERR);
405 } elsif (!$oops) {
406 $isatty++;
407 $| = 1;
408 print "hit <RETURN> for further explanation: ";
409 <STDIN>;
410 open (PIPE, "|". ($ENV{PAGER} || 'more'));
411 $SIG{PIPE} = PLUMBER;
412 select(PIPE);
413 }
414
415 print "usage: $0 [-dpnP] [var=val] [files ...]\n";
416
417 exit unless $isatty;
418
419 print <<EOF;
420
421Options:
422
423-w wide; short for: type_width=45 member_width=35 offset_width=8
424-x hex; short for: offset_fmt=x offset_width=08 size_fmt=x size_width=04
425
426-n do not generate perl code (default when invoked as pstruct)
427-p generate perl code (default when invoked as c2ph)
428-v generate perl code, with C decls as comments
429
430-i do NOT recompute sizes for intrinsic datatypes
431-a dump information on intrinsics also
432
433-t trace execution
434-d spew reams of debugging output
435
436-slist give comma-separated list a structures to dump
437
438
439Var Name Default Value Meaning
440
441EOF
442
443 &defvar('CC', 'which_compiler to call');
444 &defvar('CFLAGS', 'how to generate *.s files with stabs');
445 &defvar('DEFINES','any extra cflags or cpp defines, like -I, -D, -U');
446
447 print "\n";
448
449 &defvar('type_width', 'width of type field (column 1)');
450 &defvar('member_width', 'width of member field (column 2)');
451 &defvar('offset_width', 'width of offset field (column 3)');
452 &defvar('size_width', 'width of size field (column 4)');
453
454 print "\n";
455
456 &defvar('offset_fmt', 'sprintf format type for offset');
457 &defvar('size_fmt', 'sprintf format type for size');
458
459 print "\n";
460
461 &defvar('indent', 'how far to indent each nesting level');
462
463 print <<'EOF';
464
465 If any *.[ch] files are given, these will be catted together into
466 a temporary *.c file and sent through:
467 $CC $CFLAGS $DEFINES
468 and the resulting *.s groped for stab information. If no files are
469 supplied, then stdin is read directly with the assumption that it
470 contains stab information. All other liens will be ignored. At
471 most one *.s file should be supplied.
472
473EOF
474 close PIPE;
475 exit 1;
476}
477
478sub defvar {
479 local($var, $msg) = @_;
480 printf "%-16s%-15s %s\n", $var, eval "\$$var", $msg;
481}
482
483$recurse = 1;
484
485if (@ARGV) {
486 if (grep(!/\.[csh]$/,@ARGV)) {
487 warn "Only *.[csh] files expected!\n";
488 &usage;
489 }
490 elsif (grep(/\.s$/,@ARGV)) {
491 if (@ARGV > 1) {
492 warn "Only one *.s file allowed!\n";
493 &usage;
494 }
495 }
496 elsif (@ARGV == 1 && $ARGV[0] =~ /\.c$/) {
497 local($dir, $file) = $ARGV[0] =~ m#(.*/)?(.*)$#;
498 $chdir = "cd $dir; " if $dir;
499 &system("$chdir$CC $CFLAGS $DEFINES $file") && exit 1;
500 $ARGV[0] =~ s/\.c$/.s/;
501 }
502 else {
503 $TMPDIR = tempdir(CLEANUP => 1);
504 $TMP = "$TMPDIR/c2ph.$$.c";
505 &system("cat @ARGV > $TMP") && exit 1;
506 &system("cd $TMPDIR; $CC $CFLAGS $DEFINES $TMP") && exit 1;
507 unlink $TMP;
508 $TMP =~ s/\.c$/.s/;
509 @ARGV = ($TMP);
510 }
511}
512
513if ($opt_s) {
514 for (split(/[\s,]+/, $opt_s)) {
515 $interested{$_}++;
516 }
517}
518
519
520$| = 1 if $debug;
521
522main: {
523
524 if ($trace) {
525 if (-t && !@ARGV) {
526 print STDERR "reading from your keyboard: ";
527 } else {
528 print STDERR "reading from " . (@ARGV ? "@ARGV" : "<STDIN>").": ";
529 }
530 }
531
532STAB: while (<>) {
533 if ($trace && !($. % 10)) {
534 $lineno = $..'';
535 print STDERR $lineno, "\b" x length($lineno);
536 }
537 next unless /^\s*\.stabs\s+/;
538 $line = $_;
539 s/^\s*\.stabs\s+//;
540 if (s/\\\\"[d,]+$//) {
541 $saveline .= $line;
542 $savebar = $_;
543 next STAB;
544 }
545 if ($saveline) {
546 s/^"//;
547 $_ = $savebar . $_;
548 $line = $saveline;
549 }
550 &stab;
551 $savebar = $saveline = undef;
552 }
553 print STDERR "$.\n" if $trace;
554 unlink $TMP if $TMP;
555
556 &compute_intrinsics if $perl && !$opt_i;
557
558 print STDERR "resolving types\n" if $trace;
559
560 &resolve_types;
561 &adjust_start_addrs;
562
563 $sum = 2 + $type_width + $member_width;
564 $pmask1 = "%-${type_width}s %-${member_width}s";
565 $pmask2 = "%-${sum}s %${offset_width}${offset_fmt}%s %${size_width}${size_fmt}%s";
566
567
568
569 if ($perl) {
570 # resolve template -- should be in stab define order, but even this isn't enough.
571 print STDERR "\nbuilding type templates: " if $trace;
572 for $i (reverse 0..$#type) {
573 next unless defined($name = $type[$i]);
574 next unless defined $struct{$name};
575 ($iname = $name) =~ s/\..*//;
576 $build_recursed = 0;
577 &build_template($name) unless defined $template{&psou($name)} ||
578 $opt_s && !$interested{$iname};
579 }
580 print STDERR "\n\n" if $trace;
581 }
582
583 print STDERR "dumping structs: " if $trace;
584
585 local($iam);
586
587
588
589 foreach $name (sort keys %struct) {
590 ($iname = $name) =~ s/\..*//;
591 next if $opt_s && !$interested{$iname};
592 print STDERR "$name " if $trace;
593
594 undef @sizeof;
595 undef @typedef;
596 undef @offsetof;
597 undef @indices;
598 undef @typeof;
599 undef @fieldnames;
600
601 $mname = &munge($name);
602
603 $fname = &psou($name);
604
605 print "# " if $perl && $verbose;
606 $pcode = '';
607 print "$fname {\n" if !$perl || $verbose;
608 $template{$fname} = &scrunch($template{$fname}) if $perl;
609 &pstruct($name,$name,0);
610 print "# " if $perl && $verbose;
611 print "}\n" if !$perl || $verbose;
612 print "\n" if $perl && $verbose;
613
614 if ($perl) {
615 print "$pcode";
616
617 printf("\nsub %-32s { %4d; }\n\n", "${mname}'struct", $countof{$name});
618
619 print <<EOF;
620sub ${mname}'typedef {
621 local(\$${mname}'index) = shift;
622 defined \$${mname}'index
623 ? \$${mname}'typedef[\$${mname}'index]
624 : \$${mname}'typedef;
625}
626EOF
627
628 print <<EOF;
629sub ${mname}'sizeof {
630 local(\$${mname}'index) = shift;
631 defined \$${mname}'index
632 ? \$${mname}'sizeof[\$${mname}'index]
633 : \$${mname}'sizeof;
634}
635EOF
636
637 print <<EOF;
638sub ${mname}'offsetof {
639 local(\$${mname}'index) = shift;
640 defined \$${mname}index
641 ? \$${mname}'offsetof[\$${mname}'index]
642 : \$${mname}'sizeof;
643}
644EOF
645
646 print <<EOF;
647sub ${mname}'typeof {
648 local(\$${mname}'index) = shift;
649 defined \$${mname}index
650 ? \$${mname}'typeof[\$${mname}'index]
651 : '$name';
652}
653EOF
654
655 print <<EOF;
656sub ${mname}'fieldnames {
657 \@${mname}'fieldnames;
658}
659EOF
660
661 $iam = ($isastruct{$name} && 's') || ($isaunion{$name} && 'u');
662
663 print <<EOF;
664sub ${mname}'isastruct {
665 '$iam';
666}
667EOF
668
669 print "\$${mname}'typedef = '" . &scrunch($template{$fname})
670 . "';\n";
671
672 print "\$${mname}'sizeof = $sizeof{$name};\n\n";
673
674
675 print "\@${mname}'indices = (", &squishseq(@indices), ");\n";
676
677 print "\n";
678
679 print "\@${mname}'typedef[\@${mname}'indices] = (",
680 join("\n\t", '', @typedef), "\n );\n\n";
681 print "\@${mname}'sizeof[\@${mname}'indices] = (",
682 join("\n\t", '', @sizeof), "\n );\n\n";
683 print "\@${mname}'offsetof[\@${mname}'indices] = (",
684 join("\n\t", '', @offsetof), "\n );\n\n";
685 print "\@${mname}'typeof[\@${mname}'indices] = (",
686 join("\n\t", '', @typeof), "\n );\n\n";
687 print "\@${mname}'fieldnames[\@${mname}'indices] = (",
688 join("\n\t", '', @fieldnames), "\n );\n\n";
689
690 $template_printed{$fname}++;
691 $size_printed{$fname}++;
692 }
693 print "\n";
694 }
695
696 print STDERR "\n" if $trace;
697
698 unless ($perl && $opt_a) {
699 print "\n1;\n" if $perl;
700 exit;
701 }
702
703
704
705 foreach $name (sort bysizevalue keys %intrinsics) {
706 next if $size_printed{$name};
707 print '$',&munge($name),"'sizeof = ", $sizeof{$name}, ";\n";
708 }
709
710 print "\n";
711
712 sub bysizevalue { $sizeof{$a} <=> $sizeof{$b}; }
713
714
715 foreach $name (sort keys %intrinsics) {
716 print '$',&munge($name),"'typedef = '", $template{$name}, "';\n";
717 }
718
719 print "\n1;\n" if $perl;
720
721 exit;
722}
723
724########################################################################################
725
726
727sub stab {
728 next unless $continued || /:[\$\w]+(\(\d+,\d+\))?=[\*\$\w]+/; # (\d+,\d+) is for sun
729 s/"// || next;
730 s/",([x\d]+),([x\d]+),([x\d]+),.*// || next;
731
732 next if /^\s*$/;
733
734 $size = $3 if $3;
735 $_ = $continued . $_ if length($continued);
736 if (s/\\\\$//) {
737 # if last 2 chars of string are '\\' then stab is continued
738 # in next stab entry
739 chop;
740 $continued = $_;
741 next;
742 }
743 $continued = '';
744
745
746 $line = $_;
747
748 if (($name, $pdecl) = /^([\$ \w]+):[tT]((\d+)(=[rufs*](\d+))+)$/) {
749 print "$name is a typedef for some funky pointers: $pdecl\n" if $debug;
750 &pdecl($pdecl);
751 next;
752 }
753
754
755
756 if (/(([ \w]+):t(\d+|\(\d+,\d+\)))=r?(\d+|\(\d+,\d+\))(;\d+;\d+;)?/) {
757 local($ident) = $2;
758 push(@intrinsics, $ident);
759 $typeno = &typeno($3);
760 $type[$typeno] = $ident;
761 print STDERR "intrinsic $ident in new type $typeno\n" if $debug;
762 next;
763 }
764
765 if (($name, $typeordef, $typeno, $extra, $struct, $_)
766 = /^([\$ \w]+):([ustT])(\d+|\(\d+,\d+\))(=[rufs*](\d+))?(.*)$/)
767 {
768 $typeno = &typeno($typeno); # sun foolery
769 }
770 elsif (/^[\$\w]+:/) {
771 next; # variable
772 }
773 else {
774 warn "can't grok stab: <$_> in: $line " if $_;
775 next;
776 }
777
778 #warn "got size $size for $name\n";
779 $sizeof{$name} = $size if $size;
780
781 s/;[-\d]*;[-\d]*;$//; # we don't care about ranges
782
783 $typenos{$name} = $typeno;
784
785 unless (defined $type[$typeno]) {
786 &panic("type 0??") unless $typeno;
787 $type[$typeno] = $name unless defined $type[$typeno];
788 printf "new type $typeno is $name" if $debug;
789 if ($extra =~ /\*/ && defined $type[$struct]) {
790 print ", a typedef for a pointer to " , $type[$struct] if $debug;
791 }
792 } else {
793 printf "%s is type %d", $name, $typeno if $debug;
794 print ", a typedef for " , $type[$typeno] if $debug;
795 }
796 print "\n" if $debug;
797 #next unless $extra =~ /[su*]/;
798
799 #$type[$struct] = $name;
800
801 if ($extra =~ /[us*]/) {
802 &sou($name, $extra);
803 $_ = &sdecl($name, $_, 0);
804 }
805 elsif (/^=ar/) {
806 print "it's a bare array typedef -- that's pretty sick\n" if $debug;
807 $_ = "$typeno$_";
808 $scripts = '';
809 $_ = &adecl($_,1);
810
811 }
812 elsif (s/((\w+):t(\d+|\(\d+,\d+\)))?=r?(;\d+;\d+;)?//) { # the ?'s are for gcc
813 push(@intrinsics, $2);
814 $typeno = &typeno($3);
815 $type[$typeno] = $2;
816 print STDERR "intrinsic $2 in new type $typeno\n" if $debug;
817 }
818 elsif (s/^=e//) { # blessed be thy compiler; mine won't do this
819 &edecl;
820 }
821 else {
822 warn "Funny remainder for $name on line $_ left in $line " if $_;
823 }
824}
825
826sub typeno { # sun thinks types are (0,27) instead of just 27
827 local($_) = @_;
828 s/\(\d+,(\d+)\)/$1/;
829 $_;
830}
831
832sub pstruct {
833 local($what,$prefix,$base) = @_;
834 local($field, $fieldname, $typeno, $count, $offset, $entry);
835 local($fieldtype);
836 local($type, $tname);
837 local($mytype, $mycount, $entry2);
838 local($struct_count) = 0;
839 local($pad, $revpad, $length, $prepad, $lastoffset, $lastlength, $fmt);
840 local($bits,$bytes);
841 local($template);
842
843
844 local($mname) = &munge($name);
845
846 sub munge {
847 local($_) = @_;
848 s/[\s\$\.]/_/g;
849 $_;
850 }
851
852 local($sname) = &psou($what);
853
854 $nesting++;
855
856 for $field (split(/;/, $struct{$what})) {
857 $pad = $prepad = 0;
858 $entry = '';
859 ($fieldname, $typeno, $count, $offset, $length) = split(/,/, $field);
860
861 $type = $type[$typeno];
862
863 $type =~ /([^[]*)(\[.*\])?/;
864 $mytype = $1;
865 $count .= $2;
866 $fieldtype = &psou($mytype);
867
868 local($fname) = &psou($name);
869
870 if ($build_templates) {
871
872 $pad = ($offset - ($lastoffset + $lastlength))/8
873 if defined $lastoffset;
874
875 if (! $finished_template{$sname}) {
876 if ($isaunion{$what}) {
877 $template{$sname} .= 'X' x $revpad . ' ' if $revpad;
878 } else {
879 $template{$sname} .= 'x' x $pad . ' ' if $pad;
880 }
881 }
882
883 $template = &fetch_template($type);
884 &repeat_template($template,$count);
885
886 if (! $finished_template{$sname}) {
887 $template{$sname} .= $template;
888 }
889
890 $revpad = $length/8 if $isaunion{$what};
891
892 ($lastoffset, $lastlength) = ($offset, $length);
893
894 } else {
895 print '# ' if $perl && $verbose;
896 $entry = sprintf($pmask1,
897 ' ' x ($nesting * $indent) . $fieldtype,
898 "$prefix.$fieldname" . $count);
899
900 $entry =~ s/(\*+)( )/$2$1/;
901
902 printf $pmask2,
903 $entry,
904 ($base+$offset)/8,
905 ($bits = ($base+$offset)%8) ? ".$bits" : " ",
906 $length/8,
907 ($bits = $length % 8) ? ".$bits": ""
908 if !$perl || $verbose;
909
910 if ($perl) {
911 $template = &fetch_template($type);
912 &repeat_template($template,$count);
913 }
914
915 if ($perl && $nesting == 1) {
916
917 push(@sizeof, int($length/8) .",\t# $fieldname");
918 push(@offsetof, int($offset/8) .",\t# $fieldname");
919 local($little) = &scrunch($template);
920 push(@typedef, "'$little', \t# $fieldname");
921 $type =~ s/(struct|union) //;
922 push(@typeof, "'$mytype" . ($count ? $count : '') .
923 "',\t# $fieldname");
924 push(@fieldnames, "'$fieldname',");
925 }
926
927 print ' ', ' ' x $indent x $nesting, $template
928 if $perl && $verbose;
929
930 print "\n" if !$perl || $verbose;
931
932 }
933 if ($perl) {
934 local($mycount) = defined $struct{$mytype} ? $countof{$mytype} : 1;
935 $mycount *= &scripts2count($count) if $count;
936 if ($nesting==1 && !$build_templates) {
937 $pcode .= sprintf("sub %-32s { %4d; }\n",
938 "${mname}'${fieldname}", $struct_count);
939 push(@indices, $struct_count);
940 }
941 $struct_count += $mycount;
942 }
943
944
945 &pstruct($type, "$prefix.$fieldname", $base+$offset)
946 if $recurse && defined $struct{$type};
947 }
948
949 $countof{$what} = $struct_count unless defined $countof{$whati};
950
951 $template{$sname} .= '$' if $build_templates;
952 $finished_template{$sname}++;
953
954 if ($build_templates && !defined $sizeof{$name}) {
955 local($fmt) = &scrunch($template{$sname});
956 print STDERR "no size for $name, punting with $fmt..." if $debug;
957 eval '$sizeof{$name} = length(pack($fmt, ()))';
958 if ($@) {
959 chop $@;
960 warn "couldn't get size for \$name: $@";
961 } else {
962 print STDERR $sizeof{$name}, "\n" if $debUg;
963 }
964 }
965
966 --$nesting;
967}
968
969
970sub psize {
971 local($me) = @_;
972 local($amstruct) = $struct{$me} ? 'struct ' : '';
973
974 print '$sizeof{\'', $amstruct, $me, '\'} = ';
975 printf "%d;\n", $sizeof{$me};
976}
977
978sub pdecl {
979 local($pdecl) = @_;
980 local(@pdecls);
981 local($tname);
982
983 warn "pdecl: $pdecl\n" if $debug;
984
985 $pdecl =~ s/\(\d+,(\d+)\)/$1/g;
986 $pdecl =~ s/\*//g;
987 @pdecls = split(/=/, $pdecl);
988 $typeno = $pdecls[0];
989 $tname = pop @pdecls;
990
991 if ($tname =~ s/^f//) { $tname = "$tname&"; }
992 #else { $tname = "$tname*"; }
993
994 for (reverse @pdecls) {
995 $tname .= s/^f// ? "&" : "*";
996 #$tname =~ s/^f(.*)/$1&/;
997 print "type[$_] is $tname\n" if $debug;
998 $type[$_] = $tname unless defined $type[$_];
999 }
1000}
1001
1002
1003
1004sub adecl {
1005 ($arraytype, $unknown, $lower, $upper) = ();
1006 #local($typeno);
1007 # global $typeno, @type
1008 local($_, $typedef) = @_;
1009
1010 while (s/^((\d+|\(\d+,\d+\))=)?ar(\d+|\(\d+,\d+\));//) {
1011 ($arraytype, $unknown) = ($2, $3);
1012 $arraytype = &typeno($arraytype);
1013 $unknown = &typeno($unknown);
1014 if (s/^(\d+);(\d+);//) {
1015 ($lower, $upper) = ($1, $2);
1016 $scripts .= '[' . ($upper+1) . ']';
1017 } else {
1018 warn "can't find array bounds: $_";
1019 }
1020 }
1021 if (s/^([(,)\d*f=]*),(\d+),(\d+);//) {
1022 ($start, $length) = ($2, $3);
1023 $whatis = $1;
1024 if ($whatis =~ /^(\d+|\(\d+,\d+\))=/) {
1025 $typeno = &typeno($1);
1026 &pdecl($whatis);
1027 } else {
1028 $typeno = &typeno($whatis);
1029 }
1030 } elsif (s/^(\d+)(=[*suf]\d*)//) {
1031 local($whatis) = $2;
1032
1033 if ($whatis =~ /[f*]/) {
1034 &pdecl($whatis);
1035 } elsif ($whatis =~ /[su]/) { #
1036 print "$prefix.$fieldname is an array$scripts anon structs; disgusting\n"
1037 if $debug;
1038 #$type[$typeno] = $name unless defined $type[$typeno];
1039 ##printf "new type $typeno is $name" if $debug;
1040 $typeno = $1;
1041 $type[$typeno] = "$prefix.$fieldname";
1042 local($name) = $type[$typeno];
1043 &sou($name, $whatis);
1044 $_ = &sdecl($name, $_, $start+$offset);
1045 1;
1046 $start = $start{$name};
1047 $offset = $sizeof{$name};
1048 $length = $offset;
1049 } else {
1050 warn "what's this? $whatis in $line ";
1051 }
1052 } elsif (/^\d+$/) {
1053 $typeno = $_;
1054 } else {
1055 warn "bad array stab: $_ in $line ";
1056 next STAB;
1057 }
1058 #local($wasdef) = defined($type[$typeno]) && $debug;
1059 #if ($typedef) {
1060 #print "redefining $type[$typeno] to " if $wasdef;
1061 #$type[$typeno] = "$whatis$scripts"; # unless defined $type[$typeno];
1062 #print "$type[$typeno]\n" if $wasdef;
1063 #} else {
1064 #$type[$arraytype] = $type[$typeno] unless defined $type[$arraytype];
1065 #}
1066 $type[$arraytype] = "$type[$typeno]$scripts" if defined $type[$typeno];
1067 print "type[$arraytype] is $type[$arraytype]\n" if $debug;
1068 print "$prefix.$fieldname is an array of $type[$arraytype]\n" if $debug;
1069 $_;
1070}
1071
1072
1073
1074sub sdecl {
1075 local($prefix, $_, $offset) = @_;
1076
1077 local($fieldname, $scripts, $type, $arraytype, $unknown,
1078 $whatis, $pdecl, $upper,$lower, $start,$length) = ();
1079 local($typeno,$sou);
1080
1081
1082SFIELD:
1083 while (/^([^;]+);/) {
1084 $scripts = '';
1085 warn "sdecl $_\n" if $debug;
1086 if (s/^([\$\w]+)://) {
1087 $fieldname = $1;
1088 } elsif (s/(\d+)=([us])(\d+|\(\d+,\d+\))//) { #
1089 $typeno = &typeno($1);
1090 $type[$typeno] = "$prefix.$fieldname";
1091 local($name) = "$prefix.$fieldname";
1092 &sou($name,$2);
1093 $_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
1094 $start = $start{$name};
1095 $offset += $sizeof{$name};
1096 #print "done with anon, start is $start, offset is $offset\n";
1097 #next SFIELD;
1098 } else {
1099 warn "weird field $_ of $line" if $debug;
1100 next STAB;
1101 #$fieldname = &gensym;
1102 #$_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
1103 }
1104
1105 if (/^(\d+|\(\d+,\d+\))=ar/) {
1106 $_ = &adecl($_);
1107 }
1108 elsif (s/^(\d+|\(\d+,\d+\))?,(\d+),(\d+);//) {
1109 ($start, $length) = ($2, $3);
1110 &panic("no length?") unless $length;
1111 $typeno = &typeno($1) if $1;
1112 }
1113 elsif (s/^(\d+)=xs\w+:,(\d+),(\d+);//) {
1114 ($start, $length) = ($2, $3);
1115 &panic("no length?") unless $length;
1116 $typeno = &typeno($1) if $1;
1117 }
1118 elsif (s/^((\d+|\(\d+,\d+\))(=[*f](\d+|\(\d+,\d+\)))+),(\d+),(\d+);//) {
1119 ($pdecl, $start, $length) = ($1,$5,$6);
1120 &pdecl($pdecl);
1121 }
1122 elsif (s/(\d+)=([us])(\d+|\(\d+,\d+\))//) { # the dratted anon struct
1123 ($typeno, $sou) = ($1, $2);
1124 $typeno = &typeno($typeno);
1125 if (defined($type[$typeno])) {
1126 warn "now how did we get type $1 in $fieldname of $line?";
1127 } else {
1128 print "anon type $typeno is $prefix.$fieldname\n" if $debug;
1129 $type[$typeno] = "$prefix.$fieldname" unless defined $type[$typeno];
1130 };
1131 local($name) = "$prefix.$fieldname";
1132 &sou($name,$sou);
1133 print "anon ".($isastruct{$name}) ? "struct":"union"." for $prefix.$fieldname\n" if $debug;
1134 $type[$typeno] = "$prefix.$fieldname";
1135 $_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
1136 $start = $start{$name};
1137 $length = $sizeof{$name};
1138 }
1139 else {
1140 warn "can't grok stab for $name ($_) in line $line ";
1141 next STAB;
1142 }
1143
1144 &panic("no length for $prefix.$fieldname") unless $length;
1145 $struct{$name} .= join(',', $fieldname, $typeno, $scripts, $start, $length) . ';';
1146 }
1147 if (s/;\d*,(\d+),(\d+);//) {
1148 local($start, $size) = ($1, $2);
1149 $sizeof{$prefix} = $size;
1150 print "start of $prefix is $start, size of $sizeof{$prefix}\n" if $debug;
1151 $start{$prefix} = $start;
1152 }
1153 $_;
1154}
1155
1156sub edecl {
1157 s/;$//;
1158 $enum{$name} = $_;
1159 $_ = '';
1160}
1161
1162sub resolve_types {
1163 local($sou);
1164 for $i (0 .. $#type) {
1165 next unless defined $type[$i];
1166 $_ = $type[$i];
1167 unless (/\d/) {
1168 print "type[$i] $type[$i]\n" if $debug;
1169 next;
1170 }
1171 print "type[$i] $_ ==> " if $debug;
1172 s/^(\d+)(\**)\&\*(\**)/"$2($3".&type($1) . ')()'/e;
1173 s/^(\d+)\&/&type($1)/e;
1174 s/^(\d+)/&type($1)/e;
1175 s/(\*+)([^*]+)(\*+)/$1$3$2/;
1176 s/\((\*+)(\w+)(\*+)\)/$3($1$2)/;
1177 s/^(\d+)([\*\[].*)/&type($1).$2/e;
1178 #s/(\d+)(\*|(\[[\[\]\d\*]+]\])+)/&type($1).$2/ge;
1179 $type[$i] = $_;
1180 print "$_\n" if $debug;
1181 }
1182}
1183sub type { &psou($type[$_[0]] || "<UNDEFINED>"); }
1184
1185sub adjust_start_addrs {
1186 for (sort keys %start) {
1187 ($basename = $_) =~ s/\.[^.]+$//;
1188 $start{$_} += $start{$basename};
1189 print "start: $_ @ $start{$_}\n" if $debug;
1190 }
1191}
1192
1193sub sou {
1194 local($what, $_) = @_;
1195 /u/ && $isaunion{$what}++;
1196 /s/ && $isastruct{$what}++;
1197}
1198
1199sub psou {
1200 local($what) = @_;
1201 local($prefix) = '';
1202 if ($isaunion{$what}) {
1203 $prefix = 'union ';
1204 } elsif ($isastruct{$what}) {
1205 $prefix = 'struct ';
1206 }
1207 $prefix . $what;
1208}
1209
1210sub scrunch {
1211 local($_) = @_;
1212
1213 return '' if $_ eq '';
1214
1215 study;
1216
1217 s/\$//g;
1218 s/ / /g;
1219 1 while s/(\w) \1/$1$1/g;
1220
1221 # i wanna say this, but perl resists my efforts:
1222 # s/(\w)(\1+)/$2 . length($1)/ge;
1223
1224 &quick_scrunch;
1225
1226 s/ $//;
1227
1228 $_;
1229}
1230
1231sub buildscrunchlist {
1232 $scrunch_code = "sub quick_scrunch {\n";
1233 for (values %intrinsics) {
1234 $scrunch_code .= "\ts/(${_}{2,})/'$_' . length(\$1)/ge;\n";
1235 }
1236 $scrunch_code .= "}\n";
1237 print "$scrunch_code" if $debug;
1238 eval $scrunch_code;
1239 &panic("can't eval scrunch_code $@ \nscrunch_code") if $@;
1240}
1241
1242sub fetch_template {
1243 local($mytype) = @_;
1244 local($fmt);
1245 local($count) = 1;
1246
1247 &panic("why do you care?") unless $perl;
1248
1249 if ($mytype =~ s/(\[\d+\])+$//) {
1250 $count .= $1;
1251 }
1252
1253 if ($mytype =~ /\*/) {
1254 $fmt = $template{'pointer'};
1255 }
1256 elsif (defined $template{$mytype}) {
1257 $fmt = $template{$mytype};
1258 }
1259 elsif (defined $struct{$mytype}) {
1260 if (!defined $template{&psou($mytype)}) {
1261 &build_template($mytype) unless $mytype eq $name;
1262 }
1263 elsif ($template{&psou($mytype)} !~ /\$$/) {
1264 #warn "incomplete template for $mytype\n";
1265 }
1266 $fmt = $template{&psou($mytype)} || '?';
1267 }
1268 else {
1269 warn "unknown fmt for $mytype\n";
1270 $fmt = '?';
1271 }
1272
1273 $fmt x $count . ' ';
1274}
1275
1276sub compute_intrinsics {
1277 $TMPDIR ||= tempdir(CLEANUP => 1);
1278 local($TMP) = "$TMPDIR/c2ph-i.$$.c";
1279 open (TMP, ">$TMP") || die "can't open $TMP: $!";
1280 select(TMP);
1281
1282 print STDERR "computing intrinsic sizes: " if $trace;
1283
1284 undef %intrinsics;
1285
1286 print <<'EOF';
1287main() {
1288 char *mask = "%d %s\n";
1289EOF
1290
1291 for $type (@intrinsics) {
1292 next if !$type || $type eq 'void' || $type =~ /complex/; # sun stuff
1293 print <<"EOF";
1294 printf(mask,sizeof($type), "$type");
1295EOF
1296 }
1297
1298 print <<'EOF';
1299 printf(mask,sizeof(char *), "pointer");
1300 exit(0);
1301}
1302EOF
1303 close TMP;
1304
1305 select(STDOUT);
1306 open(PIPE, "cd $TMPDIR && $CC $TMP && $TMPDIR/a.out|");
1307 while (<PIPE>) {
1308 chop;
1309 split(' ',$_,2);;
1310 print "intrinsic $_[1] is size $_[0]\n" if $debug;
1311 $sizeof{$_[1]} = $_[0];
1312 $intrinsics{$_[1]} = $template{$_[0]};
1313 }
1314 close(PIPE) || die "couldn't read intrinsics!";
1315 unlink($TMP, '$TMPDIR/a.out');
1316 print STDERR "done\n" if $trace;
1317}
1318
1319sub scripts2count {
1320 local($_) = @_;
1321
1322 s/^\[//;
1323 s/\]$//;
1324 s/\]\[/*/g;
1325 $_ = eval;
1326 &panic("$_: $@") if $@;
1327 $_;
1328}
1329
1330sub system {
1331 print STDERR "@_\n" if $trace;
1332 system @_;
1333}
1334
1335sub build_template {
1336 local($name) = @_;
1337
1338 &panic("already got a template for $name") if defined $template{$name};
1339
1340 local($build_templates) = 1;
1341
1342 local($lparen) = '(' x $build_recursed;
1343 local($rparen) = ')' x $build_recursed;
1344
1345 print STDERR "$lparen$name$rparen " if $trace;
1346 $build_recursed++;
1347 &pstruct($name,$name,0);
1348 print STDERR "TEMPLATE for $name is ", $template{&psou($name)}, "\n" if $debug;
1349 --$build_recursed;
1350}
1351
1352
1353sub panic {
1354
1355 select(STDERR);
1356
1357 print "\npanic: @_\n";
1358
1359 exit 1 if $] <= 4.003; # caller broken
1360
1361 local($i,$_);
1362 local($p,$f,$l,$s,$h,$a,@a,@sub);
1363 for ($i = 0; ($p,$f,$l,$s,$h,$w) = caller($i); $i++) {
1364 @a = @DB'args;
1365 for (@a) {
1366 if (/^StB\000/ && length($_) == length($_main{'_main'})) {
1367 $_ = sprintf("%s",$_);
1368 }
1369 else {
1370 s/'/\\'/g;
1371 s/([^\0]*)/'$1'/ unless /^-?[\d.]+$/;
1372 s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg;
1373 s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg;
1374 }
1375 }
1376 $w = $w ? '@ = ' : '$ = ';
1377 $a = $h ? '(' . join(', ', @a) . ')' : '';
1378 push(@sub, "$w&$s$a from file $f line $l\n");
1379 last if $signal;
1380 }
1381 for ($i=0; $i <= $#sub; $i++) {
1382 last if $signal;
1383 print $sub[$i];
1384 }
1385 exit 1;
1386}
1387
1388sub squishseq {
1389 local($num);
1390 local($last) = -1e8;
1391 local($string);
1392 local($seq) = '..';
1393
1394 while (defined($num = shift)) {
1395 if ($num == ($last + 1)) {
1396 $string .= $seq unless $inseq++;
1397 $last = $num;
1398 next;
1399 } elsif ($inseq) {
1400 $string .= $last unless $last == -1e8;
1401 }
1402
1403 $string .= ',' if defined $string;
1404 $string .= $num;
1405 $last = $num;
1406 $inseq = 0;
1407 }
1408 $string .= $last if $inseq && $last != -e18;
1409 $string;
1410}
1411
1412sub repeat_template {
1413 # local($template, $scripts) = @_; have to change caller's values
1414
1415 if ( $_[1] ) {
1416 local($ncount) = &scripts2count($_[1]);
1417 if ($_[0] =~ /^\s*c\s*$/i) {
1418 $_[0] = "A$ncount ";
1419 $_[1] = '';
1420 } else {
1421 $_[0] = $template x $ncount;
1422 }
1423 }
1424}
1425!NO!SUBS!
1426
1427close OUT or die "Can't close $file: $!";
1428chmod 0755, $file or die "Can't reset permissions for $file: $!\n";
1429unlink 'pstruct';
1430print "Linking c2ph to pstruct.\n";
1431if (defined $Config{d_link}) {
1432 link 'c2ph', 'pstruct';
1433} else {
1434 unshift @INC, '../lib';
1435 require File::Copy;
1436 File::Copy::syscopy('c2ph', 'pstruct');
1437}
1438exec("$Config{'eunicefix'} $file") if $Config{'eunicefix'} ne ':';
1439chdir $origdir;