aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/scripts/python/exported-sql-viewer.py
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2018-10-23 03:59:49 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2018-10-23 13:47:14 -0400
commit76099f98aea4606f7c96b8d2366b46840529d08f (patch)
tree3b5e68a9d4a25c9ac6f4b9b70578de00685d0636 /tools/perf/scripts/python/exported-sql-viewer.py
parent8392b74b575c38fa5d50d1fe07fa9a4bcea93862 (diff)
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 Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Jiri Olsa <jolsa@redhat.com> Link: http://lkml.kernel.org/r/20181023075949.18920-1-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/scripts/python/exported-sql-viewer.py')
-rwxr-xr-xtools/perf/scripts/python/exported-sql-viewer.py547
1 files changed, 547 insertions, 0 deletions
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index ef822d850109..24cb0bd56afa 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -46,6 +46,48 @@
46# 'Branch Count' is the total number of branches for that function and all 46# 'Branch Count' is the total number of branches for that function and all
47# functions that it calls 47# functions that it calls
48 48
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
49import sys 91import sys
50import weakref 92import weakref
51import threading 93import threading
@@ -62,6 +104,16 @@ from multiprocessing import Process, Array, Value, Event
62 104
63# Data formatting helpers 105# Data formatting helpers
64 106
107def tohex(ip):
108 if ip < 0:
109 ip += 1 << 64
110 return "%x" % ip
111
112def offstr(offset):
113 if offset:
114 return "+0x%x" % offset
115 return ""
116
65def dsoname(name): 117def dsoname(name):
66 if name == "[kernel.kallsyms]": 118 if name == "[kernel.kallsyms]":
67 return "[kernel]" 119 return "[kernel]"
@@ -1077,6 +1129,351 @@ class FetchMoreRecordsBar():
1077 self.in_progress = True 1129 self.in_progress = True
1078 self.start = self.model.FetchMoreRecords(self.Target()) 1130 self.start = self.model.FetchMoreRecords(self.Target())
1079 1131
1132# Brance data model level two item
1133
1134class 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
1160class 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
1278class 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
1305def 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
1317class 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
1395class 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
1469def 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
1080# SQL data preparation 1477# SQL data preparation
1081 1478
1082def SQLTableDataPrep(query, count): 1479def SQLTableDataPrep(query, count):
@@ -1448,6 +1845,8 @@ class MainWindow(QMainWindow):
1448 reports_menu = menu.addMenu("&Reports") 1845 reports_menu = menu.addMenu("&Reports")
1449 reports_menu.addAction(CreateAction("Context-Sensitive Call &Graph", "Create a new window containing a context-sensitive call graph", self.NewCallGraph, self)) 1846 reports_menu.addAction(CreateAction("Context-Sensitive Call &Graph", "Create a new window containing a context-sensitive call graph", self.NewCallGraph, self))
1450 1847
1848 self.EventMenu(GetEventList(glb.db), reports_menu)
1849
1451 self.TableMenu(GetTableList(glb), menu) 1850 self.TableMenu(GetTableList(glb), menu)
1452 1851
1453 self.window_menu = WindowMenu(self.mdi_area, menu) 1852 self.window_menu = WindowMenu(self.mdi_area, menu)
@@ -1476,6 +1875,20 @@ class MainWindow(QMainWindow):
1476 win = self.mdi_area.activeSubWindow() 1875 win = self.mdi_area.activeSubWindow()
1477 EnlargeFont(win.view) 1876 EnlargeFont(win.view)
1478 1877
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
1479 def TableMenu(self, tables, menu): 1892 def TableMenu(self, tables, menu):
1480 table_menu = menu.addMenu("&Tables") 1893 table_menu = menu.addMenu("&Tables")
1481 for table in tables: 1894 for table in tables:
@@ -1484,9 +1897,112 @@ class MainWindow(QMainWindow):
1484 def NewCallGraph(self): 1897 def NewCallGraph(self):
1485 CallGraphWindow(self.glb, self) 1898 CallGraphWindow(self.glb, self)
1486 1899
1900 def NewBranchView(self, event_id):
1901 BranchWindow(self.glb, event_id, "", "", self)
1902
1487 def NewTableView(self, table_name): 1903 def NewTableView(self, table_name):
1488 TableWindow(self.glb, table_name, self) 1904 TableWindow(self.glb, table_name, self)
1489 1905
1906# XED Disassembler
1907
1908class xed_state_t(Structure):
1909
1910 _fields_ = [
1911 ("mode", c_int),
1912 ("width", c_int)
1913 ]
1914
1915class 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
1929class 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
1985def TryOpen(file_name):
1986 try:
1987 return open(file_name, "rb")
1988 except:
1989 return None
1990
1991def 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
1490# Global data 2006# Global data
1491 2007
1492class Glb(): 2008class Glb():
@@ -1495,9 +2011,40 @@ class Glb():
1495 self.dbref = dbref 2011 self.dbref = dbref
1496 self.db = db 2012 self.db = db
1497 self.dbname = dbname 2013 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/"
1498 self.app = None 2020 self.app = None
1499 self.mainwindow = None 2021 self.mainwindow = None
1500 self.instances_to_shutdown_on_exit = weakref.WeakSet() 2022 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
1501 2048
1502 def AddInstanceToShutdownOnExit(self, instance): 2049 def AddInstanceToShutdownOnExit(self, instance):
1503 self.instances_to_shutdown_on_exit.add(instance) 2050 self.instances_to_shutdown_on_exit.add(instance)