History

perf scripts python: exported-sql-viewer.py: Add All branches report

Add a report to display branches in a similar fashion to perf script. The main purpose of this report is to display disassembly, however, presently, the only supported disassembler is Intel XED, and additionally the object code must be present in perf build ID cache. To use Intel XED, libxed.so must be present. To build and install libxed.so: git clone https://github.com/intelxed/mbuild.git mbuild git clone https://github.com/intelxed/xed cd xed ./mfile.py --share sudo ./mfile.py --prefix=/usr/local install sudo ldconfig

Adrian Hunter committed 8 years ago

Commit 76099f91 parent 8392b741 file · +547 −0Browse files

Showing the changes to tools/perf/scripts/python (1 of 1 file). Show all

Unified · Split

tools/perf/scripts/python/exported-sql-viewer.py+547−0
@@ -46,6 +46,48 @@ · 45 unmodified lines
4646 # 'Branch Count' is the total number of branches for that function and all
4747 # functions that it calls
4848
49+# There is also a "All branches" report, which displays branches and
50+# possibly disassembly. However, presently, the only supported disassembler is
51+# Intel XED, and additionally the object code must be present in perf build ID
52+# cache. To use Intel XED, libxed.so must be present. To build and install
53+# libxed.so:
54+# git clone https://github.com/intelxed/mbuild.git mbuild
55+# git clone https://github.com/intelxed/xed
56+# cd xed
57+# ./mfile.py --share
58+# sudo ./mfile.py --prefix=/usr/local install
59+# sudo ldconfig
60+#
61+# Example report:
62+#
63+# Time CPU Command PID TID Branch Type In Tx Branch
64+# 8107675239590 2 ls 22011 22011 return from interrupt No ffffffff86a00a67 native_irq_return_iret ([kernel]) -> 7fab593ea260 _start (ld-2.19.so)
65+# 7fab593ea260 48 89 e7 mov %rsp, %rdi
66+# 8107675239899 2 ls 22011 22011 hardware interrupt No 7fab593ea260 _start (ld-2.19.so) -> ffffffff86a012e0 page_fault ([kernel])
67+# 8107675241900 2 ls 22011 22011 return from interrupt No ffffffff86a00a67 native_irq_return_iret ([kernel]) -> 7fab593ea260 _start (ld-2.19.so)
68+# 7fab593ea260 48 89 e7 mov %rsp, %rdi
69+# 7fab593ea263 e8 c8 06 00 00 callq 0x7fab593ea930
70+# 8107675241900 2 ls 22011 22011 call No 7fab593ea263 _start+0x3 (ld-2.19.so) -> 7fab593ea930 _dl_start (ld-2.19.so)
71+# 7fab593ea930 55 pushq %rbp
72+# 7fab593ea931 48 89 e5 mov %rsp, %rbp
73+# 7fab593ea934 41 57 pushq %r15
74+# 7fab593ea936 41 56 pushq %r14
75+# 7fab593ea938 41 55 pushq %r13
76+# 7fab593ea93a 41 54 pushq %r12
77+# 7fab593ea93c 53 pushq %rbx
78+# 7fab593ea93d 48 89 fb mov %rdi, %rbx
79+# 7fab593ea940 48 83 ec 68 sub $0x68, %rsp
80+# 7fab593ea944 0f 31 rdtsc
81+# 7fab593ea946 48 c1 e2 20 shl $0x20, %rdx
82+# 7fab593ea94a 89 c0 mov %eax, %eax
83+# 7fab593ea94c 48 09 c2 or %rax, %rdx
84+# 7fab593ea94f 48 8b 05 1a 15 22 00 movq 0x22151a(%rip), %rax
85+# 8107675242232 2 ls 22011 22011 hardware interrupt No 7fab593ea94f _dl_start+0x1f (ld-2.19.so) -> ffffffff86a012e0 page_fault ([kernel])
86+# 8107675242900 2 ls 22011 22011 return from interrupt No ffffffff86a00a67 native_irq_return_iret ([kernel]) -> 7fab593ea94f _dl_start+0x1f (ld-2.19.so)
87+# 7fab593ea94f 48 8b 05 1a 15 22 00 movq 0x22151a(%rip), %rax
88+# 7fab593ea956 48 89 15 3b 13 22 00 movq %rdx, 0x22133b(%rip)
89+# 8107675243232 2 ls 22011 22011 hardware interrupt No 7fab593ea956 _dl_start+0x26 (ld-2.19.so) -> ffffffff86a012e0 page_fault ([kernel])
90+
4991 import sys
5092 import weakref
5193 import threading
@@ -62,6 +104,16 @@ from multiprocessing import Process, Array, Value, Event · 10 unmodified lines
62104
63105 # Data formatting helpers
64106
107+def tohex(ip):
108+ if ip < 0:
109+ ip += 1 << 64
110+ return "%x" % ip
111+
112+def offstr(offset):
113+ if offset:
114+ return "+0x%x" % offset
115+ return ""
116+
65117 def dsoname(name):
66118 if name == "[kernel.kallsyms]":
67119 return "[kernel]"
@@ -1077,6 +1129,351 @@ class FetchMoreRecordsBar(): · 1009 unmodified lines
10771129 self.in_progress = True
10781130 self.start = self.model.FetchMoreRecords(self.Target())
10791131
1132+# Brance data model level two item
1133+
1134+class BranchLevelTwoItem():
1135+
1136+ def __init__(self, row, text, parent_item):
1137+ self.row = row
1138+ self.parent_item = parent_item
1139+ self.data = [""] * 8
1140+ self.data[7] = text
1141+ self.level = 2
1142+
1143+ def getParentItem(self):
1144+ return self.parent_item
1145+
1146+ def getRow(self):
1147+ return self.row
1148+
1149+ def childCount(self):
1150+ return 0
1151+
1152+ def hasChildren(self):
1153+ return False
1154+
1155+ def getData(self, column):
1156+ return self.data[column]
1157+
1158+# Brance data model level one item
1159+
1160+class BranchLevelOneItem():
1161+
1162+ def __init__(self, glb, row, data, parent_item):
1163+ self.glb = glb
1164+ self.row = row
1165+ self.parent_item = parent_item
1166+ self.child_count = 0
1167+ self.child_items = []
1168+ self.data = data[1:]
1169+ self.dbid = data[0]
1170+ self.level = 1
1171+ self.query_done = False
1172+
1173+ def getChildItem(self, row):
1174+ return self.child_items[row]
1175+
1176+ def getParentItem(self):
1177+ return self.parent_item
1178+
1179+ def getRow(self):
1180+ return self.row
1181+
1182+ def Select(self):
1183+ self.query_done = True
1184+
1185+ if not self.glb.have_disassembler:
1186+ return
1187+
1188+ query = QSqlQuery(self.glb.db)
1189+
1190+ QueryExec(query, "SELECT cpu, to_dso_id, to_symbol_id, to_sym_offset, short_name, long_name, build_id, sym_start, to_ip"
1191+ " FROM samples"
1192+ " INNER JOIN dsos ON samples.to_dso_id = dsos.id"
1193+ " INNER JOIN symbols ON samples.to_symbol_id = symbols.id"
1194+ " WHERE samples.id = " + str(self.dbid))
1195+ if not query.next():
1196+ return
1197+ cpu = query.value(0)
1198+ dso = query.value(1)
1199+ sym = query.value(2)
1200+ if dso == 0 or sym == 0:
1201+ return
1202+ off = query.value(3)
1203+ short_name = query.value(4)
1204+ long_name = query.value(5)
1205+ build_id = query.value(6)
1206+ sym_start = query.value(7)
1207+ ip = query.value(8)
1208+
1209+ QueryExec(query, "SELECT samples.dso_id, symbol_id, sym_offset, sym_start"
1210+ " FROM samples"
1211+ " INNER JOIN symbols ON samples.symbol_id = symbols.id"
1212+ " WHERE samples.id > " + str(self.dbid) + " AND cpu = " + str(cpu) +
1213+ " ORDER BY samples.id"
1214+ " LIMIT 1")
1215+ if not query.next():
1216+ return
1217+ if query.value(0) != dso:
1218+ # Cannot disassemble from one dso to another
1219+ return
1220+ bsym = query.value(1)
1221+ boff = query.value(2)
1222+ bsym_start = query.value(3)
1223+ if bsym == 0:
1224+ return
1225+ tot = bsym_start + boff + 1 - sym_start - off
1226+ if tot <= 0 or tot > 16384:
1227+ return
1228+
1229+ inst = self.glb.disassembler.Instruction()
1230+ f = self.glb.FileFromNamesAndBuildId(short_name, long_name, build_id)
1231+ if not f:
1232+ return
1233+ mode = 0 if Is64Bit(f) else 1
1234+ self.glb.disassembler.SetMode(inst, mode)
1235+
1236+ buf_sz = tot + 16
1237+ buf = create_string_buffer(tot + 16)
1238+ f.seek(sym_start + off)
1239+ buf.value = f.read(buf_sz)
1240+ buf_ptr = addressof(buf)
1241+ i = 0
1242+ while tot > 0:
1243+ cnt, text = self.glb.disassembler.DisassembleOne(inst, buf_ptr, buf_sz, ip)
1244+ if cnt:
1245+ byte_str = tohex(ip).rjust(16)
1246+ for k in xrange(cnt):
1247+ byte_str += " %02x" % ord(buf[i])
1248+ i += 1
1249+ while k < 15:
1250+ byte_str += " "
1251+ k += 1
1252+ self.child_items.append(BranchLevelTwoItem(0, byte_str + " " + text, self))
1253+ self.child_count += 1
1254+ else:
1255+ return
1256+ buf_ptr += cnt
1257+ tot -= cnt
1258+ buf_sz -= cnt
1259+ ip += cnt
1260+
1261+ def childCount(self):
1262+ if not self.query_done:
1263+ self.Select()
1264+ if not self.child_count:
1265+ return -1
1266+ return self.child_count
1267+
1268+ def hasChildren(self):
1269+ if not self.query_done:
1270+ return True
1271+ return self.child_count > 0
1272+
1273+ def getData(self, column):
1274+ return self.data[column]
1275+
1276+# Brance data model root item
1277+
1278+class BranchRootItem():
1279+
1280+ def __init__(self):
1281+ self.child_count = 0
1282+ self.child_items = []
1283+ self.level = 0
1284+
1285+ def getChildItem(self, row):
1286+ return self.child_items[row]
1287+
1288+ def getParentItem(self):
1289+ return None
1290+
1291+ def getRow(self):
1292+ return 0
1293+
1294+ def childCount(self):
1295+ return self.child_count
1296+
1297+ def hasChildren(self):
1298+ return self.child_count > 0
1299+
1300+ def getData(self, column):
1301+ return ""
1302+
1303+# Branch data preparation
1304+
1305+def BranchDataPrep(query):
1306+ data = []
1307+ for i in xrange(0, 8):
1308+ data.append(query.value(i))
1309+ data.append(tohex(query.value(8)).rjust(16) + " " + query.value(9) + offstr(query.value(10)) +
1310+ " (" + dsoname(query.value(11)) + ")" + " -> " +
1311+ tohex(query.value(12)) + " " + query.value(13) + offstr(query.value(14)) +
1312+ " (" + dsoname(query.value(15)) + ")")
1313+ return data
1314+
1315+# Branch data model
1316+
1317+class BranchModel(TreeModel):
1318+
1319+ progress = Signal(object)
1320+
1321+ def __init__(self, glb, event_id, where_clause, parent=None):
1322+ super(BranchModel, self).__init__(BranchRootItem(), parent)
1323+ self.glb = glb
1324+ self.event_id = event_id
1325+ self.more = True
1326+ self.populated = 0
1327+ sql = ("SELECT samples.id, time, cpu, comm, pid, tid, branch_types.name,"
1328+ " CASE WHEN in_tx = '0' THEN 'No' ELSE 'Yes' END,"
1329+ " ip, symbols.name, sym_offset, dsos.short_name,"
1330+ " to_ip, to_symbols.name, to_sym_offset, to_dsos.short_name"
1331+ " FROM samples"
1332+ " INNER JOIN comms ON comm_id = comms.id"
1333+ " INNER JOIN threads ON thread_id = threads.id"
1334+ " INNER JOIN branch_types ON branch_type = branch_types.id"
1335+ " INNER JOIN symbols ON symbol_id = symbols.id"
1336+ " INNER JOIN symbols to_symbols ON to_symbol_id = to_symbols.id"
1337+ " INNER JOIN dsos ON samples.dso_id = dsos.id"
1338+ " INNER JOIN dsos AS to_dsos ON samples.to_dso_id = to_dsos.id"
1339+ " WHERE samples.id > $$last_id$$" + where_clause +
1340+ " AND evsel_id = " + str(self.event_id) +
1341+ " ORDER BY samples.id"
1342+ " LIMIT " + str(glb_chunk_sz))
1343+ self.fetcher = SQLFetcher(glb, sql, BranchDataPrep, self.AddSample)
1344+ self.fetcher.done.connect(self.Update)
1345+ self.fetcher.Fetch(glb_chunk_sz)
1346+
1347+ def columnCount(self, parent=None):
1348+ return 8
1349+
1350+ def columnHeader(self, column):
1351+ return ("Time", "CPU", "Command", "PID", "TID", "Branch Type", "In Tx", "Branch")[column]
1352+
1353+ def columnFont(self, column):
1354+ if column != 7:
1355+ return None
1356+ return QFont("Monospace")
1357+
1358+ def DisplayData(self, item, index):
1359+ if item.level == 1:
1360+ self.FetchIfNeeded(item.row)
1361+ return item.getData(index.column())
1362+
1363+ def AddSample(self, data):
1364+ child = BranchLevelOneItem(self.glb, self.populated, data, self.root)
1365+ self.root.child_items.append(child)
1366+ self.populated += 1
1367+
1368+ def Update(self, fetched):
1369+ if not fetched:
1370+ self.more = False
1371+ self.progress.emit(0)
1372+ child_count = self.root.child_count
1373+ count = self.populated - child_count
1374+ if count > 0:
1375+ parent = QModelIndex()
1376+ self.beginInsertRows(parent, child_count, child_count + count - 1)
1377+ self.insertRows(child_count, count, parent)
1378+ self.root.child_count += count
1379+ self.endInsertRows()
1380+ self.progress.emit(self.root.child_count)
1381+
1382+ def FetchMoreRecords(self, count):
1383+ current = self.root.child_count
1384+ if self.more:
1385+ self.fetcher.Fetch(count)
1386+ else:
1387+ self.progress.emit(0)
1388+ return current
1389+
1390+ def HasMoreRecords(self):
1391+ return self.more
1392+
1393+# Branch window
1394+
1395+class BranchWindow(QMdiSubWindow):
1396+
1397+ def __init__(self, glb, event_id, name, where_clause, parent=None):
1398+ super(BranchWindow, self).__init__(parent)
1399+
1400+ model_name = "Branch Events " + str(event_id)
1401+ if len(where_clause):
1402+ model_name = where_clause + " " + model_name
1403+
1404+ self.model = LookupCreateModel(model_name, lambda: BranchModel(glb, event_id, where_clause))
1405+
1406+ self.view = QTreeView()
1407+ self.view.setUniformRowHeights(True)
1408+ self.view.setModel(self.model)
1409+
1410+ self.ResizeColumnsToContents()
1411+
1412+ self.find_bar = FindBar(self, self, True)
1413+
1414+ self.finder = ChildDataItemFinder(self.model.root)
1415+
1416+ self.fetch_bar = FetchMoreRecordsBar(self.model, self)
1417+
1418+ self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget())
1419+
1420+ self.setWidget(self.vbox.Widget())
1421+
1422+ AddSubWindow(glb.mainwindow.mdi_area, self, name + " Branch Events")
1423+
1424+ def ResizeColumnToContents(self, column, n):
1425+ # Using the view's resizeColumnToContents() here is extrememly slow
1426+ # so implement a crude alternative
1427+ mm = "MM" if column else "MMMM"
1428+ font = self.view.font()
1429+ metrics = QFontMetrics(font)
1430+ max = 0
1431+ for row in xrange(n):
1432+ val = self.model.root.child_items[row].data[column]
1433+ len = metrics.width(str(val) + mm)
1434+ max = len if len > max else max
1435+ val = self.model.columnHeader(column)
1436+ len = metrics.width(str(val) + mm)
1437+ max = len if len > max else max
1438+ self.view.setColumnWidth(column, max)
1439+
1440+ def ResizeColumnsToContents(self):
1441+ n = min(self.model.root.child_count, 100)
1442+ if n < 1:
1443+ # No data yet, so connect a signal to notify when there is
1444+ self.model.rowsInserted.connect(self.UpdateColumnWidths)
1445+ return
1446+ columns = self.model.columnCount()
1447+ for i in xrange(columns):
1448+ self.ResizeColumnToContents(i, n)
1449+
1450+ def UpdateColumnWidths(self, *x):
1451+ # This only needs to be done once, so disconnect the signal now
1452+ self.model.rowsInserted.disconnect(self.UpdateColumnWidths)
1453+ self.ResizeColumnsToContents()
1454+
1455+ def Find(self, value, direction, pattern, context):
1456+ self.view.setFocus()
1457+ self.find_bar.Busy()
1458+ self.finder.Find(value, direction, pattern, context, self.FindDone)
1459+
1460+ def FindDone(self, row):
1461+ self.find_bar.Idle()
1462+ if row >= 0:
1463+ self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex()))
1464+ else:
1465+ self.find_bar.NotFound()
1466+
1467+# Event list
1468+
1469+def GetEventList(db):
1470+ events = []
1471+ query = QSqlQuery(db)
1472+ QueryExec(query, "SELECT name FROM selected_events WHERE id > 0 ORDER BY id")
1473+ while query.next():
1474+ events.append(query.value(0))
1475+ return events
1476+
10801477 # SQL data preparation
10811478
10821479 def SQLTableDataPrep(query, count):
@@ -1448,6 +1845,8 @@ class MainWindow(QMainWindow): · 365 unmodified lines
14481845 reports_menu = menu.addMenu("&Reports")
14491846 reports_menu.addAction(CreateAction("Context-Sensitive Call &Graph", "Create a new window containing a context-sensitive call graph", self.NewCallGraph, self))
14501847
1848+ self.EventMenu(GetEventList(glb.db), reports_menu)
1849+
14511850 self.TableMenu(GetTableList(glb), menu)
14521851
14531852 self.window_menu = WindowMenu(self.mdi_area, menu)
@@ -1476,6 +1875,20 @@ class MainWindow(QMainWindow): · 22 unmodified lines
14761875 win = self.mdi_area.activeSubWindow()
14771876 EnlargeFont(win.view)
14781877
1878+ def EventMenu(self, events, reports_menu):
1879+ branches_events = 0
1880+ for event in events:
1881+ event = event.split(":")[0]
1882+ if event == "branches":
1883+ branches_events += 1
1884+ dbid = 0
1885+ for event in events:
1886+ dbid += 1
1887+ event = event.split(":")[0]
1888+ if event == "branches":
1889+ label = "All branches" if branches_events == 1 else "All branches " + "(id=" + dbid + ")"
1890+ reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewBranchView(x), self))
1891+
14791892 def TableMenu(self, tables, menu):
14801893 table_menu = menu.addMenu("&Tables")
14811894 for table in tables:
@@ -1484,9 +1897,112 @@ class MainWindow(QMainWindow): · 2 unmodified lines
14841897 def NewCallGraph(self):
14851898 CallGraphWindow(self.glb, self)
14861899
1900+ def NewBranchView(self, event_id):
1901+ BranchWindow(self.glb, event_id, "", "", self)
1902+
14871903 def NewTableView(self, table_name):
14881904 TableWindow(self.glb, table_name, self)
14891905
1906+# XED Disassembler
1907+
1908+class xed_state_t(Structure):
1909+
1910+ _fields_ = [
1911+ ("mode", c_int),
1912+ ("width", c_int)
1913+ ]
1914+
1915+class XEDInstruction():
1916+
1917+ def __init__(self, libxed):
1918+ # Current xed_decoded_inst_t structure is 192 bytes. Use 512 to allow for future expansion
1919+ xedd_t = c_byte * 512
1920+ self.xedd = xedd_t()
1921+ self.xedp = addressof(self.xedd)
1922+ libxed.xed_decoded_inst_zero(self.xedp)
1923+ self.state = xed_state_t()
1924+ self.statep = addressof(self.state)
1925+ # Buffer for disassembled instruction text
1926+ self.buffer = create_string_buffer(256)
1927+ self.bufferp = addressof(self.buffer)
1928+
1929+class LibXED():
1930+
1931+ def __init__(self):
1932+ self.libxed = CDLL("libxed.so")
1933+
1934+ self.xed_tables_init = self.libxed.xed_tables_init
1935+ self.xed_tables_init.restype = None
1936+ self.xed_tables_init.argtypes = []
1937+
1938+ self.xed_decoded_inst_zero = self.libxed.xed_decoded_inst_zero
1939+ self.xed_decoded_inst_zero.restype = None
1940+ self.xed_decoded_inst_zero.argtypes = [ c_void_p ]
1941+
1942+ self.xed_operand_values_set_mode = self.libxed.xed_operand_values_set_mode
1943+ self.xed_operand_values_set_mode.restype = None
1944+ self.xed_operand_values_set_mode.argtypes = [ c_void_p, c_void_p ]
1945+
1946+ self.xed_decoded_inst_zero_keep_mode = self.libxed.xed_decoded_inst_zero_keep_mode
1947+ self.xed_decoded_inst_zero_keep_mode.restype = None
1948+ self.xed_decoded_inst_zero_keep_mode.argtypes = [ c_void_p ]
1949+
1950+ self.xed_decode = self.libxed.xed_decode
1951+ self.xed_decode.restype = c_int
1952+ self.xed_decode.argtypes = [ c_void_p, c_void_p, c_uint ]
1953+
1954+ self.xed_format_context = self.libxed.xed_format_context
1955+ self.xed_format_context.restype = c_uint
1956+ self.xed_format_context.argtypes = [ c_int, c_void_p, c_void_p, c_int, c_ulonglong, c_void_p, c_void_p ]
1957+
1958+ self.xed_tables_init()
1959+
1960+ def Instruction(self):
1961+ return XEDInstruction(self)
1962+
1963+ def SetMode(self, inst, mode):
1964+ if mode:
1965+ inst.state.mode = 4 # 32-bit
1966+ inst.state.width = 4 # 4 bytes
1967+ else:
1968+ inst.state.mode = 1 # 64-bit
1969+ inst.state.width = 8 # 8 bytes
1970+ self.xed_operand_values_set_mode(inst.xedp, inst.statep)
1971+
1972+ def DisassembleOne(self, inst, bytes_ptr, bytes_cnt, ip):
1973+ self.xed_decoded_inst_zero_keep_mode(inst.xedp)
1974+ err = self.xed_decode(inst.xedp, bytes_ptr, bytes_cnt)
1975+ if err:
1976+ return 0, ""
1977+ # Use AT&T mode (2), alternative is Intel (3)
1978+ ok = self.xed_format_context(2, inst.xedp, inst.bufferp, sizeof(inst.buffer), ip, 0, 0)
1979+ if not ok:
1980+ return 0, ""
1981+ # Return instruction length and the disassembled instruction text
1982+ # For now, assume the length is in byte 166
1983+ return inst.xedd[166], inst.buffer.value
1984+
1985+def TryOpen(file_name):
1986+ try:
1987+ return open(file_name, "rb")
1988+ except:
1989+ return None
1990+
1991+def Is64Bit(f):
1992+ result = sizeof(c_void_p)
1993+ # ELF support only
1994+ pos = f.tell()
1995+ f.seek(0)
1996+ header = f.read(7)
1997+ f.seek(pos)
1998+ magic = header[0:4]
1999+ eclass = ord(header[4])
2000+ encoding = ord(header[5])
2001+ version = ord(header[6])
2002+ if magic == chr(127) + "ELF" and eclass > 0 and eclass < 3 and encoding > 0 and encoding < 3 and version == 1:
2003+ result = True if eclass == 2 else False
2004+ return result
2005+
14902006 # Global data
14912007
14922008 class Glb():
@@ -1495,9 +2011,40 @@ class Glb(): · 2 unmodified lines
14952011 self.dbref = dbref
14962012 self.db = db
14972013 self.dbname = dbname
2014+ self.home_dir = os.path.expanduser("~")
2015+ self.buildid_dir = os.getenv("PERF_BUILDID_DIR")
2016+ if self.buildid_dir:
2017+ self.buildid_dir += "/.build-id/"
2018+ else:
2019+ self.buildid_dir = self.home_dir + "/.debug/.build-id/"
14982020 self.app = None
14992021 self.mainwindow = None
15002022 self.instances_to_shutdown_on_exit = weakref.WeakSet()
2023+ try:
2024+ self.disassembler = LibXED()
2025+ self.have_disassembler = True
2026+ except:
2027+ self.have_disassembler = False
2028+
2029+ def FileFromBuildId(self, build_id):
2030+ file_name = self.buildid_dir + build_id[0:2] + "/" + build_id[2:] + "/elf"
2031+ return TryOpen(file_name)
2032+
2033+ def FileFromNamesAndBuildId(self, short_name, long_name, build_id):
2034+ # Assume current machine i.e. no support for virtualization
2035+ if short_name[0:7] == "[kernel" and os.path.basename(long_name) == "kcore":
2036+ file_name = os.getenv("PERF_KCORE")
2037+ f = TryOpen(file_name) if file_name else None
2038+ if f:
2039+ return f
2040+ # For now, no special handling if long_name is /proc/kcore
2041+ f = TryOpen(long_name)
2042+ if f:
2043+ return f
2044+ f = self.FileFromBuildId(build_id)
2045+ if f:
2046+ return f
2047+ return None
15012048
15022049 def AddInstanceToShutdownOnExit(self, instance):
15032050 self.instances_to_shutdown_on_exit.add(instance)