~ [ 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 (Architecture i386) and /scripts/get_abi.pl (Architecture sparc)


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