source: other-projects/trunk/realistic-books/bin/windows/perl/bin/c2ph.bat@ 19631

Last change on this file since 19631 was 19631, checked in by davidb, 15 years ago

addition of bin directory

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