Quelle find-can-be-private-symbols.py
Sprache: Python
#!/usr/bin/python3 # # Find exported symbols that can be made non-exported. # # Noting that (a) parsing these commands is a pain, the output is quite irregular and (b) I'm fumbling in the # dark here, trying to guess what exactly constitutes an "import" vs an "export" of a symbol, linux linking # is rather complex. # # Takes about 5min to run on a decent machine. # # The standalone function analysis is reasonable reliable, but the class/method analysis is less so # (something to do with destructor thunks not showing up in my results?) # # Also, the class/method analysis will not catch problems like # 'dynamic_cast from 'Foo' with hidden type visibility to 'Bar' with default type visibility' # but loplugin:dyncastvisibility will do that for you #
# find all our shared libs
subprocess_find = subprocess.Popen("find ./instdir -name *.so && find ./workdir/LinkTarget/CppunitTest -name *.so",
stdout=subprocess.PIPE, shell=True) with subprocess_find.stdout as txt: for line in txt:
sharedlib = line.strip() # look for exported symbols
subprocess_nm = subprocess.Popen(b"nm -D " + sharedlib, stdout=subprocess.PIPE, shell=True) with subprocess_nm.stdout as txt2: # We are looking for lines something like: # 0000000000036ed0 T flash_component_getFactory
line_regex = re.compile(r'^[0-9a-fA-F]+ T ') for line2_bytes in txt2:
line2 = line2_bytes.strip().decode("utf-8") if line_regex.match(line2):
sym = line2.split(" ")[2].strip()
exported_symbols1.add(sym)
subprocess_nm.terminate() # look for imported symbols
subprocess_objdump = subprocess.Popen(b"objdump -T " + sharedlib, stdout=subprocess.PIPE, shell=True) with subprocess_objdump.stdout as txt2: # ignore some header bumpf
txt2.readline()
txt2.readline()
txt2.readline()
txt2.readline() # We are looking for lines something like: # 0000000000000000 DF *UND* 0000000000000000 _ZN16FilterConfigItem10WriteInt32ERKN3rtl8OUStringEi for line2_bytes in txt2:
line2 = line2_bytes.strip().decode("utf-8") if"*UND*"notin line2: continue
tokens = line2.split(" ")
sym = tokens[len(tokens)-1].strip()
imported_symbols1.add(sym)
subprocess_objdump.terminate()
subprocess_find.terminate()
# look for imported symbols in executables
subprocess_find = subprocess.Popen("find ./instdir -name *.bin", stdout=subprocess.PIPE, shell=True) with subprocess_find.stdout as txt: for line in txt:
executable = line.strip() # look for exported symbols
subprocess_nm = subprocess.Popen(b"nm -D " + executable + b" | grep -w U", stdout=subprocess.PIPE, shell=True) with subprocess_nm.stdout as txt2: # We are looking for lines something like: # U sal_detail_deinitialize for line2_bytes in txt2:
line2 = line2_bytes.strip().decode("utf-8")
sym = line2.split(" ")[1]
imported_symbols1.add(sym)
subprocess_find.terminate()
# Now we have to symbolize before comparing because sometimes (due to thunks) two # different encoded names symbolize to the same method/func name #
progress = 0
progress_max_len = len(imported_symbols1) + len(exported_symbols1) for sym in imported_symbols1:
progress += 1 if (progress % 128 == 0):
print( str(int(progress * 100 / progress_max_len)) + "%")
filtered_sym = subprocess.check_output(["c++filt", sym]).strip().decode("utf-8") if filtered_sym.startswith("non-virtual thunk to "):
filtered_sym = filtered_sym[21:] elif filtered_sym.startswith("virtual thunk to "):
filtered_sym = filtered_sym[17:]
imported_symbols2.add(filtered_sym)
progress = 0 for sym in exported_symbols1:
progress += 1 if (progress % 128 == 0):
print( str(int(progress * 100 / progress_max_len)) + "%")
filtered_sym = subprocess.check_output(["c++filt", sym]).strip().decode("utf-8") if filtered_sym.startswith("non-virtual thunk to "):
filtered_sym = filtered_sym[21:] elif filtered_sym.startswith("virtual thunk to "):
filtered_sym = filtered_sym[17:]
exported_symbols2.add(filtered_sym)
# for each class, count how many symbols will become hidden if we mark the class as hidden
can_be_hidden_count = dict() for sym in exported_symbols2:
i = sym.rfind("::") if i == -1: continue
clz = sym[:i] if clz in can_be_hidden_count:
can_be_hidden_count[clz] = can_be_hidden_count[clz] + 1 else:
can_be_hidden_count[clz] = 1 for sym in imported_symbols2:
i = sym.rfind("::") if i == -1: continue
clz = sym[:i] if clz in can_be_hidden_count:
can_be_hidden_count[clz] = can_be_hidden_count[clz] - 1 else:
can_be_hidden_count[clz] = -1 # convert to list, and sort the results in descending order
can_be_hidden_list = list() for clz in can_be_hidden_count:
cnt = can_be_hidden_count[clz] if cnt > 0:
can_be_hidden_list.append((cnt, clz))
can_be_hidden_list.sort(reverse=True) with open("bin/find-can-be-private-symbols.classes.results", "wt") as f: for i in can_be_hidden_list: if i[0] < 10: break
f.write(str(i[0]) + " " + i[1] + "\n")
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.