| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 |
|
| 8 | use strict;
|
| 9 | use warnings;
|
| 10 | use IO::Handle;
|
| 11 | use IO::Select;
|
| 12 | use POSIX ":sys_wait_h";
|
| 13 |
|
| 14 | my $nm = $ENV{'NM'} || die "$0: ERROR: NM not set?";
|
| 15 | my $objtree = $ENV{'objtree'} || '.';
|
| 16 |
|
| 17 | |
| 18 | my $jobs = {}; |
| 19 | |
| 20 | my $results = {}; |
| 21 |
|
| 22 | |
| 23 | |
| 24 | sub get_online_processors {
|
| 25 | open(my $fh, "getconf _NPROCESSORS_ONLN 2>/dev/null |")
|
| 26 | or die "$0: ERROR: failed to execute getconf: $!";
|
| 27 | my $procs = <$fh>;
|
| 28 | close($fh);
|
| 29 |
|
| 30 | if (!($procs =~ /^\d+$/)) {
|
| 31 | return 1;
|
| 32 | }
|
| 33 |
|
| 34 | return int($procs);
|
| 35 | }
|
| 36 |
|
| 37 | |
| 38 | |
| 39 | sub write_results {
|
| 40 | my ($index, $initcalls) = @_;
|
| 41 |
|
| 42 | |
| 43 | |
| 44 | foreach my $counter (sort { $a <=> $b } keys(%{$initcalls})) {
|
| 45 | my $level = $initcalls->{$counter}->{'level'};
|
| 46 |
|
| 47 | |
| 48 | my $secname = $initcalls->{$counter}->{'module'} . '__' .
|
| 49 | $counter . '_' .
|
| 50 | $initcalls->{$counter}->{'line'} . '_' .
|
| 51 | $initcalls->{$counter}->{'function'};
|
| 52 |
|
| 53 | print "$index $level $secname\n";
|
| 54 | }
|
| 55 | }
|
| 56 |
|
| 57 | |
| 58 | sub read_results{
|
| 59 | my ($fh) = @_;
|
| 60 |
|
| 61 | |
| 62 | |
| 63 | |
| 64 | my $data = <$fh>;
|
| 65 |
|
| 66 | if (!defined($data)) {
|
| 67 | return 0;
|
| 68 | }
|
| 69 |
|
| 70 | chomp($data);
|
| 71 |
|
| 72 | my ($index, $level, $secname) = $data =~
|
| 73 | /^(\d+)\ ([^\ ]+)\ (.*)$/;
|
| 74 |
|
| 75 | if (!defined($index) ||
|
| 76 | !defined($level) ||
|
| 77 | !defined($secname)) {
|
| 78 | die "$0: ERROR: child process returned invalid data: $data\n";
|
| 79 | }
|
| 80 |
|
| 81 | $index = int($index);
|
| 82 |
|
| 83 | if (!exists($results->{$index})) {
|
| 84 | $results->{$index} = [];
|
| 85 | }
|
| 86 |
|
| 87 | push (@{$results->{$index}}, {
|
| 88 | 'level' => $level,
|
| 89 | 'secname' => $secname
|
| 90 | });
|
| 91 |
|
| 92 | return 1;
|
| 93 | }
|
| 94 |
|
| 95 | |
| 96 | |
| 97 | sub find_initcalls {
|
| 98 | my ($index, $file) = @_;
|
| 99 |
|
| 100 | die "$0: ERROR: file $file doesn't exist?" if (! -f $file);
|
| 101 |
|
| 102 | open(my $fh, "\"$nm\" --defined-only \"$file\" 2>/dev/null |")
|
| 103 | or die "$0: ERROR: failed to execute \"$nm\": $!";
|
| 104 |
|
| 105 | my $initcalls = {};
|
| 106 |
|
| 107 | while (<$fh>) {
|
| 108 | chomp;
|
| 109 |
|
| 110 | |
| 111 | |
| 112 | my ($path)= $_ =~ /^(.+)\:$/;
|
| 113 |
|
| 114 | if (defined($path)) {
|
| 115 | write_results($index, $initcalls);
|
| 116 | $initcalls = {};
|
| 117 | next;
|
| 118 | }
|
| 119 |
|
| 120 | |
| 121 | my ($module, $counter, $line, $symbol) = $_ =~
|
| 122 | /[a-z]\s+__initcall__(\S*)__(\d+)_(\d+)_(.*)$/;
|
| 123 |
|
| 124 | if (!defined($module)) {
|
| 125 | $module = ''
|
| 126 | }
|
| 127 |
|
| 128 | if (!defined($counter) ||
|
| 129 | !defined($line) ||
|
| 130 | !defined($symbol)) {
|
| 131 | next;
|
| 132 | }
|
| 133 |
|
| 134 | |
| 135 | my ($function, $level) = $symbol =~
|
| 136 | /^(.*)((early|rootfs|con|[0-9])s?)$/;
|
| 137 |
|
| 138 | die "$0: ERROR: invalid initcall name $symbol in $file($path)"
|
| 139 | if (!defined($function) || !defined($level));
|
| 140 |
|
| 141 | $initcalls->{$counter} = {
|
| 142 | 'module' => $module,
|
| 143 | 'line' => $line,
|
| 144 | 'function' => $function,
|
| 145 | 'level' => $level,
|
| 146 | };
|
| 147 | }
|
| 148 |
|
| 149 | close($fh);
|
| 150 | write_results($index, $initcalls);
|
| 151 | }
|
| 152 |
|
| 153 | |
| 154 | |
| 155 | sub wait_for_results {
|
| 156 | my ($select) = @_;
|
| 157 |
|
| 158 | my $pid = 0;
|
| 159 | do {
|
| 160 | |
| 161 | foreach my $fh ($select->can_read(0)) {
|
| 162 | read_results($fh);
|
| 163 | }
|
| 164 |
|
| 165 | |
| 166 | |
| 167 | $pid = waitpid(-1, WNOHANG);
|
| 168 | if ($pid > 0) {
|
| 169 | if (!exists($jobs->{$pid})) {
|
| 170 | next;
|
| 171 | }
|
| 172 |
|
| 173 | my $fh = $jobs->{$pid};
|
| 174 | $select->remove($fh);
|
| 175 |
|
| 176 | while (read_results($fh)) {
|
| 177 | |
| 178 | }
|
| 179 |
|
| 180 | close($fh);
|
| 181 | delete($jobs->{$pid});
|
| 182 | }
|
| 183 | } while ($pid > 0);
|
| 184 | }
|
| 185 |
|
| 186 | |
| 187 | |
| 188 | sub process_files {
|
| 189 | my $index = 0;
|
| 190 | my $njobs = $ENV{'PARALLELISM'} || get_online_processors();
|
| 191 | my $select = IO::Select->new();
|
| 192 |
|
| 193 | while (my $file = shift(@ARGV)) {
|
| 194 | |
| 195 | my $pid = open(my $fh, '-|');
|
| 196 |
|
| 197 | if (!defined($pid)) {
|
| 198 | die "$0: ERROR: failed to fork: $!";
|
| 199 | } elsif ($pid) {
|
| 200 | |
| 201 | $select->add($fh);
|
| 202 | $jobs->{$pid} = $fh;
|
| 203 | } else {
|
| 204 | |
| 205 | STDOUT->autoflush(1);
|
| 206 | find_initcalls($index, "$objtree/$file");
|
| 207 | exit;
|
| 208 | }
|
| 209 |
|
| 210 | $index++;
|
| 211 |
|
| 212 | |
| 213 | if (scalar(keys(%{$jobs})) >= $njobs) {
|
| 214 | wait_for_results($select);
|
| 215 | }
|
| 216 | }
|
| 217 |
|
| 218 | |
| 219 | while (scalar(keys(%{$jobs})) > 0) {
|
| 220 | wait_for_results($select);
|
| 221 | }
|
| 222 | }
|
| 223 |
|
| 224 | sub generate_initcall_lds() {
|
| 225 | process_files();
|
| 226 |
|
| 227 | my $sections = {}; |
| 228 |
|
| 229 | |
| 230 | |
| 231 | foreach my $index (sort { $a <=> $b } keys(%{$results})) {
|
| 232 | foreach my $result (@{$results->{$index}}) {
|
| 233 | my $level = $result->{'level'};
|
| 234 |
|
| 235 | if (!exists($sections->{$level})) {
|
| 236 | $sections->{$level} = [];
|
| 237 | }
|
| 238 |
|
| 239 | push(@{$sections->{$level}}, $result->{'secname'});
|
| 240 | }
|
| 241 | }
|
| 242 |
|
| 243 | die "$0: ERROR: no initcalls?" if (!keys(%{$sections}));
|
| 244 |
|
| 245 | |
| 246 | |
| 247 | print "SECTIONS {\n";
|
| 248 |
|
| 249 | foreach my $level (sort(keys(%{$sections}))) {
|
| 250 | my $section;
|
| 251 |
|
| 252 | if ($level eq 'con') {
|
| 253 | $section = '.con_initcall.init';
|
| 254 | } else {
|
| 255 | $section = ".initcall${level}.init";
|
| 256 | }
|
| 257 |
|
| 258 | print "\t${section} : {\n";
|
| 259 |
|
| 260 | foreach my $secname (@{$sections->{$level}}) {
|
| 261 | print "\t\t*(${section}..${secname}) ;\n";
|
| 262 | }
|
| 263 |
|
| 264 | print "\t}\n";
|
| 265 | }
|
| 266 |
|
| 267 | print "}\n";
|
| 268 | }
|
| 269 |
|
| 270 | generate_initcall_lds();
|