0001
0002
0003
0004
0005
0006
0007
0008 use strict;
0009 use warnings;
0010 use IO::Handle;
0011 use IO::Select;
0012 use POSIX ":sys_wait_h";
0013
0014 my $nm = $ENV{'NM'} || die "$0: ERROR: NM not set?";
0015 my $objtree = $ENV{'objtree'} || '.';
0016
0017
0018 my $jobs = {};
0019
0020 my $results = {};
0021
0022
0023
0024 sub get_online_processors {
0025 open(my $fh, "getconf _NPROCESSORS_ONLN 2>/dev/null |")
0026 or die "$0: ERROR: failed to execute getconf: $!";
0027 my $procs = <$fh>;
0028 close($fh);
0029
0030 if (!($procs =~ /^\d+$/)) {
0031 return 1;
0032 }
0033
0034 return int($procs);
0035 }
0036
0037
0038
0039 sub write_results {
0040 my ($index, $initcalls) = @_;
0041
0042
0043
0044 foreach my $counter (sort { $a <=> $b } keys(%{$initcalls})) {
0045 my $level = $initcalls->{$counter}->{'level'};
0046
0047
0048 my $secname = $initcalls->{$counter}->{'module'} . '__' .
0049 $counter . '_' .
0050 $initcalls->{$counter}->{'line'} . '_' .
0051 $initcalls->{$counter}->{'function'};
0052
0053 print "$index $level $secname\n";
0054 }
0055 }
0056
0057
0058 sub read_results{
0059 my ($fh) = @_;
0060
0061
0062
0063
0064 my $data = <$fh>;
0065
0066 if (!defined($data)) {
0067 return 0;
0068 }
0069
0070 chomp($data);
0071
0072 my ($index, $level, $secname) = $data =~
0073 /^(\d+)\ ([^\ ]+)\ (.*)$/;
0074
0075 if (!defined($index) ||
0076 !defined($level) ||
0077 !defined($secname)) {
0078 die "$0: ERROR: child process returned invalid data: $data\n";
0079 }
0080
0081 $index = int($index);
0082
0083 if (!exists($results->{$index})) {
0084 $results->{$index} = [];
0085 }
0086
0087 push (@{$results->{$index}}, {
0088 'level' => $level,
0089 'secname' => $secname
0090 });
0091
0092 return 1;
0093 }
0094
0095
0096
0097 sub find_initcalls {
0098 my ($index, $file) = @_;
0099
0100 die "$0: ERROR: file $file doesn't exist?" if (! -f $file);
0101
0102 open(my $fh, "\"$nm\" --defined-only \"$file\" 2>/dev/null |")
0103 or die "$0: ERROR: failed to execute \"$nm\": $!";
0104
0105 my $initcalls = {};
0106
0107 while (<$fh>) {
0108 chomp;
0109
0110
0111
0112 my ($path)= $_ =~ /^(.+)\:$/;
0113
0114 if (defined($path)) {
0115 write_results($index, $initcalls);
0116 $initcalls = {};
0117 next;
0118 }
0119
0120
0121 my ($module, $counter, $line, $symbol) = $_ =~
0122 /[a-z]\s+__initcall__(\S*)__(\d+)_(\d+)_(.*)$/;
0123
0124 if (!defined($module)) {
0125 $module = ''
0126 }
0127
0128 if (!defined($counter) ||
0129 !defined($line) ||
0130 !defined($symbol)) {
0131 next;
0132 }
0133
0134
0135 my ($function, $level) = $symbol =~
0136 /^(.*)((early|rootfs|con|[0-9])s?)$/;
0137
0138 die "$0: ERROR: invalid initcall name $symbol in $file($path)"
0139 if (!defined($function) || !defined($level));
0140
0141 $initcalls->{$counter} = {
0142 'module' => $module,
0143 'line' => $line,
0144 'function' => $function,
0145 'level' => $level,
0146 };
0147 }
0148
0149 close($fh);
0150 write_results($index, $initcalls);
0151 }
0152
0153
0154
0155 sub wait_for_results {
0156 my ($select) = @_;
0157
0158 my $pid = 0;
0159 do {
0160
0161 foreach my $fh ($select->can_read(0)) {
0162 read_results($fh);
0163 }
0164
0165
0166
0167 $pid = waitpid(-1, WNOHANG);
0168 if ($pid > 0) {
0169 if (!exists($jobs->{$pid})) {
0170 next;
0171 }
0172
0173 my $fh = $jobs->{$pid};
0174 $select->remove($fh);
0175
0176 while (read_results($fh)) {
0177
0178 }
0179
0180 close($fh);
0181 delete($jobs->{$pid});
0182 }
0183 } while ($pid > 0);
0184 }
0185
0186
0187
0188 sub process_files {
0189 my $index = 0;
0190 my $njobs = $ENV{'PARALLELISM'} || get_online_processors();
0191 my $select = IO::Select->new();
0192
0193 while (my $file = shift(@ARGV)) {
0194
0195 my $pid = open(my $fh, '-|');
0196
0197 if (!defined($pid)) {
0198 die "$0: ERROR: failed to fork: $!";
0199 } elsif ($pid) {
0200
0201 $select->add($fh);
0202 $jobs->{$pid} = $fh;
0203 } else {
0204
0205 STDOUT->autoflush(1);
0206 find_initcalls($index, "$objtree/$file");
0207 exit;
0208 }
0209
0210 $index++;
0211
0212
0213 if (scalar(keys(%{$jobs})) >= $njobs) {
0214 wait_for_results($select);
0215 }
0216 }
0217
0218
0219 while (scalar(keys(%{$jobs})) > 0) {
0220 wait_for_results($select);
0221 }
0222 }
0223
0224 sub generate_initcall_lds() {
0225 process_files();
0226
0227 my $sections = {};
0228
0229
0230
0231 foreach my $index (sort { $a <=> $b } keys(%{$results})) {
0232 foreach my $result (@{$results->{$index}}) {
0233 my $level = $result->{'level'};
0234
0235 if (!exists($sections->{$level})) {
0236 $sections->{$level} = [];
0237 }
0238
0239 push(@{$sections->{$level}}, $result->{'secname'});
0240 }
0241 }
0242
0243 die "$0: ERROR: no initcalls?" if (!keys(%{$sections}));
0244
0245
0246
0247 print "SECTIONS {\n";
0248
0249 foreach my $level (sort(keys(%{$sections}))) {
0250 my $section;
0251
0252 if ($level eq 'con') {
0253 $section = '.con_initcall.init';
0254 } else {
0255 $section = ".initcall${level}.init";
0256 }
0257
0258 print "\t${section} : {\n";
0259
0260 foreach my $secname (@{$sections->{$level}}) {
0261 print "\t\t*(${section}..${secname}) ;\n";
0262 }
0263
0264 print "\t}\n";
0265 }
0266
0267 print "}\n";
0268 }
0269
0270 generate_initcall_lds();