Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | # ========== Copyright Header Begin ========================================== |
2 | # | |
3 | # OpenSPARC T2 Processor File: Objects.pm | |
4 | # Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved | |
5 | # 4150 Network Circle, Santa Clara, California 95054, U.S.A. | |
6 | # | |
7 | # * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
8 | # | |
9 | # This program is free software; you can redistribute it and/or modify | |
10 | # it under the terms of the GNU General Public License as published by | |
11 | # the Free Software Foundation; version 2 of the License. | |
12 | # | |
13 | # This program is distributed in the hope that it will be useful, | |
14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | # GNU General Public License for more details. | |
17 | # | |
18 | # You should have received a copy of the GNU General Public License | |
19 | # along with this program; if not, write to the Free Software | |
20 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 | # | |
22 | # For the avoidance of doubt, and except that if any non-GPL license | |
23 | # choice is available it will apply instead, Sun elects to use only | |
24 | # the General Public License version 2 (GPLv2) at this time for any | |
25 | # software where a choice of GPL license versions is made | |
26 | # available with the language indicating that GPLv2 or any later version | |
27 | # may be used, or where a choice of which version of the GPL is applied is | |
28 | # otherwise unspecified. | |
29 | # | |
30 | # Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
31 | # CA 95054 USA or visit www.sun.com if you need additional information or | |
32 | # have any questions. | |
33 | # | |
34 | # ========== Copyright Header End ============================================ | |
35 | package DiagList::Objects; | |
36 | ||
37 | use strict; | |
38 | use DiagList::Output; | |
39 | use DiagList::Settings; | |
40 | ||
41 | ############################################################################### | |
42 | ||
43 | { | |
44 | package DiagList; | |
45 | ||
46 | use DiagList::Output; | |
47 | use DiagList::Settings; | |
48 | ||
49 | use fields qw( | |
50 | file | |
51 | buildtags | |
52 | groups | |
53 | ); | |
54 | ||
55 | our $COMMENT_RE = qr|\/\/|; | |
56 | our $TAG_RE = | |
57 | qr|^ | |
58 | \s* | |
59 | \< | |
60 | \s* | |
61 | (\S+) | |
62 | \s* | |
63 | (.*) | |
64 | \> | |
65 | |x; | |
66 | ||
67 | ############################################################################# | |
68 | ||
69 | sub new { | |
70 | my $class = shift; | |
71 | my $file = shift; | |
72 | my $fh = shift; | |
73 | ||
74 | my $this = {}; | |
75 | bless $this, $class; | |
76 | ||
77 | tie my %buildtags, 'Tie::IxHash'; | |
78 | $this->{buildtags} = \%buildtags; | |
79 | tie my %groups, 'Tie::IxHash'; | |
80 | $this->{groups} = \%groups; | |
81 | $this->parse($file, $fh) if defined $file; | |
82 | return $this; | |
83 | } | |
84 | ||
85 | ############################################################################# | |
86 | ||
87 | sub parse { | |
88 | my $this = shift; | |
89 | my $file = shift; | |
90 | my $fh = shift; | |
91 | ||
92 | chat "Reading $file"; | |
93 | $this->{file} = $file; | |
94 | ||
95 | if(defined $fh and not (ref $fh and $fh->isa('IO::File'))) { | |
96 | my $handle = $fh; | |
97 | $fh = IO::File->new(); | |
98 | $fh->fdopen(fileno($handle), "r") or | |
99 | fatal "Cannot create IO::File object from handle $handle\n"; | |
100 | } else { | |
101 | $fh = IO::File->new("<$file") or fatal "Cannot open $file: $!"; | |
102 | } | |
103 | ||
104 | my $line = 0; | |
105 | ||
106 | my $cur_build_tag; | |
107 | my $cur_name_tag; | |
108 | ||
109 | my @group_stack; | |
110 | my %group_args; | |
111 | my @runarg_stack; | |
112 | my @owner_stack; | |
113 | ||
114 | while(<$fh>) { | |
115 | $line++; | |
116 | chomp; | |
117 | s/$COMMENT_RE.*//; | |
118 | next unless /\S/; | |
119 | ||
120 | ||
121 | if(/^\#\s*(\d+)\s*\"(.*)\"/) { | |
122 | $line = $1 - 1; | |
123 | $file = $2; | |
124 | next; | |
125 | } | |
126 | ||
127 | if(/$TAG_RE/) { | |
128 | my ($tag, $args) = ($1, $2); | |
129 | ||
130 | if($tag =~ s|^\/||) { | |
131 | # End tag | |
132 | ||
133 | if($tag eq 'runargs') { | |
134 | fatal "Nesting error, </runargs> with no matching beginning", | |
135 | $file, $line unless @runarg_stack; | |
136 | pop @runarg_stack; | |
137 | } elsif($tag eq 'debugowner') { | |
138 | fatal "Nesting error, </debugowners> with no matching beginning", | |
139 | $file, $line unless @owner_stack; | |
140 | pop @owner_stack; | |
141 | } else { | |
142 | my $group = pop @group_stack; | |
143 | fatal "Nesting error: /$tag found, /$group->{name} expected", | |
144 | $file, $line unless $tag eq $group->{name}; | |
145 | ||
146 | undef $cur_build_tag if $group->compile_tag; | |
147 | undef $cur_name_tag if $group->name_tag; | |
148 | delete $group_args{$group->{name}}; | |
149 | } | |
150 | ||
151 | } else { | |
152 | ||
153 | if($tag eq 'runargs') { | |
154 | push @runarg_stack, $args; | |
155 | } elsif($tag eq 'debugowner') { | |
156 | push @owner_stack, $args; | |
157 | } else { | |
158 | ||
159 | # Start tag | |
160 | my $buildtag = ($args =~ /\bsys=(\S+)/); | |
161 | $buildtag = $1 if $buildtag; | |
162 | ||
163 | my $nametag = ($args =~ s/\bname=(\S+)\s*//); | |
164 | $nametag = $1 if $nametag; | |
165 | ||
166 | # Error checking here | |
167 | fatal "Build tag $tag multiply defined." , $file, $line | |
168 | if exists $this->{buildtags}{$tag}; | |
169 | ||
170 | ||
171 | if($buildtag) { | |
172 | chat "Inserting tags: $tag=$buildtag\n"; | |
173 | ||
174 | (my $buildargs = $args) =~ s/\b(sys=\S+)/-$1/; | |
175 | ||
176 | $this->{buildtags}{$tag} = $buildargs; | |
177 | ||
178 | # Strip sys= argument for use in group args | |
179 | $args =~ s/\bsys=(\S)+\s*//; | |
180 | ||
181 | $cur_build_tag = $tag; | |
182 | ||
183 | } | |
184 | if($nametag) { | |
185 | fatal "Nametag $nametag defined within nametag $cur_name_tag", | |
186 | $file, $line if defined $cur_name_tag; | |
187 | $cur_name_tag = $nametag; | |
188 | } | |
189 | ||
190 | ||
191 | my $group; | |
192 | if(exists $this->{groups}{$tag}) { | |
193 | fatal "Group $tag is nested inside itself", $file, $line | |
194 | if exists $group_args{$tag}; | |
195 | ||
196 | $group = $this->{groups}{$tag}; | |
197 | } else { | |
198 | ||
199 | $group = DiagList::Group->new(name => $tag); | |
200 | $group->compile_tag($buildtag) if $buildtag; | |
201 | $group->name_tag($nametag) if $nametag; | |
202 | ||
203 | ||
204 | $this->{groups}{$group->{name}} = $group; | |
205 | } | |
206 | $args =~ s/^\s+//; | |
207 | $args =~ s/\s+$//; | |
208 | $group_args{$group->{name}} = $args; | |
209 | push @group_stack, $group; | |
210 | } | |
211 | } | |
212 | } else { | |
213 | # Diag | |
214 | ||
215 | my $diag = DiagList::Diag->new_from_line($_, $cur_name_tag); | |
216 | ||
217 | fatal "Diag $diag->{alias} appears outside any group.", $file, $line | |
218 | unless @group_stack; | |
219 | fatal "Diag $diag->{alias} appears outside any name tag.", $file, $line | |
220 | unless defined $cur_name_tag; | |
221 | fatal "Diag $diag->{name} appears outside any build tag.", $file, $line | |
222 | unless defined $cur_build_tag; | |
223 | ||
224 | foreach my $group (@group_stack) { | |
225 | my $group_diag = $diag->new(); # Clone diag object | |
226 | $group_diag->prepend_args([@runarg_stack, | |
227 | $group_args{$group->{name}}]); | |
228 | $group_diag->set_group($group->{name}); | |
229 | $group->add_diag($group_diag, $cur_build_tag); | |
230 | if(@owner_stack) { | |
231 | my $owner = $owner_stack[$#owner_stack]; | |
232 | $group_diag->add_owner($owner) unless | |
233 | defined $group_diag->get_owner(); # diag has owner on cmdline | |
234 | } | |
235 | } | |
236 | ||
237 | } | |
238 | ||
239 | } | |
240 | ||
241 | fatal "End of file with <runargs> still open!" if @runarg_stack; | |
242 | ||
243 | undef $fh; | |
244 | } | |
245 | ||
246 | ############################################################################# | |
247 | ||
248 | sub build_hash { | |
249 | my $this = shift; | |
250 | return $this->{buildtags}; | |
251 | } | |
252 | ||
253 | ############################################################################# | |
254 | ||
255 | sub build_list { | |
256 | my $this = shift; | |
257 | return keys %{$this->{buildtags}}; | |
258 | } | |
259 | ||
260 | ############################################################################# | |
261 | ||
262 | sub build_args { | |
263 | my $this = shift; | |
264 | my $build_tag = shift; | |
265 | return unless exists $this->{buildtags}{$build_tag}; | |
266 | return $this->{buildtags}{$build_tag}; | |
267 | } | |
268 | ||
269 | ############################################################################# | |
270 | ||
271 | sub group_hash { | |
272 | my $this = shift; | |
273 | return $this->{groups}; | |
274 | } | |
275 | ||
276 | ############################################################################# | |
277 | ||
278 | sub group_list { | |
279 | my $this = shift; | |
280 | return keys %{$this->{groups}}; | |
281 | } | |
282 | ||
283 | ############################################################################# | |
284 | ||
285 | sub find_group { | |
286 | my $this = shift; | |
287 | my $group = shift; | |
288 | ||
289 | return unless exists $this->{groups}{$group}; | |
290 | return $this->{groups}{$group}; | |
291 | } | |
292 | ||
293 | ############################################################################# | |
294 | ||
295 | } | |
296 | ||
297 | ############################################################################### | |
298 | ############################################################################## | |
299 | ||
300 | { | |
301 | package DiagList::Group; | |
302 | use strict; | |
303 | ||
304 | use DiagList::Settings; | |
305 | ||
306 | use fields qw( | |
307 | name | |
308 | compile_tag | |
309 | name_tag | |
310 | ||
311 | tags | |
312 | ); | |
313 | ||
314 | ############################################################################ | |
315 | ||
316 | sub new { | |
317 | my $this = shift; | |
318 | my %args = @_; | |
319 | ||
320 | unless (ref $this) { | |
321 | $this = fields::new($this); | |
322 | } | |
323 | ||
324 | foreach my $arg (keys %args) { | |
325 | $this->{$arg} = $args{$arg}; | |
326 | } | |
327 | $this->{tags} = {} unless defined $this->{tags}; | |
328 | ||
329 | return $this; | |
330 | } | |
331 | ||
332 | ############################################################################ | |
333 | ||
334 | sub name { | |
335 | my $this = shift; | |
336 | my $name = shift; | |
337 | $this->{name} = $name if defined $name; | |
338 | return $this->{name}; | |
339 | } | |
340 | ||
341 | ############################################################################ | |
342 | ||
343 | sub compile_tag { | |
344 | my $this = shift; | |
345 | my $tag = shift; | |
346 | ||
347 | $this->{compile_tag} = undef unless exists $this->{compile_tag}; | |
348 | $this->{compile_tag} = $tag if defined $tag; | |
349 | return $this->{compile_tag}; | |
350 | } | |
351 | ||
352 | ############################################################################ | |
353 | ||
354 | sub name_tag { | |
355 | my $this = shift; | |
356 | my $tag = shift; | |
357 | ||
358 | $this->{name_tag} = undef unless exists $this->{name_tag}; | |
359 | $this->{name_tag} = $tag if defined $tag; | |
360 | return $this->{name_tag}; | |
361 | } | |
362 | ||
363 | ############################################################################ | |
364 | ||
365 | sub build_tags { | |
366 | my $this = shift; | |
367 | my $name = shift; | |
368 | return keys %{$this->{tags}}; | |
369 | } | |
370 | ||
371 | ############################################################################ | |
372 | ||
373 | sub list_diags { | |
374 | my $this = shift; | |
375 | my $buildtag = shift; | |
376 | ||
377 | return unless exists $this->{tags}{$buildtag}; | |
378 | return keys %{$this->{tags}{$buildtag}}; | |
379 | } | |
380 | ||
381 | ############################################################################ | |
382 | ||
383 | sub diag_hash { | |
384 | my $this = shift; | |
385 | my $buildtag = shift; | |
386 | return unless exists $this->{tags}{$buildtag}; | |
387 | return $this->{tags}{$buildtag}; | |
388 | } | |
389 | ||
390 | ############################################################################ | |
391 | ||
392 | sub find_diag { | |
393 | my $this = shift; | |
394 | my $buildtag = shift; | |
395 | my $diagname = shift; | |
396 | ||
397 | return unless exists $this->{tags}{$buildtag}; | |
398 | return unless exists $this->{tags}{$buildtag}{$diagname}; | |
399 | return $this->{tags}{$buildtag}{$diagname}; | |
400 | } | |
401 | ||
402 | ############################################################################ | |
403 | ||
404 | sub add_diag { | |
405 | my $this = shift; | |
406 | my $diag = shift; | |
407 | my $buildtag = shift; | |
408 | ||
409 | if(not defined $this->{tags}{$buildtag}) { | |
410 | tie my %sys, 'Tie::IxHash'; | |
411 | $this->{tags}{$buildtag} = \%sys; | |
412 | } | |
413 | ||
414 | my $key = $diag->{name}; | |
415 | my $gname = $this->{name}; | |
416 | ||
417 | warn "WARNING: Diag $key multiply defined in group $gname\n" | |
418 | if (exists $this->{tags}{$buildtag}{$key} and display_warnings()); | |
419 | ||
420 | $this->{tags}{$buildtag}{$key} = $diag; | |
421 | ||
422 | } | |
423 | ||
424 | ############################################################################ | |
425 | } | |
426 | ||
427 | ############################################################################## | |
428 | ||
429 | { | |
430 | package DiagList::Diag; | |
431 | use strict; | |
432 | ||
433 | use Text::ParseWords; | |
434 | ||
435 | use fields qw( | |
436 | name | |
437 | alias | |
438 | files | |
439 | args | |
440 | ||
441 | nametag | |
442 | buildtag | |
443 | group | |
444 | debugowner | |
445 | ); | |
446 | ||
447 | our @FILE_SUFFIXES = qw(s pal vr tpt); | |
448 | ||
449 | ############################################################################ | |
450 | ||
451 | sub new { | |
452 | my $this = shift; | |
453 | my %args = @_; | |
454 | ||
455 | if(ref $this) { | |
456 | # Cloning! | |
457 | my $that = $this; | |
458 | $this = fields::new(ref $that); | |
459 | foreach my $field (keys %$that) { | |
460 | ||
461 | if(ref $that->{$field} eq 'ARRAY') { | |
462 | $this->{$field} = [ @{$that->{$field}} ]; | |
463 | } elsif(ref $that->{$field}) { | |
464 | die "Don't know how to clone non-array ref field $field in ". | |
465 | "DiagList::Diag\n"; | |
466 | } else { | |
467 | $this->{$field} = $that->{$field}; | |
468 | } | |
469 | ||
470 | } | |
471 | ||
472 | } else { | |
473 | $this = fields::new($this); | |
474 | ||
475 | foreach my $arg (keys %args) { | |
476 | $this->{$arg} = $args{$arg}; | |
477 | } | |
478 | ||
479 | } | |
480 | ||
481 | ||
482 | $this->{args} = [] unless defined $this->{args}; | |
483 | $this->{files} = [] unless defined $this->{files}; | |
484 | ||
485 | return $this; | |
486 | } | |
487 | ||
488 | ############################################################################ | |
489 | ||
490 | sub new_from_line { | |
491 | my $class = shift; | |
492 | my $line = shift; | |
493 | my $nametag = shift; | |
494 | ||
495 | $nametag = '' unless defined $nametag; | |
496 | my @fields = split ' ', $line; | |
497 | my $alias = shift @fields; | |
498 | ||
499 | my @args; | |
500 | my @files; | |
501 | my $debugowner; | |
502 | ||
503 | my $suffix_re = join '|', @FILE_SUFFIXES; | |
504 | $suffix_re = qr/($suffix_re)/; | |
505 | ||
506 | foreach my $field (@fields) { | |
507 | if($field !~ /^[-+]/ and $field =~ /\.$suffix_re$/o) { | |
508 | push @files, $field; | |
509 | } else { | |
510 | ||
511 | if($field =~ /^debugowner=(\S+)$/) { | |
512 | $debugowner = $1; | |
513 | } else { | |
514 | push @args, $field; | |
515 | } | |
516 | } | |
517 | } | |
518 | ||
519 | my $diag = $class->new( | |
520 | alias => $alias, | |
521 | nametag => $nametag, | |
522 | name => "$alias:$nametag", | |
523 | files => \@files, | |
524 | args => \@args, | |
525 | ); | |
526 | ||
527 | $diag->{debugowner} = $debugowner if defined $debugowner; | |
528 | return $diag; | |
529 | } | |
530 | ||
531 | ############################################################################ | |
532 | ||
533 | sub get_file { | |
534 | my $this = shift; | |
535 | return $this->{files}[0]; | |
536 | } | |
537 | ||
538 | ############################################################################ | |
539 | ||
540 | sub prepend_args { | |
541 | my $this = shift; | |
542 | my $args = shift; | |
543 | ||
544 | unshift @{$this->{args}}, @$args; | |
545 | } | |
546 | ||
547 | ############################################################################ | |
548 | ||
549 | sub add_owner { | |
550 | my $this = shift; | |
551 | my $owner = shift; | |
552 | ||
553 | $this->{debugowner} = $owner; | |
554 | } | |
555 | ||
556 | ############################################################################ | |
557 | ||
558 | sub get_owner { | |
559 | my $this = shift; | |
560 | return $this->{debugowner} if defined $this->{debugowner}; | |
561 | return; | |
562 | } | |
563 | ||
564 | ############################################################################ | |
565 | ||
566 | sub get_cmdline { | |
567 | my $this = shift; | |
568 | ||
569 | my @args = grep { $_ =~ /\S/ } @{$this->{args}}; | |
570 | my $args = (scalar @args) ? join ' ', @args : ''; | |
571 | my $files = join ' ', @{$this->{files}}; | |
572 | my $sep = (length $args) ? ' ' : ''; | |
573 | my $cmdline = "$args$sep$files"; | |
574 | $cmdline =~ s/^\s+//; | |
575 | $cmdline =~ s/\s+$//; | |
576 | return $cmdline; | |
577 | } | |
578 | ||
579 | ############################################################################ | |
580 | ||
581 | sub get_cmd_argv { | |
582 | my $this = shift; | |
583 | my $line = $this->get_cmdline; | |
584 | ||
585 | my $keep = 0; | |
586 | my @words = `showargv $line`; | |
587 | ||
588 | my @argv; | |
589 | my $i = 0; | |
590 | while($i <= $#words) { | |
591 | my $word = $words[$i]; | |
592 | ||
593 | # Strip off ARGV stuff at beginning of line | |
594 | # If next line doesn't start with /^ARGV/, then there must be an | |
595 | # embedded newline | |
596 | $word =~ s/^ARGV\[\d+\]\://; | |
597 | chomp $word; | |
598 | $i++; | |
599 | ||
600 | if($i > $#words) { | |
601 | push @argv, $word; | |
602 | last; | |
603 | } | |
604 | ||
605 | while($words[$i] !~ /^ARGV/) { | |
606 | my $new_word = $words[$i]; | |
607 | $word .= "\n" . $new_word; | |
608 | chomp $new_word; | |
609 | $i++; | |
610 | if($i > $#words) { | |
611 | push @argv, $word; | |
612 | last; | |
613 | } | |
614 | } | |
615 | ||
616 | push @argv, $word; | |
617 | } | |
618 | ||
619 | # get rid of argv[0] (showargv executable) | |
620 | shift @argv; | |
621 | ||
622 | return @argv; | |
623 | } | |
624 | ||
625 | ############################################################################ | |
626 | ||
627 | sub get_name { | |
628 | my $this = shift; | |
629 | return $this->{name}; | |
630 | } | |
631 | ||
632 | ############################################################################ | |
633 | ||
634 | sub get_alias { | |
635 | my $this = shift; | |
636 | return $this->{alias}; | |
637 | } | |
638 | ||
639 | ############################################################################ | |
640 | ||
641 | sub get_nametag { | |
642 | my $this = shift; | |
643 | return $this->{nametag}; | |
644 | } | |
645 | ||
646 | ############################################################################ | |
647 | ||
648 | sub set_group { | |
649 | my $this = shift; | |
650 | my $group = shift; | |
651 | $this->{group} = $group if defined $group; | |
652 | return $this->{group}; | |
653 | } | |
654 | ||
655 | ############################################################################ | |
656 | ||
657 | sub get_group { | |
658 | my $this = shift; | |
659 | return $this->{group}; | |
660 | } | |
661 | ||
662 | ############################################################################ | |
663 | ||
664 | sub get_full_name { | |
665 | my $this = shift; | |
666 | my $fullname = $this->{alias} . ':' . $this->{nametag} . ':' . | |
667 | $this->{group}; | |
668 | return $fullname; | |
669 | } | |
670 | ||
671 | ############################################################################ | |
672 | ||
673 | ||
674 | ############################################################################ | |
675 | } | |
676 | ||
677 | ############################################################################## | |
678 | ||
679 | 1; |