blob: e63d9a20785a6a44dbeb2c494d12fdbc9f0c7ad3 [file] [log] [blame] [edit]
// Copyright (c) 2025 The BoringSSL Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build ignore
// extract_identifiers_clang_json parses the BoringSSL public includes and (for now)
// outputs a report of all identifiers defined therein. Sample usage:
//
// for f in include/openssl/*.h; do echo "#include <${f#include/}>"; done |\
// clang++ -x c++ -std=c++17 -Iinclude -fsyntax-only -Xclang -ast-dump=json - \
// go run util/extract_identifiers_clang_json.go > extract_identifiers.txt
//
// Note that right now the output of this tool is for human use only.
// The tool will likely be changed further for the purpose of symbol prefixing
// and auditing thereof.
package main
import (
"flag"
"fmt"
"log"
"os"
"boringssl.googlesource.com/boringssl.git/util/idextractor"
)
var (
dumpTree = flag.Bool("dump_tree", false, "dump syntax tree while processing")
dumpFullTree = flag.Bool("dump_full_tree", false, "dump syntax tree while processing including system headers")
keepGoing = flag.Bool("keep_going", false, "continue even after errors")
language = flag.String("language", "C", "language to consider the source to be")
globalSymbolsOnly = flag.Bool("global_symbols_only", false, "only output a list of names that may become (part of) linker symbols and are not namespaced")
)
func reportIdentifierGlobalSymbolsOnly(id idextractor.IdentifierInfo) error {
// NOTE: This is over-exporting.
// At least for quite a while we can't namespace the
// enum, struct and union tags either
// as they may be forward declared by callers.
// The idea is to first get this overzealous namespacing to work,
// and then to remove those forward declaration prone symbols
// at least initially (and possibly namespace them then one by one).
if id.Symbol == id.Identifier && id.Linkage != "static" && id.Tag != "typedef" && id.Tag != "using" {
fmt.Printf("%s\n", id.Identifier)
}
return nil
}
var seen = map[string]string{}
func reportIdentifierVerbose(id idextractor.IdentifierInfo) error {
linkage := ""
if id.Linkage != "" {
linkage = id.Linkage + " "
}
declaration := fmt.Sprintf("%s%s %s;", linkage, id.Tag, id.Symbol)
key := id.Symbol
previous, found := seen[key]
if found {
if previous != declaration {
return fmt.Errorf("duplicate distinct definition of %v: %v and %v", key, previous, declaration)
}
return nil
}
seen[key] = declaration
// Append some debug info.
// This might be used later to generate symbol renaming headers,
// but is generally useful to humans debugging this tool's output.
var suffix string
if id.File != "" {
suffix += fmt.Sprintf(" %s:%v (%v-%v)", id.File, id.Line, id.Start, id.End)
}
for _, arg := range id.FunctionArgs {
if arg == "" {
arg = "_"
}
suffix += " " + arg
}
if suffix != "" {
suffix = " //" + suffix
}
fmt.Printf("%s%s\n", declaration, suffix)
return nil
}
// Main is the main program.
func Main() error {
report := reportIdentifierVerbose
if *globalSymbolsOnly {
report = reportIdentifierGlobalSymbolsOnly
}
x := idextractor.New(report, idextractor.Options{
DumpTree: *dumpTree,
DumpFullTree: *dumpFullTree,
KeepGoing: *keepGoing,
Language: *language,
})
return x.Parse(os.Stdin)
}
// main runs Main turning errors into exit codes.
func main() {
flag.Parse()
err := Main()
if err != nil {
log.Panicf("error returned from Main: %v", err)
}
}