~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/scripts/get_abi.pl

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /scripts/get_abi.pl (Version linux-6.11.5) and /scripts/get_abi.pl (Version linux-6.5.13)


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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php