This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Move "DEVEL####" marker to the 'perl -v' output.
[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
283use File::Temp;
284
285######################################################################
286
287# some handy data definitions. many of these can be reset later.
288
289$bitorder = 'b'; # ascending; set to B for descending bit fields
290
291%intrinsics =
292%template = (
293 'char', 'c',
294 'unsigned char', 'C',
295 'short', 's',
296 'short int', 's',
297 'unsigned short', 'S',
298 'unsigned short int', 'S',
299 'short unsigned int', 'S',
300 'int', 'i',
301 'unsigned int', 'I',
302 'long', 'l',
303 'long int', 'l',
304 'unsigned long', 'L',
305 'unsigned long', 'L',
306 'long unsigned int', 'L',
307 'unsigned long int', 'L',
308 'long long', 'q',
309 'long long int', 'q',
310 'unsigned long long', 'Q',
311 'unsigned long long int', 'Q',
312 'float', 'f',
313 'double', 'd',
314 'pointer', 'p',
315 'null', 'x',
316 'neganull', 'X',
317 'bit', $bitorder,
318);
319
320&buildscrunchlist;
321delete $intrinsics{'neganull'};
322delete $intrinsics{'bit'};
323delete $intrinsics{'null'};
324
325# use -s to recompute sizes
326%sizeof = (
327 'char', '1',
328 'unsigned char', '1',
329 'short', '2',
330 'short int', '2',
331 'unsigned short', '2',
332 'unsigned short int', '2',
333 'short unsigned int', '2',
334 'int', '4',
335 'unsigned int', '4',
336 'long', '4',
337 'long int', '4',
338 'unsigned long', '4',
339 'unsigned long int', '4',
340 'long unsigned int', '4',
341 'long long', '8',
342 'long long int', '8',
343 'unsigned long long', '8',
344 'unsigned long long int', '8',
345 'float', '4',
346 'double', '8',
347 'pointer', '4',
348);
349
350($type_width, $member_width, $offset_width, $size_width) = (20, 20, 6, 5);
351
352($offset_fmt, $size_fmt) = ('d', 'd');
353
354$indent = 2;
355
356$CC = 'cc';
357!NO!SUBS!
358
359if (($Config{gccversion} || '') =~ /^(\d+)\.(\d+)/
360 and ($1 > 3 or ($1 == 3 and $2 >= 2))) {
361 print OUT q/$CFLAGS = '-gstabs -S';/;
362} else {
363 print OUT q/$CFLAGS = '-g -S';/;
364}
365
366print OUT <<'!NO!SUBS!';
367
368$DEFINES = '';
369
370$perl++ if $0 =~ m#/?c2ph$#;
371
372require 'getopts.pl';
373
374use File::Temp 'tempdir';
375
376eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;
377
378&Getopts('aixdpvtnws:') || &usage(0);
379
380$opt_d && $debug++;
381$opt_t && $trace++;
382$opt_p && $perl++;
383$opt_v && $verbose++;
384$opt_n && ($perl = 0);
385
386if ($opt_w) {
387 ($type_width, $member_width, $offset_width) = (45, 35, 8);
388}
389if ($opt_x) {
390 ($offset_fmt, $offset_width, $size_fmt, $size_width) = ( 'x', '08', 'x', 04 );
391}
392
393eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;
394
395sub PLUMBER {
396 select(STDERR);
397 print "oops, apperent pager foulup\n";
398 $isatty++;
399 &usage(1);
400}
401
402sub usage {
403 local($oops) = @_;
404 unless (-t STDOUT) {
405 select(STDERR);
406 } elsif (!$oops) {
407 $isatty++;
408 $| = 1;
409 print "hit <RETURN> for further explanation: ";
410 <STDIN>;
411 open (PIPE, "|". ($ENV{PAGER} || 'more'));
412 $SIG{PIPE} = PLUMBER;
413 select(PIPE);
414 }
415
416 print "usage: $0 [-dpnP] [var=val] [files ...]\n";
417
418 exit unless $isatty;
419
420 print <<EOF;
421
422Options:
423
424-w wide; short for: type_width=45 member_width=35 offset_width=8
425-x hex; short for: offset_fmt=x offset_width=08 size_fmt=x size_width=04
426
427-n do not generate perl code (default when invoked as pstruct)
428-p generate perl code (default when invoked as c2ph)
429-v generate perl code, with C decls as comments
430
431-i do NOT recompute sizes for intrinsic datatypes
432-a dump information on intrinsics also
433
434-t trace execution
435-d spew reams of debugging output
436
437-slist give comma-separated list a structures to dump
438
439
440Var Name Default Value Meaning
441
442EOF
443
444 &defvar('CC', 'which_compiler to call');
445 &defvar('CFLAGS', 'how to generate *.s files with stabs');
446 &defvar('DEFINES','any extra cflags or cpp defines, like -I, -D, -U');
447
448 print "\n";
449
450 &defvar('type_width', 'width of type field (column 1)');
451 &defvar('member_width', 'width of member field (column 2)');
452 &defvar('offset_width', 'width of offset field (column 3)');
453 &defvar('size_width', 'width of size field (column 4)');
454
455 print "\n";
456
457 &defvar('offset_fmt', 'sprintf format type for offset');
458 &defvar('size_fmt', 'sprintf format type for size');
459
460 print "\n";
461
462 &defvar('indent', 'how far to indent each nesting level');
463
464 print <<'EOF';
465
466 If any *.[ch] files are given, these will be catted together into
467 a temporary *.c file and sent through:
468 $CC $CFLAGS $DEFINES
469 and the resulting *.s groped for stab information. If no files are
470 supplied, then stdin is read directly with the assumption that it
471 contains stab information. All other lines will be ignored. At
472 most one *.s file should be supplied.
473
474EOF
475 close PIPE;
476 exit 1;
477}
478
479sub defvar {
480 local($var, $msg) = @_;
481 printf "%-16s%-15s %s\n", $var, eval "\$$var", $msg;
482}
483
484sub safedir {
485 $SAFEDIR = File::Temp::tempdir("c2ph.XXXXXX", TMPDIR => 1, CLEANUP => 1)
486 unless (defined($SAFEDIR));
487}
488
489undef $SAFEDIR;
490
491$recurse = 1;
492
493if (@ARGV) {
494 if (grep(!/\.[csh]$/,@ARGV)) {
495 warn "Only *.[csh] files expected!\n";
496 &usage;
497 }
498 elsif (grep(/\.s$/,@ARGV)) {
499 if (@ARGV > 1) {
500 warn "Only one *.s file allowed!\n";
501 &usage;
502 }
503 }
504 elsif (@ARGV == 1 && $ARGV[0] =~ /\.c$/) {
505 local($dir, $file) = $ARGV[0] =~ m#(.*/)?(.*)$#;
506 $chdir = "cd $dir && " if $dir;
507 &system("$chdir$CC $CFLAGS $DEFINES $file") && exit 1;
508 $ARGV[0] =~ s/\.c$/.s/;
509 }
510 else {
511 &safedir;
512 $TMP = "$SAFEDIR/c2ph.$$.c";
513 &system("cat @ARGV > $TMP") && exit 1;
514 &system("cd $SAFEDIR && $CC $CFLAGS $DEFINES $TMP") && exit 1;
515 unlink $TMP;
516 $TMP =~ s/\.c$/.s/;
517 @ARGV = ($TMP);
518 }
519}
520
521if ($opt_s) {
522 for (split(/[\s,]+/, $opt_s)) {
523 $interested{$_}++;
524 }
525}
526
527
528$| = 1 if $debug;
529
530main: {
531
532 if ($trace) {
533 if (-t && !@ARGV) {
534 print STDERR "reading from your keyboard: ";
535 } else {
536 print STDERR "reading from " . (@ARGV ? "@ARGV" : "<STDIN>").": ";
537 }
538 }
539
540STAB: while (<>) {
541 if ($trace && !($. % 10)) {
542 $lineno = $..'';
543 print STDERR $lineno, "\b" x length($lineno);
544 }
545 next unless /^\s*\.stabs\s+/;
546 $line = $_;
547 s/^\s*\.stabs\s+//;
548 if (s/\\\\"[d,]+$//) {
549 $saveline .= $line;
550 $savebar = $_;
551 next STAB;
552 }
553 if ($saveline) {
554 s/^"//;
555 $_ = $savebar . $_;
556 $line = $saveline;
557 }
558 &stab;
559 $savebar = $saveline = undef;
560 }
561 print STDERR "$.\n" if $trace;
562 unlink $TMP if $TMP;
563
564 &compute_intrinsics if $perl && !$opt_i;
565
566 print STDERR "resolving types\n" if $trace;
567
568 &resolve_types;
569 &adjust_start_addrs;
570
571 $sum = 2 + $type_width + $member_width;
572 $pmask1 = "%-${type_width}s %-${member_width}s";
573 $pmask2 = "%-${sum}s %${offset_width}${offset_fmt}%s %${size_width}${size_fmt}%s";
574
575
576
577 if ($perl) {
578 # resolve template -- should be in stab define order, but even this isn't enough.
579 print STDERR "\nbuilding type templates: " if $trace;
580 for $i (reverse 0..$#type) {
581 next unless defined($name = $type[$i]);
582 next unless defined $struct{$name};
583 ($iname = $name) =~ s/\..*//;
584 $build_recursed = 0;
585 &build_template($name) unless defined $template{&psou($name)} ||
586 $opt_s && !$interested{$iname};
587 }
588 print STDERR "\n\n" if $trace;
589 }
590
591 print STDERR "dumping structs: " if $trace;
592
593 local($iam);
594
595
596
597 foreach $name (sort keys %struct) {
598 ($iname = $name) =~ s/\..*//;
599 next if $opt_s && !$interested{$iname};
600 print STDERR "$name " if $trace;
601
602 undef @sizeof;
603 undef @typedef;
604 undef @offsetof;
605 undef @indices;
606 undef @typeof;
607 undef @fieldnames;
608
609 $mname = &munge($name);
610
611 $fname = &psou($name);
612
613 print "# " if $perl && $verbose;
614 $pcode = '';
615 print "$fname {\n" if !$perl || $verbose;
616 $template{$fname} = &scrunch($template{$fname}) if $perl;
617 &pstruct($name,$name,0);
618 print "# " if $perl && $verbose;
619 print "}\n" if !$perl || $verbose;
620 print "\n" if $perl && $verbose;
621
622 if ($perl) {
623 print "$pcode";
624
625 printf("\nsub %-32s { %4d; }\n\n", "${mname}'struct", $countof{$name});
626
627 print <<EOF;
628sub ${mname}'typedef {
629 local(\$${mname}'index) = shift;
630 defined \$${mname}'index
631 ? \$${mname}'typedef[\$${mname}'index]
632 : \$${mname}'typedef;
633}
634EOF
635
636 print <<EOF;
637sub ${mname}'sizeof {
638 local(\$${mname}'index) = shift;
639 defined \$${mname}'index
640 ? \$${mname}'sizeof[\$${mname}'index]
641 : \$${mname}'sizeof;
642}
643EOF
644
645 print <<EOF;
646sub ${mname}'offsetof {
647 local(\$${mname}'index) = shift;
648 defined \$${mname}index
649 ? \$${mname}'offsetof[\$${mname}'index]
650 : \$${mname}'sizeof;
651}
652EOF
653
654 print <<EOF;
655sub ${mname}'typeof {
656 local(\$${mname}'index) = shift;
657 defined \$${mname}index
658 ? \$${mname}'typeof[\$${mname}'index]
659 : '$name';
660}
661EOF
662
663 print <<EOF;
664sub ${mname}'fieldnames {
665 \@${mname}'fieldnames;
666}
667EOF
668
669 $iam = ($isastruct{$name} && 's') || ($isaunion{$name} && 'u');
670
671 print <<EOF;
672sub ${mname}'isastruct {
673 '$iam';
674}
675EOF
676
677 print "\$${mname}'typedef = '" . &scrunch($template{$fname})
678 . "';\n";
679
680 print "\$${mname}'sizeof = $sizeof{$name};\n\n";
681
682
683 print "\@${mname}'indices = (", &squishseq(@indices), ");\n";
684
685 print "\n";
686
687 print "\@${mname}'typedef[\@${mname}'indices] = (",
688 join("\n\t", '', @typedef), "\n );\n\n";
689 print "\@${mname}'sizeof[\@${mname}'indices] = (",
690 join("\n\t", '', @sizeof), "\n );\n\n";
691 print "\@${mname}'offsetof[\@${mname}'indices] = (",
692 join("\n\t", '', @offsetof), "\n );\n\n";
693 print "\@${mname}'typeof[\@${mname}'indices] = (",
694 join("\n\t", '', @typeof), "\n );\n\n";
695 print "\@${mname}'fieldnames[\@${mname}'indices] = (",
696 join("\n\t", '', @fieldnames), "\n );\n\n";
697
698 $template_printed{$fname}++;
699 $size_printed{$fname}++;
700 }
701 print "\n";
702 }
703
704 print STDERR "\n" if $trace;
705
706 unless ($perl && $opt_a) {
707 print "\n1;\n" if $perl;
708 exit;
709 }
710
711
712
713 foreach $name (sort bysizevalue keys %intrinsics) {
714 next if $size_printed{$name};
715 print '$',&munge($name),"'sizeof = ", $sizeof{$name}, ";\n";
716 }
717
718 print "\n";
719
720 sub bysizevalue { $sizeof{$a} <=> $sizeof{$b}; }
721
722
723 foreach $name (sort keys %intrinsics) {
724 print '$',&munge($name),"'typedef = '", $template{$name}, "';\n";
725 }
726
727 print "\n1;\n" if $perl;
728
729 exit;
730}
731
732########################################################################################
733
734
735sub stab {
736 next unless $continued || /:[\$\w]+(\(\d+,\d+\))?=[\*\$\w]+/; # (\d+,\d+) is for sun
737 s/"// || next;
738 s/",([x\d]+),([x\d]+),([x\d]+),.*// || next;
739
740 next if /^\s*$/;
741
742 $size = $3 if $3;
743 $_ = $continued . $_ if length($continued);
744 if (s/\\\\$//) {
745 # if last 2 chars of string are '\\' then stab is continued
746 # in next stab entry
747 chop;
748 $continued = $_;
749 next;
750 }
751 $continued = '';
752
753
754 $line = $_;
755
756 if (($name, $pdecl) = /^([\$ \w]+):[tT]((\d+)(=[rufs*](\d+))+)$/) {
757 print "$name is a typedef for some funky pointers: $pdecl\n" if $debug;
758 &pdecl($pdecl);
759 next;
760 }
761
762
763
764 if (/(([ \w]+):t(\d+|\(\d+,\d+\)))=r?(\d+|\(\d+,\d+\))(;\d+;\d+;)?/) {
765 local($ident) = $2;
766 push(@intrinsics, $ident);
767 $typeno = &typeno($3);
768 $type[$typeno] = $ident;
769 print STDERR "intrinsic $ident in new type $typeno\n" if $debug;
770 next;
771 }
772
773 if (($name, $typeordef, $typeno, $extra, $struct, $_)
774 = /^([\$ \w]+):([ustT])(\d+|\(\d+,\d+\))(=[rufs*](\d+))?(.*)$/)
775 {
776 $typeno = &typeno($typeno); # sun foolery
777 }
778 elsif (/^[\$\w]+:/) {
779 next; # variable
780 }
781 else {
782 warn "can't grok stab: <$_> in: $line " if $_;
783 next;
784 }
785
786 #warn "got size $size for $name\n";
787 $sizeof{$name} = $size if $size;
788
789 s/;[-\d]*;[-\d]*;$//; # we don't care about ranges
790
791 $typenos{$name} = $typeno;
792
793 unless (defined $type[$typeno]) {
794 &panic("type 0??") unless $typeno;
795 $type[$typeno] = $name unless defined $type[$typeno];
796 printf "new type $typeno is $name" if $debug;
797 if ($extra =~ /\*/ && defined $type[$struct]) {
798 print ", a typedef for a pointer to " , $type[$struct] if $debug;
799 }
800 } else {
801 printf "%s is type %d", $name, $typeno if $debug;
802 print ", a typedef for " , $type[$typeno] if $debug;
803 }
804 print "\n" if $debug;
805 #next unless $extra =~ /[su*]/;
806
807 #$type[$struct] = $name;
808
809 if ($extra =~ /[us*]/) {
810 &sou($name, $extra);
811 $_ = &sdecl($name, $_, 0);
812 }
813 elsif (/^=ar/) {
814 print "it's a bare array typedef -- that's pretty sick\n" if $debug;
815 $_ = "$typeno$_";
816 $scripts = '';
817 $_ = &adecl($_,1);
818
819 }
820 elsif (s/((\w+):t(\d+|\(\d+,\d+\)))?=r?(;\d+;\d+;)?//) { # the ?'s are for gcc
821 push(@intrinsics, $2);
822 $typeno = &typeno($3);
823 $type[$typeno] = $2;
824 print STDERR "intrinsic $2 in new type $typeno\n" if $debug;
825 }
826 elsif (s/^=e//) { # blessed be thy compiler; mine won't do this
827 &edecl;
828 }
829 else {
830 warn "Funny remainder for $name on line $_ left in $line " if $_;
831 }
832}
833
834sub typeno { # sun thinks types are (0,27) instead of just 27
835 local($_) = @_;
836 s/\(\d+,(\d+)\)/$1/;
837 $_;
838}
839
840sub pstruct {
841 local($what,$prefix,$base) = @_;
842 local($field, $fieldname, $typeno, $count, $offset, $entry);
843 local($fieldtype);
844 local($type, $tname);
845 local($mytype, $mycount, $entry2);
846 local($struct_count) = 0;
847 local($pad, $revpad, $length, $prepad, $lastoffset, $lastlength, $fmt);
848 local($bits,$bytes);
849 local($template);
850
851
852 local($mname) = &munge($name);
853
854 sub munge {
855 local($_) = @_;
856 s/[\s\$\.]/_/g;
857 $_;
858 }
859
860 local($sname) = &psou($what);
861
862 $nesting++;
863
864 for $field (split(/;/, $struct{$what})) {
865 $pad = $prepad = 0;
866 $entry = '';
867 ($fieldname, $typeno, $count, $offset, $length) = split(/,/, $field);
868
869 $type = $type[$typeno];
870
871 $type =~ /([^[]*)(\[.*\])?/;
872 $mytype = $1;
873 $count .= $2;
874 $fieldtype = &psou($mytype);
875
876 local($fname) = &psou($name);
877
878 if ($build_templates) {
879
880 $pad = ($offset - ($lastoffset + $lastlength))/8
881 if defined $lastoffset;
882
883 if (! $finished_template{$sname}) {
884 if ($isaunion{$what}) {
885 $template{$sname} .= 'X' x $revpad . ' ' if $revpad;
886 } else {
887 $template{$sname} .= 'x' x $pad . ' ' if $pad;
888 }
889 }
890
891 $template = &fetch_template($type);
892 &repeat_template($template,$count);
893
894 if (! $finished_template{$sname}) {
895 $template{$sname} .= $template;
896 }
897
898 $revpad = $length/8 if $isaunion{$what};
899
900 ($lastoffset, $lastlength) = ($offset, $length);
901
902 } else {
903 print '# ' if $perl && $verbose;
904 $entry = sprintf($pmask1,
905 ' ' x ($nesting * $indent) . $fieldtype,
906 "$prefix.$fieldname" . $count);
907
908 $entry =~ s/(\*+)( )/$2$1/;
909
910 printf $pmask2,
911 $entry,
912 ($base+$offset)/8,
913 ($bits = ($base+$offset)%8) ? ".$bits" : " ",
914 $length/8,
915 ($bits = $length % 8) ? ".$bits": ""
916 if !$perl || $verbose;
917
918 if ($perl) {
919 $template = &fetch_template($type);
920 &repeat_template($template,$count);
921 }
922
923 if ($perl && $nesting == 1) {
924
925 push(@sizeof, int($length/8) .",\t# $fieldname");
926 push(@offsetof, int($offset/8) .",\t# $fieldname");
927 local($little) = &scrunch($template);
928 push(@typedef, "'$little', \t# $fieldname");
929 $type =~ s/(struct|union) //;
930 push(@typeof, "'$mytype" . ($count ? $count : '') .
931 "',\t# $fieldname");
932 push(@fieldnames, "'$fieldname',");
933 }
934
935 print ' ', ' ' x $indent x $nesting, $template
936 if $perl && $verbose;
937
938 print "\n" if !$perl || $verbose;
939
940 }
941 if ($perl) {
942 local($mycount) = defined $struct{$mytype} ? $countof{$mytype} : 1;
943 $mycount *= &scripts2count($count) if $count;
944 if ($nesting==1 && !$build_templates) {
945 $pcode .= sprintf("sub %-32s { %4d; }\n",
946 "${mname}'${fieldname}", $struct_count);
947 push(@indices, $struct_count);
948 }
949 $struct_count += $mycount;
950 }
951
952
953 &pstruct($type, "$prefix.$fieldname", $base+$offset)
954 if $recurse && defined $struct{$type};
955 }
956
957 $countof{$what} = $struct_count unless defined $countof{$whati};
958
959 $template{$sname} .= '$' if $build_templates;
960 $finished_template{$sname}++;
961
962 if ($build_templates && !defined $sizeof{$name}) {
963 local($fmt) = &scrunch($template{$sname});
964 print STDERR "no size for $name, punting with $fmt..." if $debug;
965 eval '$sizeof{$name} = length(pack($fmt, ()))';
966 if ($@) {
967 chop $@;
968 warn "couldn't get size for \$name: $@";
969 } else {
970 print STDERR $sizeof{$name}, "\n" if $debUg;
971 }
972 }
973
974 --$nesting;
975}
976
977
978sub psize {
979 local($me) = @_;
980 local($amstruct) = $struct{$me} ? 'struct ' : '';
981
982 print '$sizeof{\'', $amstruct, $me, '\'} = ';
983 printf "%d;\n", $sizeof{$me};
984}
985
986sub pdecl {
987 local($pdecl) = @_;
988 local(@pdecls);
989 local($tname);
990
991 warn "pdecl: $pdecl\n" if $debug;
992
993 $pdecl =~ s/\(\d+,(\d+)\)/$1/g;
994 $pdecl =~ s/\*//g;
995 @pdecls = split(/=/, $pdecl);
996 $typeno = $pdecls[0];
997 $tname = pop @pdecls;
998
999 if ($tname =~ s/^f//) { $tname = "$tname&"; }
1000 #else { $tname = "$tname*"; }
1001
1002 for (reverse @pdecls) {
1003 $tname .= s/^f// ? "&" : "*";
1004 #$tname =~ s/^f(.*)/$1&/;
1005 print "type[$_] is $tname\n" if $debug;
1006 $type[$_] = $tname unless defined $type[$_];
1007 }
1008}
1009
1010
1011
1012sub adecl {
1013 ($arraytype, $unknown, $lower, $upper) = ();
1014 #local($typeno);
1015 # global $typeno, @type
1016 local($_, $typedef) = @_;
1017
1018 while (s/^((\d+|\(\d+,\d+\))=)?ar(\d+|\(\d+,\d+\));//) {
1019 ($arraytype, $unknown) = ($2, $3);
1020 $arraytype = &typeno($arraytype);
1021 $unknown = &typeno($unknown);
1022 if (s/^(\d+);(\d+);//) {
1023 ($lower, $upper) = ($1, $2);
1024 $scripts .= '[' . ($upper+1) . ']';
1025 } else {
1026 warn "can't find array bounds: $_";
1027 }
1028 }
1029 if (s/^([(,)\d*f=]*),(\d+),(\d+);//) {
1030 ($start, $length) = ($2, $3);
1031 $whatis = $1;
1032 if ($whatis =~ /^(\d+|\(\d+,\d+\))=/) {
1033 $typeno = &typeno($1);
1034 &pdecl($whatis);
1035 } else {
1036 $typeno = &typeno($whatis);
1037 }
1038 } elsif (s/^(\d+)(=[*suf]\d*)//) {
1039 local($whatis) = $2;
1040
1041 if ($whatis =~ /[f*]/) {
1042 &pdecl($whatis);
1043 } elsif ($whatis =~ /[su]/) { #
1044 print "$prefix.$fieldname is an array$scripts anon structs; disgusting\n"
1045 if $debug;
1046 #$type[$typeno] = $name unless defined $type[$typeno];
1047 ##printf "new type $typeno is $name" if $debug;
1048 $typeno = $1;
1049 $type[$typeno] = "$prefix.$fieldname";
1050 local($name) = $type[$typeno];
1051 &sou($name, $whatis);
1052 $_ = &sdecl($name, $_, $start+$offset);
1053 1;
1054 $start = $start{$name};
1055 $offset = $sizeof{$name};
1056 $length = $offset;
1057 } else {
1058 warn "what's this? $whatis in $line ";
1059 }
1060 } elsif (/^\d+$/) {
1061 $typeno = $_;
1062 } else {
1063 warn "bad array stab: $_ in $line ";
1064 next STAB;
1065 }
1066 #local($wasdef) = defined($type[$typeno]) && $debug;
1067 #if ($typedef) {
1068 #print "redefining $type[$typeno] to " if $wasdef;
1069 #$type[$typeno] = "$whatis$scripts"; # unless defined $type[$typeno];
1070 #print "$type[$typeno]\n" if $wasdef;
1071 #} else {
1072 #$type[$arraytype] = $type[$typeno] unless defined $type[$arraytype];
1073 #}
1074 $type[$arraytype] = "$type[$typeno]$scripts" if defined $type[$typeno];
1075 print "type[$arraytype] is $type[$arraytype]\n" if $debug;
1076 print "$prefix.$fieldname is an array of $type[$arraytype]\n" if $debug;
1077 $_;
1078}
1079
1080
1081
1082sub sdecl {
1083 local($prefix, $_, $offset) = @_;
1084
1085 local($fieldname, $scripts, $type, $arraytype, $unknown,
1086 $whatis, $pdecl, $upper,$lower, $start,$length) = ();
1087 local($typeno,$sou);
1088
1089
1090SFIELD:
1091 while (/^([^;]+);/) {
1092 $scripts = '';
1093 warn "sdecl $_\n" if $debug;
1094 if (s/^([\$\w]+)://) {
1095 $fieldname = $1;
1096 } elsif (s/(\d+)=([us])(\d+|\(\d+,\d+\))//) { #
1097 $typeno = &typeno($1);
1098 $type[$typeno] = "$prefix.$fieldname";
1099 local($name) = "$prefix.$fieldname";
1100 &sou($name,$2);
1101 $_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
1102 $start = $start{$name};
1103 $offset += $sizeof{$name};
1104 #print "done with anon, start is $start, offset is $offset\n";
1105 #next SFIELD;
1106 } else {
1107 warn "weird field $_ of $line" if $debug;
1108 next STAB;
1109 #$fieldname = &gensym;
1110 #$_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
1111 }
1112
1113 if (/^(\d+|\(\d+,\d+\))=ar/) {
1114 $_ = &adecl($_);
1115 }
1116 elsif (s/^(\d+|\(\d+,\d+\))?,(\d+),(\d+);//) {
1117 ($start, $length) = ($2, $3);
1118 &panic("no length?") unless $length;
1119 $typeno = &typeno($1) if $1;
1120 }
1121 elsif (s/^(\d+)=xs\w+:,(\d+),(\d+);//) {
1122 ($start, $length) = ($2, $3);
1123 &panic("no length?") unless $length;
1124 $typeno = &typeno($1) if $1;
1125 }
1126 elsif (s/^((\d+|\(\d+,\d+\))(=[*f](\d+|\(\d+,\d+\)))+),(\d+),(\d+);//) {
1127 ($pdecl, $start, $length) = ($1,$5,$6);
1128 &pdecl($pdecl);
1129 }
1130 elsif (s/(\d+)=([us])(\d+|\(\d+,\d+\))//) { # the dratted anon struct
1131 ($typeno, $sou) = ($1, $2);
1132 $typeno = &typeno($typeno);
1133 if (defined($type[$typeno])) {
1134 warn "now how did we get type $1 in $fieldname of $line?";
1135 } else {
1136 print "anon type $typeno is $prefix.$fieldname\n" if $debug;
1137 $type[$typeno] = "$prefix.$fieldname" unless defined $type[$typeno];
1138 };
1139 local($name) = "$prefix.$fieldname";
1140 &sou($name,$sou);
1141 print "anon ".($isastruct{$name}) ? "struct":"union"." for $prefix.$fieldname\n" if $debug;
1142 $type[$typeno] = "$prefix.$fieldname";
1143 $_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
1144 $start = $start{$name};
1145 $length = $sizeof{$name};
1146 }
1147 else {
1148 warn "can't grok stab for $name ($_) in line $line ";
1149 next STAB;
1150 }
1151
1152 &panic("no length for $prefix.$fieldname") unless $length;
1153 $struct{$name} .= join(',', $fieldname, $typeno, $scripts, $start, $length) . ';';
1154 }
1155 if (s/;\d*,(\d+),(\d+);//) {
1156 local($start, $size) = ($1, $2);
1157 $sizeof{$prefix} = $size;
1158 print "start of $prefix is $start, size of $sizeof{$prefix}\n" if $debug;
1159 $start{$prefix} = $start;
1160 }
1161 $_;
1162}
1163
1164sub edecl {
1165 s/;$//;
1166 $enum{$name} = $_;
1167 $_ = '';
1168}
1169
1170sub resolve_types {
1171 local($sou);
1172 for $i (0 .. $#type) {
1173 next unless defined $type[$i];
1174 $_ = $type[$i];
1175 unless (/\d/) {
1176 print "type[$i] $type[$i]\n" if $debug;
1177 next;
1178 }
1179 print "type[$i] $_ ==> " if $debug;
1180 s/^(\d+)(\**)\&\*(\**)/"$2($3".&type($1) . ')()'/e;
1181 s/^(\d+)\&/&type($1)/e;
1182 s/^(\d+)/&type($1)/e;
1183 s/(\*+)([^*]+)(\*+)/$1$3$2/;
1184 s/\((\*+)(\w+)(\*+)\)/$3($1$2)/;
1185 s/^(\d+)([\*\[].*)/&type($1).$2/e;
1186 #s/(\d+)(\*|(\[[\[\]\d\*]+]\])+)/&type($1).$2/ge;
1187 $type[$i] = $_;
1188 print "$_\n" if $debug;
1189 }
1190}
1191sub type { &psou($type[$_[0]] || "<UNDEFINED>"); }
1192
1193sub adjust_start_addrs {
1194 for (sort keys %start) {
1195 ($basename = $_) =~ s/\.[^.]+$//;
1196 $start{$_} += $start{$basename};
1197 print "start: $_ @ $start{$_}\n" if $debug;
1198 }
1199}
1200
1201sub sou {
1202 local($what, $_) = @_;
1203 /u/ && $isaunion{$what}++;
1204 /s/ && $isastruct{$what}++;
1205}
1206
1207sub psou {
1208 local($what) = @_;
1209 local($prefix) = '';
1210 if ($isaunion{$what}) {
1211 $prefix = 'union ';
1212 } elsif ($isastruct{$what}) {
1213 $prefix = 'struct ';
1214 }
1215 $prefix . $what;
1216}
1217
1218sub scrunch {
1219 local($_) = @_;
1220
1221 return '' if $_ eq '';
1222
1223 study;
1224
1225 s/\$//g;
1226 s/ / /g;
1227 1 while s/(\w) \1/$1$1/g;
1228
1229 # i wanna say this, but perl resists my efforts:
1230 # s/(\w)(\1+)/$2 . length($1)/ge;
1231
1232 &quick_scrunch;
1233
1234 s/ $//;
1235
1236 $_;
1237}
1238
1239sub buildscrunchlist {
1240 $scrunch_code = "sub quick_scrunch {\n";
1241 for (values %intrinsics) {
1242 $scrunch_code .= "\ts/(${_}{2,})/'$_' . length(\$1)/ge;\n";
1243 }
1244 $scrunch_code .= "}\n";
1245 print "$scrunch_code" if $debug;
1246 eval $scrunch_code;
1247 &panic("can't eval scrunch_code $@ \nscrunch_code") if $@;
1248}
1249
1250sub fetch_template {
1251 local($mytype) = @_;
1252 local($fmt);
1253 local($count) = 1;
1254
1255 &panic("why do you care?") unless $perl;
1256
1257 if ($mytype =~ s/(\[\d+\])+$//) {
1258 $count .= $1;
1259 }
1260
1261 if ($mytype =~ /\*/) {
1262 $fmt = $template{'pointer'};
1263 }
1264 elsif (defined $template{$mytype}) {
1265 $fmt = $template{$mytype};
1266 }
1267 elsif (defined $struct{$mytype}) {
1268 if (!defined $template{&psou($mytype)}) {
1269 &build_template($mytype) unless $mytype eq $name;
1270 }
1271 elsif ($template{&psou($mytype)} !~ /\$$/) {
1272 #warn "incomplete template for $mytype\n";
1273 }
1274 $fmt = $template{&psou($mytype)} || '?';
1275 }
1276 else {
1277 warn "unknown fmt for $mytype\n";
1278 $fmt = '?';
1279 }
1280
1281 $fmt x $count . ' ';
1282}
1283
1284sub compute_intrinsics {
1285 &safedir;
1286 local($TMP) = "$SAFEDIR/c2ph-i.$$.c";
1287 open (TMP, ">$TMP") || die "can't open $TMP: $!";
1288 select(TMP);
1289
1290 print STDERR "computing intrinsic sizes: " if $trace;
1291
1292 undef %intrinsics;
1293
1294 print <<'EOF';
1295main() {
1296 char *mask = "%d %s\n";
1297EOF
1298
1299 for $type (@intrinsics) {
1300 next if !$type || $type eq 'void' || $type =~ /complex/; # sun stuff
1301 print <<"EOF";
1302 printf(mask,sizeof($type), "$type");
1303EOF
1304 }
1305
1306 print <<'EOF';
1307 printf(mask,sizeof(char *), "pointer");
1308 exit(0);
1309}
1310EOF
1311 close TMP;
1312
1313 select(STDOUT);
1314 open(PIPE, "cd $SAFEDIR && $CC $TMP && $SAFEDIR/a.out|");
1315 while (<PIPE>) {
1316 chop;
1317 split(' ',$_,2);;
1318 print "intrinsic $_[1] is size $_[0]\n" if $debug;
1319 $sizeof{$_[1]} = $_[0];
1320 $intrinsics{$_[1]} = $template{$_[0]};
1321 }
1322 close(PIPE) || die "couldn't read intrinsics!";
1323 unlink($TMP, '$SAFEDIR/a.out');
1324 print STDERR "done\n" if $trace;
1325}
1326
1327sub scripts2count {
1328 local($_) = @_;
1329
1330 s/^\[//;
1331 s/\]$//;
1332 s/\]\[/*/g;
1333 $_ = eval;
1334 &panic("$_: $@") if $@;
1335 $_;
1336}
1337
1338sub system {
1339 print STDERR "@_\n" if $trace;
1340 system @_;
1341}
1342
1343sub build_template {
1344 local($name) = @_;
1345
1346 &panic("already got a template for $name") if defined $template{$name};
1347
1348 local($build_templates) = 1;
1349
1350 local($lparen) = '(' x $build_recursed;
1351 local($rparen) = ')' x $build_recursed;
1352
1353 print STDERR "$lparen$name$rparen " if $trace;
1354 $build_recursed++;
1355 &pstruct($name,$name,0);
1356 print STDERR "TEMPLATE for $name is ", $template{&psou($name)}, "\n" if $debug;
1357 --$build_recursed;
1358}
1359
1360
1361sub panic {
1362
1363 select(STDERR);
1364
1365 print "\npanic: @_\n";
1366
1367 exit 1 if $] <= 4.003; # caller broken
1368
1369 local($i,$_);
1370 local($p,$f,$l,$s,$h,$a,@a,@sub);
1371 for ($i = 0; ($p,$f,$l,$s,$h,$w) = caller($i); $i++) {
1372 @a = @DB'args;
1373 for (@a) {
1374 if (/^StB\000/ && length($_) == length($_main{'_main'})) {
1375 $_ = sprintf("%s",$_);
1376 }
1377 else {
1378 s/'/\\'/g;
1379 s/([^\0]*)/'$1'/ unless /^-?[\d.]+$/;
1380 s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg;
1381 s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg;
1382 }
1383 }
1384 $w = $w ? '@ = ' : '$ = ';
1385 $a = $h ? '(' . join(', ', @a) . ')' : '';
1386 push(@sub, "$w&$s$a from file $f line $l\n");
1387 last if $signal;
1388 }
1389 for ($i=0; $i <= $#sub; $i++) {
1390 last if $signal;
1391 print $sub[$i];
1392 }
1393 exit 1;
1394}
1395
1396sub squishseq {
1397 local($num);
1398 local($last) = -1e8;
1399 local($string);
1400 local($seq) = '..';
1401
1402 while (defined($num = shift)) {
1403 if ($num == ($last + 1)) {
1404 $string .= $seq unless $inseq++;
1405 $last = $num;
1406 next;
1407 } elsif ($inseq) {
1408 $string .= $last unless $last == -1e8;
1409 }
1410
1411 $string .= ',' if defined $string;
1412 $string .= $num;
1413 $last = $num;
1414 $inseq = 0;
1415 }
1416 $string .= $last if $inseq && $last != -e18;
1417 $string;
1418}
1419
1420sub repeat_template {
1421 # local($template, $scripts) = @_; have to change caller's values
1422
1423 if ( $_[1] ) {
1424 local($ncount) = &scripts2count($_[1]);
1425 if ($_[0] =~ /^\s*c\s*$/i) {
1426 $_[0] = "A$ncount ";
1427 $_[1] = '';
1428 } else {
1429 $_[0] = $template x $ncount;
1430 }
1431 }
1432}
1433!NO!SUBS!
1434
1435close OUT or die "Can't close $file: $!";
1436chmod 0755, $file or die "Can't reset permissions for $file: $!\n";
1437unlink 'pstruct';
1438print "Linking $file to pstruct.\n";
1439if (defined $Config{d_link}) {
1440 link $file, 'pstruct';
1441} else {
1442 unshift @INC, '../lib';
1443 require File::Copy;
1444 File::Copy::syscopy('c2ph', 'pstruct');
1445}
1446exec("$Config{'eunicefix'} $file") if $Config{'eunicefix'} ne ':';
1447chdir $origdir;