103 lines · python
1"""A tool for extracting a list of private lldb symbols to export for MSVC.2 3When exporting symbols from a dll or exe we either need to mark the symbols in4the source code as __declspec(dllexport) or supply a list of symbols to the5linker. Private symbols in LLDB don't explicitly specific dllexport, so we6automate that by examining the symbol table.7"""8 9import argparse10import os11import re12import subprocess13import sys14 15 16def extract_symbols(nm_path: str, lib: str):17 """Extract all of the private lldb symbols from the given path to llvm-nm and18 library to extract from."""19 20 # Matches mangled symbols containing 'lldb_private'.21 lldb_sym_re = r"[0-9a-zA-Z]* [BT] (?P<symbol>[?]+[^?].*lldb_private.*)"22 23 # '-g' means we only get global symbols.24 # '-p' do not waste time sorting the symbols.25 process = subprocess.Popen(26 [nm_path, "-g", "-p", lib],27 bufsize=1,28 stdout=subprocess.PIPE,29 stdin=subprocess.PIPE,30 universal_newlines=True,31 )32 process.stdin.close()33 34 lldb_symbols = set()35 for line in process.stdout:36 match = re.match(lldb_sym_re, line)37 if match:38 symbol = match.group("symbol")39 assert (40 symbol.count(" ") == 041 ), "Regex matched too much, probably got undecorated name as well"42 # Deleting destructors start with ?_G or ?_E and can be discarded43 # because link.exe gives you a warning telling you they can't be44 # exported if you don't.45 if symbol.startswith("??_G") or symbol.startswith("??_E"):46 continue47 lldb_symbols.add(symbol)48 49 return lldb_symbols50 51 52def main():53 parser = argparse.ArgumentParser(description="Generate LLDB dll exports")54 parser.add_argument(55 "-o", metavar="file", type=str, help="The name of the resultant export file."56 )57 parser.add_argument("--nm", help="Path to the llvm-nm executable.")58 parser.add_argument(59 "libs",60 metavar="lib",61 type=str,62 nargs="+",63 help="The libraries to extract symbols from.",64 )65 args = parser.parse_args()66 67 # Get the list of libraries to extract symbols from68 libs = list()69 for lib in args.libs:70 # When invoked by cmake the arguments are the cmake target names of the71 # libraries, so we need to add .lib/.a to the end and maybe lib to the72 # start to get the filename. Also allow objects.73 suffixes = [".lib", ".a", ".obj", ".o"]74 if not any([lib.endswith(s) for s in suffixes]):75 for suffix in suffixes:76 if os.path.exists(lib + suffix):77 lib = lib + suffix78 break79 if os.path.exists("lib" + lib + suffix):80 lib = "lib" + lib + suffix81 break82 if not any([lib.endswith(s) for s in suffixes]):83 print(84 "Unknown extension type for library argument: " + lib, file=sys.stderr85 )86 exit(1)87 libs.append(lib)88 89 # Extract symbols from the input libraries.90 symbols = set()91 for lib in libs:92 for sym in list(extract_symbols(args.nm, lib)):93 symbols.add(sym)94 95 # Write out the symbols to the output file.96 with open(args.o, "w", newline="") as f:97 for s in sorted(symbols):98 f.write(f"{s}\n")99 100 101if __name__ == "__main__":102 main()103