Commit 7885386d authored by Carsten Emde's avatar Carsten Emde
Browse files

Added option (-x) to force output of symbols in use, unused symbols are

suppressed
parent 012b3ccd
cypherdir
gexfdir
gvdir
testdir
textdir
......@@ -58,6 +58,8 @@ Copyright 2021 - Open Source Automation Development Lab (OSADL) eG, author Carst
-t FILE, --targets FILE
only examine file or comma-separated list of files
-x, --symbols include symbols and their relations (default when format is 'cypher')
-v, --verbose be more verbose about what the program is actually doing
# Scope
......@@ -89,6 +91,26 @@ line options, e.g.
dot -Nfontname=Korolev -Nfontsize=16 -Tpdf callgraph-output.gv >/tmp/gv-display.pdf
There is also a Graphviz live visual editor
# Getting the Graphviz live visual editor from
https://github.com/magjac/graphviz-visual-editor
and follow the installations instructions
1 git clone https://github.com/magjac/graphviz-visual-editor
2. cd graphviz-visual-editor
3. npm install
4. make
5. npm run start
You may then access the Graphviz visual editor by entering
https://localhost:3000
into your browser of choice.
# Getting Neo4J (tested with version 3.4.9 community edition)
Get the community edition at:
......
......@@ -64,7 +64,7 @@ def notarget(filename, limitsearch):
def createoutput(outputdir, outputformat, machine_to_binary, linked_libraries,
filename_to_full_path, elf_to_exported_symbols,
elf_to_imported_symbols, symlink_to_target, targets):
elf_to_imported_symbols, symlink_to_target, targets, forcesymbols):
'''Create an output file for each set of ELF files that belongs together'''
# create an output file for each architecture/operating system
......@@ -90,7 +90,11 @@ def createoutput(outputdir, outputformat, machine_to_binary, linked_libraries,
if limit not in linked_libraries:
continue
for lib in linked_libraries[limit]:
fullfilenames = filename_to_full_path[lib]
try:
fullfilenames = filename_to_full_path[lib]
except:
print("Warning: '%s' not found in file system" % (lib))
continue
for fullfilename in fullfilenames:
if fullfilename in symlink_to_target:
fullfilename = symlink_to_target[fullfilename]
......@@ -154,7 +158,7 @@ def createoutput(outputdir, outputformat, machine_to_binary, linked_libraries,
outputfileopen.write("<graph defaultedgetype=\"directed\" idtype=\"string\" type=\"static\">\n")
outputfileopen.write("<nodes>\n")
elif outputformat == 'gv':
outputfileopen.write("digraph " + os.path.basename(limitsearch[0]) + " {\n ratio=0.562\n")
outputfileopen.write("digraph " + os.path.basename(limitsearch[0]) + " {\n ratio=0.562;\n")
seenfirst = False
......@@ -206,14 +210,20 @@ def createoutput(outputdir, outputformat, machine_to_binary, linked_libraries,
print("Warning: Library '%s' of file '%s' not found in file system" % (l, filename))
continue
#pass
outputfileopen.write(newline)
if seenfirst:
outputfileopen.write(newline)
else:
seenfirst = True
if outputformat == 'cypher':
outputfileopen.write("(%s)-[:LINKSWITH]->(%s)" % (elf_to_placeholder[filename], elf_to_placeholder[fl]))
elif outputformat == 'gexf':
outputfileopen.write("<edge id=\"%s\" source=\"%s\" target=\"%s\" label=\"links with\"/>" % (elf_to_placeholder[filename] + elf_to_placeholder[fl],
elf_to_placeholder[filename], elf_to_placeholder[fl]))
elif outputformat == 'gv':
outputfileopen.write(" %s -> %s;" % (elf_to_placeholder[filename], elf_to_placeholder[fl]))
if forcesymbols:
outputfileopen.write(" %s -> %s [label=\"links with\"];" % (elf_to_placeholder[filename], elf_to_placeholder[fl]))
else:
outputfileopen.write(" %s -> %s;" % (elf_to_placeholder[filename], elf_to_placeholder[fl]))
elif outputformat == 'text':
outputfileopen.write("%s LINKSWITH %s" % (filename, fl))
if fl not in linked_from:
......@@ -225,9 +235,12 @@ def createoutput(outputdir, outputformat, machine_to_binary, linked_libraries,
if outputformat == 'gexf':
outputfileopen.write("\n</edges>")
if outputformat != 'cypher':
if outputformat != 'cypher' and not forcesymbols:
continue;
if outputformat == 'gexf':
outputfileopen.write("\n<nodes>")
# then add all the exported symbols just once
tmpexportsymbols = set()
......@@ -242,6 +255,18 @@ def createoutput(outputdir, outputformat, machine_to_binary, linked_libraries,
continue
if exp['type'] == 'DATA':
continue
symbolinuse = False
for otherfilename in machine_to_binary[architecture][o][endian][elfclass]:
if otherfilename == filename or notarget(otherfilename, limitsearch):
continue
for imp in elf_to_imported_symbols[otherfilename]:
if imp['bind'] != 'LOCAL' and imp['bind'] != 'WEAK' and exp['name'] == imp['name']:
symbolinuse = True
break
if symbolinuse:
break
if not symbolinuse:
continue
if 'name' in exp and 'type' in exp and 'bind' in exp:
tmpexportsymbols.add((exp['name'], exp['type'], exp['bind']))
else:
......@@ -260,8 +285,18 @@ def createoutput(outputdir, outputformat, machine_to_binary, linked_libraries,
break
symbol_to_placeholder[(symbolname, symboltype)] = placeholdername
all_placeholder_names.add(placeholdername)
outputfileopen.write(newline)
outputfileopen.write("(%s:SYMBOL {name: '%s', type: '%s'})" % (symbol_to_placeholder[(symbolname, symboltype)], symbolname, symboltype))
if outputformat != 'text':
outputfileopen.write(newline)
if outputformat == 'cypher':
outputfileopen.write("(%s:SYMBOL {name: '%s', type: '%s'})" % (symbol_to_placeholder[(symbolname, symboltype)], symbolname, symboltype))
elif outputformat == 'gexf':
outputfileopen.write("<node id=\"%s\" label=\"%s\"/>" % (symbol_to_placeholder[(symbolname, symboltype)], symbolname))
elif outputformat == 'gv':
outputfileopen.write(" %s [label=\"%s\" tooltip=\"%s\"];" % (symbol_to_placeholder[(symbolname, symboltype)], symbolname, symboltype))
if outputformat == 'gexf':
outputfileopen.write("\n</nodes>")
outputfileopen.write("\n<edges>")
# then declare for all the symbols which are exported
for filename in machine_to_binary[architecture][o][endian][elfclass]:
......@@ -289,7 +324,17 @@ def createoutput(outputdir, outputformat, machine_to_binary, linked_libraries,
if not symbolinuse:
continue
outputfileopen.write(newline)
outputfileopen.write("(%s)-[:EXPORTS]->(%s)" % (elf_to_placeholder[filename], symbol_to_placeholder[(exp['name'], exp['type'])]))
if outputformat == 'cypher':
outputfileopen.write("(%s)-[:EXPORTS]->(%s)" % (elf_to_placeholder[filename],
symbol_to_placeholder[(exp['name'], exp['type'])]))
elif outputformat == 'gexf':
outputfileopen.write("<edge source=\"%s\" target=\"%s\" label=\"exports\"/>" % (elf_to_placeholder[filename],
symbol_to_placeholder[(exp['name'], exp['type'])]))
elif outputformat == 'gv':
outputfileopen.write(" %s -> %s [label=\"exports\"];" % (elf_to_placeholder[filename],
symbol_to_placeholder[(exp['name'], exp['type'])]))
elif outputformat == 'text':
outputfileopen.write("%s EXPORTS %s" % (filename, exp['name']))
exportedsymbols += 1
if exportedsymbols == 0 and targets != [] and filename not in targets:
files_without_exports.add(filename)
......@@ -321,10 +366,24 @@ def createoutput(outputdir, outputformat, machine_to_binary, linked_libraries,
usage = "UNUSES"
else:
usage = "USES"
outputfileopen.write("(%s)-[:%s]->(%s)" % (elf_to_placeholder[filename], usage, symbol_to_placeholder[(imp['name'], imp['type'])]))
else:
# something is horribly wrong here
pass
if outputformat == 'cypher':
outputfileopen.write("(%s)-[:%s]->(%s)" % (elf_to_placeholder[filename], usage,
symbol_to_placeholder[(imp['name'], imp['type'])]))
elif outputformat == 'gexf':
outputfileopen.write("<edge source=\"%s\" target=\"%s\" label=\"%s\"/>" % (elf_to_placeholder[filename],
symbol_to_placeholder[(imp['name'], imp['type'])], usage.lower()))
elif outputformat == 'gv':
outputfileopen.write(" %s -> %s [label=\"%s\"];" % (elf_to_placeholder[filename],
symbol_to_placeholder[(imp['name'], imp['type'])], usage.lower()))
elif outputformat == 'text':
outputfileopen.write("%s %s %s" % (filename, usage, imp['name']))
else:
# something is horribly wrong here
pass
if outputformat == 'gexf':
outputfileopen.write("\n</edges>")
if outputformat == 'cypher':
outputfileopen.write(";\n")
elif outputformat == 'text':
......@@ -357,6 +416,9 @@ def main(argv):
parser.add_argument("-t", "--targets", action="store",
dest="targets",
help="only examine file or comma-separated list of files", metavar="FILE")
parser.add_argument("-x", "--symbols", action="store_true",
dest="forcesymbols", default=False,
help="include symbols and their relations (default when format is 'cypher')")
parser.add_argument("-v", "--verbose", action="store_true",
dest="verbose", default=False,
help="be more verbose about what the program is actually doing")
......@@ -709,7 +771,7 @@ def main(argv):
createoutput(outputdir, outputformat, machine_to_binary, linked_libraries,
filename_to_full_path, elf_to_exported_symbols,
elf_to_imported_symbols, symlink_to_target,
args.targets)
args.targets, args.forcesymbols)
if __name__ == "__main__":
main(sys.argv)
......@@ -6,9 +6,9 @@ cypherdir = cypherdir
textdir = textdir
[gexf]
gexfdir = gexfdir
gexfdir = gexfdir
[gv]
gvdir = gvdir
gvdir = gvdir
[neo4j]
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment