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

TOMOYO Linux Cross Reference
Linux/scripts/get_abi.pl

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

Diff markup

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


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