]> git.ipfire.org Git - thirdparty/kernel/linux.git/blame - scripts/get_abi.pl
scripts: get_abi.pl: add a graph to speedup the undefined algorithm
[thirdparty/kernel/linux.git] / scripts / get_abi.pl
CommitLineData
c25ce589 1#!/usr/bin/env perl
ecb351f1 2# SPDX-License-Identifier: GPL-2.0
bbc249f2
MCC
3
4use strict;
234948bf 5use warnings;
55e5414f 6use utf8;
bbc249f2
MCC
7use Pod::Usage;
8use Getopt::Long;
9use File::Find;
10use Fcntl ':mode';
ab02c515 11use Cwd 'abs_path';
bbc249f2 12
234948bf 13my $help = 0;
ab02c515 14my $hint = 0;
234948bf
MCC
15my $man = 0;
16my $debug = 0;
17my $enable_lineno = 0;
f090db43 18my $show_warnings = 1;
33e3e991 19my $prefix="Documentation/ABI";
f090db43 20my $sysfs_prefix="/sys";
14c94257 21my $search_string;
bbc249f2 22
11ce90a4
MCC
23#
24# If true, assumes that the description is formatted with ReST
25#
2fcce37a 26my $description_is_rst = 1;
11ce90a4 27
bbc249f2
MCC
28GetOptions(
29 "debug|d+" => \$debug,
61439c4a 30 "enable-lineno" => \$enable_lineno,
11ce90a4 31 "rst-source!" => \$description_is_rst,
33e3e991 32 "dir=s" => \$prefix,
bbc249f2 33 'help|?' => \$help,
ab02c515 34 "show-hints" => \$hint,
14c94257 35 "search-string=s" => \$search_string,
bbc249f2
MCC
36 man => \$man
37) or pod2usage(2);
38
39pod2usage(1) if $help;
40pod2usage(-exitstatus => 0, -verbose => 2) if $man;
41
33e3e991 42pod2usage(2) if (scalar @ARGV < 1 || @ARGV > 2);
bbc249f2 43
33e3e991
MCC
44my ($cmd, $arg) = @ARGV;
45
f090db43 46pod2usage(2) if ($cmd ne "search" && $cmd ne "rest" && $cmd ne "validate" && $cmd ne "undefined");
33e3e991 47pod2usage(2) if ($cmd eq "search" && !$arg);
bbc249f2
MCC
48
49require Data::Dumper if ($debug);
50
51my %data;
234948bf 52my %symbols;
bbc249f2
MCC
53
54#
55# Displays an error message, printing file name and line
56#
57sub parse_error($$$$) {
58 my ($file, $ln, $msg, $data) = @_;
59
f090db43
MCC
60 return if (!$show_warnings);
61
75442fb0
MCC
62 $data =~ s/\s+$/\n/;
63
64 print STDERR "Warning: file $file#$ln:\n\t$msg";
65
66 if ($data ne "") {
67 print STDERR ". Line\n\t\t$data";
68 } else {
69 print STDERR "\n";
70 }
bbc249f2
MCC
71}
72
73#
74# Parse an ABI file, storing its contents at %data
75#
76sub parse_abi {
77 my $file = $File::Find::name;
78
79 my $mode = (stat($file))[2];
80 return if ($mode & S_IFDIR);
81 return if ($file =~ m,/README,);
82
83 my $name = $file;
84 $name =~ s,.*/,,;
85
a4ea67bc
MCC
86 my $fn = $file;
87 $fn =~ s,Documentation/ABI/,,;
88
89 my $nametag = "File $fn";
d0ebaf51
MCC
90 $data{$nametag}->{what} = "File $name";
91 $data{$nametag}->{type} = "File";
92 $data{$nametag}->{file} = $name;
33e3e991 93 $data{$nametag}->{filepath} = $file;
d0ebaf51 94 $data{$nametag}->{is_file} = 1;
61439c4a 95 $data{$nametag}->{line_no} = 1;
d0ebaf51 96
bbc249f2
MCC
97 my $type = $file;
98 $type =~ s,.*/(.*)/.*,$1,;
99
100 my $what;
101 my $new_what;
234948bf 102 my $tag = "";
bbc249f2 103 my $ln;
6619c661 104 my $xrefs;
4e6a6234 105 my $space;
d0ebaf51 106 my @labels;
234948bf 107 my $label = "";
bbc249f2
MCC
108
109 print STDERR "Opening $file\n" if ($debug > 1);
110 open IN, $file;
111 while(<IN>) {
112 $ln++;
4e6a6234 113 if (m/^(\S+)(:\s*)(.*)/i) {
bbc249f2 114 my $new_tag = lc($1);
4e6a6234
MCC
115 my $sep = $2;
116 my $content = $3;
bbc249f2 117
7ce7b89b 118 if (!($new_tag =~ m/(what|where|date|kernelversion|contact|description|users)/)) {
bbc249f2 119 if ($tag eq "description") {
4e6a6234
MCC
120 # New "tag" is actually part of
121 # description. Don't consider it a tag
122 $new_tag = "";
7d7ea8d2 123 } elsif ($tag ne "") {
bbc249f2
MCC
124 parse_error($file, $ln, "tag '$tag' is invalid", $_);
125 }
126 }
127
2c0700e7
MCC
128 # Invalid, but it is a common mistake
129 if ($new_tag eq "where") {
75442fb0 130 parse_error($file, $ln, "tag 'Where' is invalid. Should be 'What:' instead", "");
2c0700e7
MCC
131 $new_tag = "what";
132 }
133
bbc249f2 134 if ($new_tag =~ m/what/) {
4e6a6234 135 $space = "";
234948bf
MCC
136 $content =~ s/[,.;]$//;
137
c7ba3334
MCC
138 push @{$symbols{$content}->{file}}, " $file:" . ($ln - 1);
139
bbc249f2 140 if ($tag =~ m/what/) {
ab9c1480 141 $what .= "\xac" . $content;
bbc249f2 142 } else {
234948bf
MCC
143 if ($what) {
144 parse_error($file, $ln, "What '$what' doesn't have a description", "") if (!$data{$what}->{description});
145
ab9c1480 146 foreach my $w(split /\xac/, $what) {
c7ba3334 147 $symbols{$w}->{xref} = $what;
234948bf
MCC
148 };
149 }
4e6a6234 150
bbc249f2 151 $what = $content;
d0ebaf51 152 $label = $content;
bbc249f2
MCC
153 $new_what = 1;
154 }
d0ebaf51 155 push @labels, [($content, $label)];
bbc249f2 156 $tag = $new_tag;
6619c661 157
234948bf 158 push @{$data{$nametag}->{symbols}}, $content if ($data{$nametag}->{what});
bbc249f2
MCC
159 next;
160 }
161
7d7ea8d2 162 if ($tag ne "" && $new_tag) {
4e6a6234 163 $tag = $new_tag;
bbc249f2 164
4e6a6234 165 if ($new_what) {
234948bf 166 @{$data{$what}->{label_list}} = @labels if ($data{$nametag}->{what});
d0ebaf51
MCC
167 @labels = ();
168 $label = "";
4e6a6234 169 $new_what = 0;
bbc249f2 170
4e6a6234 171 $data{$what}->{type} = $type;
c7ba3334
MCC
172 if (!defined($data{$what}->{file})) {
173 $data{$what}->{file} = $name;
174 $data{$what}->{filepath} = $file;
175 } else {
176 if ($name ne $data{$what}->{file}) {
177 $data{$what}->{file} .= " " . $name;
178 $data{$what}->{filepath} .= " " . $file;
179 }
180 }
4e6a6234 181 print STDERR "\twhat: $what\n" if ($debug > 1);
c7ba3334
MCC
182 $data{$what}->{line_no} = $ln;
183 } else {
184 $data{$what}->{line_no} = $ln if (!defined($data{$what}->{line_no}));
4e6a6234 185 }
bbc249f2 186
4e6a6234
MCC
187 if (!$what) {
188 parse_error($file, $ln, "'What:' should come first:", $_);
189 next;
190 }
f82a8a74
MCC
191 if ($new_tag eq "description") {
192 $sep =~ s,:, ,;
11ce90a4 193 $content = ' ' x length($new_tag) . $sep . $content;
f82a8a74
MCC
194 while ($content =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}
195 if ($content =~ m/^(\s*)(\S.*)$/) {
196 # Preserve initial spaces for the first line
11ce90a4 197 $space = $1;
f82a8a74
MCC
198 $content = "$2\n";
199 $data{$what}->{$tag} .= $content;
200 } else {
201 undef($space);
4e6a6234 202 }
e9bca891 203
4e6a6234
MCC
204 } else {
205 $data{$what}->{$tag} = $content;
206 }
bbc249f2
MCC
207 next;
208 }
bbc249f2
MCC
209 }
210
4e6a6234 211 # Store any contents before tags at the database
d0ebaf51
MCC
212 if (!$tag && $data{$nametag}->{what}) {
213 $data{$nametag}->{description} .= $_;
6619c661
MCC
214 next;
215 }
bbc249f2 216
4e6a6234 217 if ($tag eq "description") {
e9bca891
MCC
218 my $content = $_;
219 while ($content =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}
f82a8a74
MCC
220 if (m/^\s*\n/) {
221 $data{$what}->{$tag} .= "\n";
222 next;
223 }
224
225 if (!defined($space)) {
e9bca891 226 # Preserve initial spaces for the first line
f82a8a74 227 if ($content =~ m/^(\s*)(\S.*)$/) {
e9bca891 228 $space = $1;
f82a8a74 229 $content = "$2\n";
4e6a6234
MCC
230 }
231 } else {
4e6a6234 232 $space = "" if (!($content =~ s/^($space)//));
4e6a6234 233 }
f82a8a74
MCC
234 $data{$what}->{$tag} .= $content;
235
4e6a6234
MCC
236 next;
237 }
bbc249f2
MCC
238 if (m/^\s*(.*)/) {
239 $data{$what}->{$tag} .= "\n$1";
240 $data{$what}->{$tag} =~ s/\n+$//;
241 next;
242 }
243
244 # Everything else is error
75442fb0 245 parse_error($file, $ln, "Unexpected content", $_);
bbc249f2 246 }
234948bf
MCC
247 $data{$nametag}->{description} =~ s/^\n+// if ($data{$nametag}->{description});
248 if ($what) {
249 parse_error($file, $ln, "What '$what' doesn't have a description", "") if (!$data{$what}->{description});
250
ab9c1480 251 foreach my $w(split /\xac/,$what) {
c7ba3334 252 $symbols{$w}->{xref} = $what;
234948bf
MCC
253 };
254 }
bbc249f2
MCC
255 close IN;
256}
257
234948bf
MCC
258sub create_labels {
259 my %labels;
bbc249f2 260
234948bf
MCC
261 foreach my $what (keys %data) {
262 next if ($data{$what}->{file} eq "File");
4e6a6234 263
234948bf 264 foreach my $p (@{$data{$what}->{label_list}}) {
d0ebaf51
MCC
265 my ($content, $label) = @{$p};
266 $label = "abi_" . $label . " ";
267 $label =~ tr/A-Z/a-z/;
268
269 # Convert special chars to "_"
270 $label =~s/([\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xff])/_/g;
271 $label =~ s,_+,_,g;
272 $label =~ s,_$,,;
273
2e7ce055
MCC
274 # Avoid duplicated labels
275 while (defined($labels{$label})) {
276 my @chars = ("A".."Z", "a".."z");
277 $label .= $chars[rand @chars];
278 }
279 $labels{$label} = 1;
280
234948bf 281 $data{$what}->{label} = $label;
d0ebaf51
MCC
282
283 # only one label is enough
284 last;
6619c661 285 }
234948bf
MCC
286 }
287}
288
289#
290# Outputs the book on ReST format
291#
292
50ebf8f4
MCC
293# \b doesn't work well with paths. So, we need to define something else:
294# Boundaries are punct characters, spaces and end-of-line
295my $start = qr {(^|\s|\() }x;
296my $bondary = qr { ([,.:;\)\s]|\z) }x;
87ec9ea1 297my $xref_match = qr { $start(\/(sys|config|proc|dev|kvd)\/[^,.:;\)\s]+)$bondary }x;
b0f9580a 298my $symbols = qr { ([\x01-\x08\x0e-\x1f\x21-\x2f\x3a-\x40\x7b-\xff]) }x;
55e5414f 299
234948bf
MCC
300sub output_rest {
301 create_labels();
302
9d4fdda3
MCC
303 my $part = "";
304
234948bf
MCC
305 foreach my $what (sort {
306 ($data{$a}->{type} eq "File") cmp ($data{$b}->{type} eq "File") ||
307 $a cmp $b
308 } keys %data) {
309 my $type = $data{$what}->{type};
c7ba3334
MCC
310
311 my @file = split / /, $data{$what}->{file};
312 my @filepath = split / /, $data{$what}->{filepath};
234948bf
MCC
313
314 if ($enable_lineno) {
315 printf "#define LINENO %s%s#%s\n\n",
c7ba3334 316 $prefix, $file[0],
234948bf
MCC
317 $data{$what}->{line_no};
318 }
6619c661 319
234948bf 320 my $w = $what;
6619c661 321
c7ba3334 322 if ($type ne "File") {
9d4fdda3
MCC
323 my $cur_part = $what;
324 if ($what =~ '/') {
325 if ($what =~ m#^(\/?(?:[\w\-]+\/?){1,2})#) {
326 $cur_part = "Symbols under $1";
327 $cur_part =~ s,/$,,;
328 }
329 }
330
331 if ($cur_part ne "" && $part ne $cur_part) {
332 $part = $cur_part;
333 my $bar = $part;
334 $bar =~ s/./-/g;
335 print "$part\n$bar\n\n";
336 }
337
234948bf 338 printf ".. _%s:\n\n", $data{$what}->{label};
45f96517 339
ab9c1480 340 my @names = split /\xac/,$w;
45f96517
MCC
341 my $len = 0;
342
343 foreach my $name (@names) {
b0f9580a 344 $name =~ s/$symbols/\\$1/g;
c01d62d3 345 $name = "**$name**";
45f96517
MCC
346 $len = length($name) if (length($name) > $len);
347 }
348
45f96517
MCC
349 print "+-" . "-" x $len . "-+\n";
350 foreach my $name (@names) {
351 printf "| %s", $name . " " x ($len - length($name)) . " |\n";
352 print "+-" . "-" x $len . "-+\n";
353 }
45f96517 354
c7ba3334
MCC
355 print "\n";
356 }
357
358 for (my $i = 0; $i < scalar(@filepath); $i++) {
359 my $path = $filepath[$i];
360 my $f = $file[$i];
361
362 $path =~ s,.*/(.*/.*),$1,;;
363 $path =~ s,[/\-],_,g;;
364 my $fileref = "abi_file_".$path;
365
366 if ($type eq "File") {
c7ba3334 367 print ".. _$fileref:\n\n";
c7ba3334
MCC
368 } else {
369 print "Defined on file :ref:`$f <$fileref>`\n\n";
370 }
234948bf 371 }
bbc249f2 372
a4ea67bc
MCC
373 if ($type eq "File") {
374 my $bar = $w;
375 $bar =~ s/./-/g;
376 print "$w\n$bar\n\n";
377 }
378
234948bf
MCC
379 my $desc = "";
380 $desc = $data{$what}->{description} if (defined($data{$what}->{description}));
381 $desc =~ s/\s+$/\n/;
bbc249f2 382
4e6a6234 383 if (!($desc =~ /^\s*$/)) {
11ce90a4 384 if ($description_is_rst) {
daaaf58a
MCC
385 # Remove title markups from the description
386 # Having titles inside ABI files will only work if extra
387 # care would be taken in order to strictly follow the same
388 # level order for each markup.
389 $desc =~ s/\n[\-\*\=\^\~]+\n/\n\n/g;
390
55e5414f
MCC
391 # Enrich text by creating cross-references
392
c27c2e34 393 my $new_desc = "";
2ae7bb57
MCC
394 my $init_indent = -1;
395 my $literal_indent = -1;
396
c27c2e34
MCC
397 open(my $fh, "+<", \$desc);
398 while (my $d = <$fh>) {
2ae7bb57
MCC
399 my $indent = $d =~ m/^(\s+)/;
400 my $spaces = length($indent);
401 $init_indent = $indent if ($init_indent < 0);
402 if ($literal_indent >= 0) {
403 if ($spaces > $literal_indent) {
404 $new_desc .= $d;
405 next;
406 } else {
407 $literal_indent = -1;
408 }
409 } else {
410 if ($d =~ /()::$/ && !($d =~ /^\s*\.\./)) {
411 $literal_indent = $spaces;
412 }
413 }
414
c27c2e34
MCC
415 $d =~ s,Documentation/(?!devicetree)(\S+)\.rst,:doc:`/$1`,g;
416
417 my @matches = $d =~ m,Documentation/ABI/([\w\/\-]+),g;
418 foreach my $f (@matches) {
419 my $xref = $f;
420 my $path = $f;
421 $path =~ s,.*/(.*/.*),$1,;;
422 $path =~ s,[/\-],_,g;;
423 $xref .= " <abi_file_" . $path . ">";
424 $d =~ s,\bDocumentation/ABI/$f\b,:ref:`$xref`,g;
425 }
55e5414f 426
c27c2e34
MCC
427 # Seek for cross reference symbols like /sys/...
428 @matches = $d =~ m/$xref_match/g;
55e5414f 429
c27c2e34
MCC
430 foreach my $s (@matches) {
431 next if (!($s =~ m,/,));
432 if (defined($data{$s}) && defined($data{$s}->{label})) {
433 my $xref = $s;
55e5414f 434
c27c2e34
MCC
435 $xref =~ s/$symbols/\\$1/g;
436 $xref = ":ref:`$xref <" . $data{$s}->{label} . ">`";
55e5414f 437
c27c2e34
MCC
438 $d =~ s,$start$s$bondary,$1$xref$2,g;
439 }
55e5414f 440 }
c27c2e34 441 $new_desc .= $d;
55e5414f 442 }
c27c2e34
MCC
443 close $fh;
444
55e5414f 445
c27c2e34 446 print "$new_desc\n\n";
4e6a6234 447 } else {
11ce90a4 448 $desc =~ s/^\s+//;
bbc249f2 449
11ce90a4
MCC
450 # Remove title markups from the description, as they won't work
451 $desc =~ s/\n[\-\*\=\^\~]+\n/\n\n/g;
452
453 if ($desc =~ m/\:\n/ || $desc =~ m/\n[\t ]+/ || $desc =~ m/[\x00-\x08\x0b-\x1f\x7b-\xff]/) {
454 # put everything inside a code block
455 $desc =~ s/\n/\n /g;
456
457 print "::\n\n";
458 print " $desc\n\n";
459 } else {
460 # Escape any special chars from description
461 $desc =~s/([\x00-\x08\x0b-\x1f\x21-\x2a\x2d\x2f\x3c-\x40\x5c\x5e-\x60\x7b-\xff])/\\$1/g;
462 print "$desc\n\n";
463 }
4e6a6234 464 }
bbc249f2 465 } else {
d0ebaf51 466 print "DESCRIPTION MISSING for $what\n\n" if (!$data{$what}->{is_file});
bbc249f2 467 }
6619c661 468
234948bf 469 if ($data{$what}->{symbols}) {
d0ebaf51
MCC
470 printf "Has the following ABI:\n\n";
471
234948bf 472 foreach my $content(@{$data{$what}->{symbols}}) {
c7ba3334 473 my $label = $data{$symbols{$content}->{xref}}->{label};
d0ebaf51
MCC
474
475 # Escape special chars from content
476 $content =~s/([\x00-\x1f\x21-\x2f\x3a-\x40\x7b-\xff])/\\$1/g;
477
478 print "- :ref:`$content <$label>`\n\n";
479 }
480 }
a16ab14e
MCC
481
482 if (defined($data{$what}->{users})) {
483 my $users = $data{$what}->{users};
484
485 $users =~ s/\n/\n\t/g;
486 printf "Users:\n\t%s\n\n", $users if ($users ne "");
487 }
488
bbc249f2
MCC
489 }
490}
491
33e3e991
MCC
492#
493# Searches for ABI symbols
494#
495sub search_symbols {
496 foreach my $what (sort keys %data) {
497 next if (!($what =~ m/($arg)/));
498
499 my $type = $data{$what}->{type};
500 next if ($type eq "File");
501
502 my $file = $data{$what}->{filepath};
503
504 my $bar = $what;
505 $bar =~ s/./-/g;
506
507 print "\n$what\n$bar\n\n";
508
234948bf
MCC
509 my $kernelversion = $data{$what}->{kernelversion} if (defined($data{$what}->{kernelversion}));
510 my $contact = $data{$what}->{contact} if (defined($data{$what}->{contact}));
511 my $users = $data{$what}->{users} if (defined($data{$what}->{users}));
512 my $date = $data{$what}->{date} if (defined($data{$what}->{date}));
513 my $desc = $data{$what}->{description} if (defined($data{$what}->{description}));
514
515 $kernelversion =~ s/^\s+// if ($kernelversion);
516 $contact =~ s/^\s+// if ($contact);
517 if ($users) {
518 $users =~ s/^\s+//;
519 $users =~ s/\n//g;
520 }
521 $date =~ s/^\s+// if ($date);
522 $desc =~ s/^\s+// if ($desc);
33e3e991
MCC
523
524 printf "Kernel version:\t\t%s\n", $kernelversion if ($kernelversion);
525 printf "Date:\t\t\t%s\n", $date if ($date);
526 printf "Contact:\t\t%s\n", $contact if ($contact);
527 printf "Users:\t\t\t%s\n", $users if ($users);
c7ba3334 528 print "Defined on file(s):\t$file\n\n";
33e3e991
MCC
529 print "Description:\n\n$desc";
530 }
531}
532
f090db43 533# Exclude /sys/kernel/debug and /sys/kernel/tracing from the search path
ab02c515 534sub dont_parse_special_attributes {
f090db43
MCC
535 if (($File::Find::dir =~ m,^/sys/kernel,)) {
536 return grep {!/(debug|tracing)/ } @_;
537 }
538
539 if (($File::Find::dir =~ m,^/sys/fs,)) {
540 return grep {!/(pstore|bpf|fuse)/ } @_;
541 }
542
543 return @_
544}
545
546my %leaf;
ab02c515
MCC
547my %aliases;
548my @files;
ca8e055c
MCC
549my %root;
550
551sub graph_add_file {
552 my $file = shift;
553 my $type = shift;
554
555 my $dir = $file;
556 $dir =~ s,^(.*/).*,$1,;
557 $file =~ s,.*/,,;
558
559 my $name;
560 my $file_ref = \%root;
561 foreach my $edge(split "/", $dir) {
562 $name .= "$edge/";
563 if (!defined ${$file_ref}{$edge}) {
564 ${$file_ref}{$edge} = { };
565 }
566 $file_ref = \%{$$file_ref{$edge}};
567 ${$file_ref}{"__name"} = [ $name ];
568 }
569 $name .= "$file";
570 ${$file_ref}{$file} = {
571 "__name" => [ $name ]
572 };
573
574 return \%{$$file_ref{$file}};
575}
576
577sub graph_add_link {
578 my $file = shift;
579 my $link = shift;
580
581 # Traverse graph to find the reference
582 my $file_ref = \%root;
583 foreach my $edge(split "/", $file) {
584 $file_ref = \%{$$file_ref{$edge}} || die "Missing node!";
585 }
586
587 # do a BFS
588
589 my @queue;
590 my %seen;
591 my $base_name;
592 my $st;
593
594 push @queue, $file_ref;
595 $seen{$start}++;
596
597 while (@queue) {
598 my $v = shift @queue;
599 my @child = keys(%{$v});
600
601 foreach my $c(@child) {
602 next if $seen{$$v{$c}};
603 next if ($c eq "__name");
604
605 # Add new name
606 my $name = @{$$v{$c}{"__name"}}[0];
607 if ($name =~ s#^$file/#$link/#) {
608 push @{$$v{$c}{"__name"}}, $name;
609 }
610 # Add child to the queue and mark as seen
611 push @queue, $$v{$c};
612 $seen{$c}++;
613 }
614 }
615}
f090db43 616
ab02c515 617my $escape_symbols = qr { ([\x01-\x08\x0e-\x1f\x21-\x29\x2b-\x2d\x3a-\x40\x7b-\xfe]) }x;
f090db43
MCC
618sub parse_existing_sysfs {
619 my $file = $File::Find::name;
0b87a1b8
MCC
620
621 # Ignore cgroup and firmware
622 return if ($file =~ m#^/sys/(fs/cgroup|firmware)/#);
623
ab02c515
MCC
624 my $mode = (lstat($file))[2];
625 my $abs_file = abs_path($file);
f090db43 626
ab02c515
MCC
627 if (S_ISLNK($mode)) {
628 $aliases{$file} = $abs_file;
629 return;
630 }
631
632 return if (S_ISDIR($mode));
f090db43 633
ab02c515
MCC
634 # Trivial: file is defined exactly the same way at ABI What:
635 return if (defined($data{$file}));
636 return if (defined($data{$abs_file}));
f090db43 637
ca8e055c
MCC
638 push @files, graph_add_file($abs_file, "file");
639}
640
641sub get_leave($)
642{
643 my $what = shift;
644 my $leave;
645
646 my $l = $what;
647 my $stop = 1;
648
649 $leave = $l;
650 $leave =~ s,/$,,;
651 $leave =~ s,.*/,,;
652 $leave =~ s/[\(\)]//g;
653
654 # $leave is used to improve search performance at
655 # check_undefined_symbols, as the algorithm there can seek
656 # for a small number of "what". It also allows giving a
657 # hint about a leave with the same name somewhere else.
658 # However, there are a few occurences where the leave is
659 # either a wildcard or a number. Just group such cases
660 # altogether.
661 if ($leave =~ m/^\.\*/ || $leave eq "" || $leave =~ /^\d+$/) {
662 $leave = "others";
663 }
664
665 return $leave;
ab02c515 666}
f090db43 667
ab02c515 668sub check_undefined_symbols {
ca8e055c
MCC
669 foreach my $file_ref (sort @files) {
670 my @names = @{$$file_ref{"__name"}};
671 my $file = $names[0];
f090db43 672
ab02c515
MCC
673 my $defined = 0;
674 my $exact = 0;
14c94257 675 my $found_string;
f090db43 676
ca8e055c
MCC
677 my $leave = get_leave($file);
678 if (!defined($leaf{$leave})) {
679 $leave = "others";
680 }
681 my $what = $leaf{$leave};
ab02c515
MCC
682
683 my $path = $file;
684 $path =~ s,(.*/).*,$1,;
685
14c94257
MCC
686 if ($search_string) {
687 next if (!($file =~ m#$search_string#));
688 $found_string = 1;
689 }
690
ca8e055c
MCC
691 foreach my $a (@names) {
692 print "--> $a\n" if ($found_string && $hint);
693 foreach my $w (split /\xac/, $what) {
694 if ($a =~ m#^$w$#) {
695 $exact = 1;
696 last;
ab02c515 697 }
f090db43
MCC
698 }
699 }
50116aec
MCC
700
701 $defined++;
702
ab02c515 703 next if ($exact);
f090db43 704
ab02c515
MCC
705 # Ignore some sysfs nodes
706 next if ($file =~ m#/(sections|notes)/#);
f090db43 707
ab02c515
MCC
708 # Would need to check at
709 # Documentation/admin-guide/kernel-parameters.txt, but this
710 # is not easily parseable.
711 next if ($file =~ m#/parameters/#);
f090db43 712
ca8e055c
MCC
713 if ($hint && $defined && (!$search_string || $found_string)) {
714 $what =~ s/\xac/\n\t/g;
715 if ($leave ne "others") {
716 print " more likely regexes:\n\t$what\n";
717 } else {
718 print " tested regexes:\n\t$what\n";
719 }
ab02c515
MCC
720 next;
721 }
14c94257 722 print "$file not found.\n" if (!$search_string || $found_string);
ab02c515 723 }
f090db43
MCC
724}
725
726sub undefined_symbols {
ab02c515
MCC
727 find({
728 wanted =>\&parse_existing_sysfs,
729 preprocess =>\&dont_parse_special_attributes,
730 no_chdir => 1
731 }, $sysfs_prefix);
732
ca8e055c
MCC
733 $leaf{"others"} = "";
734
f090db43 735 foreach my $w (sort keys %data) {
ca8e055c 736 foreach my $what (split /\xac/,$w) {
ab02c515
MCC
737 next if (!($what =~ m/^$sysfs_prefix/));
738
739 # Convert what into regular expressions
740
741 $what =~ s,/\.\.\./,/*/,g;
742 $what =~ s,\*,.*,g;
743
744 # Temporarily change [0-9]+ type of patterns
745 $what =~ s/\[0\-9\]\+/\xff/g;
746
747 # Temporarily change [\d+-\d+] type of patterns
748 $what =~ s/\[0\-\d+\]/\xff/g;
749 $what =~ s/\[(\d+)\]/\xf4$1\xf5/g;
750
751 # Temporarily change [0-9] type of patterns
752 $what =~ s/\[(\d)\-(\d)\]/\xf4$1-$2\xf5/g;
753
754 # Handle multiple option patterns
755 $what =~ s/[\{\<\[]([\w_]+)(?:[,|]+([\w_]+)){1,}[\}\>\]]/($1|$2)/g;
756
757 # Handle wildcards
758 $what =~ s/\<[^\>]+\>/.*/g;
759 $what =~ s/\{[^\}]+\}/.*/g;
760 $what =~ s/\[[^\]]+\]/.*/g;
761
762 $what =~ s/[XYZ]/.*/g;
763
764 # Recover [0-9] type of patterns
765 $what =~ s/\xf4/[/g;
766 $what =~ s/\xf5/]/g;
767
768 # Remove duplicated spaces
769 $what =~ s/\s+/ /g;
770
771 # Special case: this ABI has a parenthesis on it
772 $what =~ s/sqrt\(x^2\+y^2\+z^2\)/sqrt\(x^2\+y^2\+z^2\)/;
773
774 # Special case: drop comparition as in:
775 # What: foo = <something>
776 # (this happens on a few IIO definitions)
777 $what =~ s,\s*\=.*$,,;
778
ca8e055c 779 my $leave = get_leave($what);
ab02c515
MCC
780
781 # Escape all other symbols
782 $what =~ s/$escape_symbols/\\$1/g;
783 $what =~ s/\\\\/\\/g;
784 $what =~ s/\\([\[\]\(\)\|])/$1/g;
785 $what =~ s/(\d+)\\(-\d+)/$1$2/g;
786
14c94257
MCC
787 $what =~ s/\xff/\\d+/g;
788
14c94257
MCC
789 # Special case: IIO ABI which a parenthesis.
790 $what =~ s/sqrt(.*)/sqrt\(.*\)/;
791
14c94257 792 my $added = 0;
ab02c515
MCC
793 foreach my $l (split /\|/, $leave) {
794 if (defined($leaf{$l})) {
ca8e055c
MCC
795 next if ($leaf{$l} =~ m/\b$what\b/);
796 $leaf{$l} .= "\xac" . $what;
14c94257 797 $added = 1;
ab02c515
MCC
798 } else {
799 $leaf{$l} = $what;
14c94257 800 $added = 1;
ab02c515 801 }
f090db43 802 }
14c94257
MCC
803 if ($search_string && $added) {
804 print "What: $what\n" if ($what =~ m#$search_string#);
805 }
806
f090db43
MCC
807 }
808 }
ca8e055c
MCC
809 # Take links into account
810 foreach my $link (keys %aliases) {
811 my $abs_file = $aliases{$link};
812 graph_add_link($abs_file, $link);
813 }
ab02c515 814 check_undefined_symbols;
f090db43
MCC
815}
816
61439c4a
MCC
817# Ensure that the prefix will always end with a slash
818# While this is not needed for find, it makes the patch nicer
819# with --enable-lineno
820$prefix =~ s,/?$,/,;
33e3e991 821
f090db43
MCC
822if ($cmd eq "undefined" || $cmd eq "search") {
823 $show_warnings = 0;
824}
bbc249f2
MCC
825#
826# Parses all ABI files located at $prefix dir
827#
828find({wanted =>\&parse_abi, no_chdir => 1}, $prefix);
829
830print STDERR Data::Dumper->Dump([\%data], [qw(*data)]) if ($debug);
831
832#
33e3e991 833# Handles the command
bbc249f2 834#
f090db43
MCC
835if ($cmd eq "undefined") {
836 undefined_symbols;
837} elsif ($cmd eq "search") {
33e3e991 838 search_symbols;
c7ba3334
MCC
839} else {
840 if ($cmd eq "rest") {
841 output_rest;
842 }
843
844 # Warn about duplicated ABI entries
845 foreach my $what(sort keys %symbols) {
846 my @files = @{$symbols{$what}->{file}};
847
848 next if (scalar(@files) == 1);
bbc249f2 849
c7ba3334
MCC
850 printf STDERR "Warning: $what is defined %d times: @files\n",
851 scalar(@files);
852 }
853}
bbc249f2
MCC
854
855__END__
856
857=head1 NAME
858
859abi_book.pl - parse the Linux ABI files and produce a ReST book.
860
861=head1 SYNOPSIS
862
61439c4a 863B<abi_book.pl> [--debug] [--enable-lineno] [--man] [--help]
ab02c515 864 [--(no-)rst-source] [--dir=<dir>] [--show-hints]
14c94257 865 [--search-string <regex>]
ab02c515 866 <COMAND> [<ARGUMENT>]
33e3e991
MCC
867
868Where <COMMAND> can be:
869
870=over 8
871
872B<search> [SEARCH_REGEX] - search for [SEARCH_REGEX] inside ABI
873
7ce7b89b
MCC
874B<rest> - output the ABI in ReST markup language
875
876B<validate> - validate the ABI contents
33e3e991 877
f090db43
MCC
878B<undefined> - existing symbols at the system that aren't
879 defined at Documentation/ABI
880
33e3e991 881=back
bbc249f2
MCC
882
883=head1 OPTIONS
884
885=over 8
886
33e3e991
MCC
887=item B<--dir>
888
889Changes the location of the ABI search. By default, it uses
890the Documentation/ABI directory.
891
11ce90a4
MCC
892=item B<--rst-source> and B<--no-rst-source>
893
894The input file may be using ReST syntax or not. Those two options allow
895selecting between a rst-compliant source ABI (--rst-source), or a
896plain text that may be violating ReST spec, so it requres some escaping
897logic (--no-rst-source).
898
61439c4a
MCC
899=item B<--enable-lineno>
900
901Enable output of #define LINENO lines.
902
bbc249f2
MCC
903=item B<--debug>
904
905Put the script in verbose mode, useful for debugging. Can be called multiple
906times, to increase verbosity.
907
ab02c515
MCC
908=item B<--show-hints>
909
910Show hints about possible definitions for the missing ABI symbols.
911Used only when B<undefined>.
912
14c94257
MCC
913=item B<--search-string> [regex string]
914
915Show only occurences that match a search string.
916Used only when B<undefined>.
917
bbc249f2
MCC
918=item B<--help>
919
920Prints a brief help message and exits.
921
922=item B<--man>
923
924Prints the manual page and exits.
925
926=back
927
928=head1 DESCRIPTION
929
33e3e991
MCC
930Parse the Linux ABI files from ABI DIR (usually located at Documentation/ABI),
931allowing to search for ABI symbols or to produce a ReST book containing
932the Linux ABI documentation.
933
934=head1 EXAMPLES
935
936Search for all stable symbols with the word "usb":
937
938=over 8
939
940$ scripts/get_abi.pl search usb --dir Documentation/ABI/stable
941
942=back
943
944Search for all symbols that match the regex expression "usb.*cap":
945
946=over 8
947
948$ scripts/get_abi.pl search usb.*cap
949
950=back
951
952Output all obsoleted symbols in ReST format
953
954=over 8
955
956$ scripts/get_abi.pl rest --dir Documentation/ABI/obsolete
957
958=back
bbc249f2
MCC
959
960=head1 BUGS
961
7ce7b89b 962Report bugs to Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
bbc249f2
MCC
963
964=head1 COPYRIGHT
965
7ce7b89b 966Copyright (c) 2016-2019 by Mauro Carvalho Chehab <mchehab+samsung@kernel.org>.
bbc249f2
MCC
967
968License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>.
969
970This is free software: you are free to change and redistribute it.
971There is NO WARRANTY, to the extent permitted by law.
972
973=cut