Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Adrian Hunter and committed by
Arnaldo Carvalho de Melo
76099f98 8392b74b

+547
+547
tools/perf/scripts/python/exported-sql-viewer.py
··· 46 46 # 'Branch Count' is the total number of branches for that function and all 47 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 + 49 91 import sys 50 92 import weakref 51 93 import threading ··· 103 61 from multiprocessing import Process, Array, Value, Event 104 62 105 63 # Data formatting helpers 64 + 65 + def tohex(ip): 66 + if ip < 0: 67 + ip += 1 << 64 68 + return "%x" % ip 69 + 70 + def offstr(offset): 71 + if offset: 72 + return "+0x%x" % offset 73 + return "" 106 74 107 75 def dsoname(name): 108 76 if name == "[kernel.kallsyms]": ··· 1129 1077 self.in_progress = True 1130 1078 self.start = self.model.FetchMoreRecords(self.Target()) 1131 1079 1080 + # Brance data model level two item 1081 + 1082 + class BranchLevelTwoItem(): 1083 + 1084 + def __init__(self, row, text, parent_item): 1085 + self.row = row 1086 + self.parent_item = parent_item 1087 + self.data = [""] * 8 1088 + self.data[7] = text 1089 + self.level = 2 1090 + 1091 + def getParentItem(self): 1092 + return self.parent_item 1093 + 1094 + def getRow(self): 1095 + return self.row 1096 + 1097 + def childCount(self): 1098 + return 0 1099 + 1100 + def hasChildren(self): 1101 + return False 1102 + 1103 + def getData(self, column): 1104 + return self.data[column] 1105 + 1106 + # Brance data model level one item 1107 + 1108 + class BranchLevelOneItem(): 1109 + 1110 + def __init__(self, glb, row, data, parent_item): 1111 + self.glb = glb 1112 + self.row = row 1113 + self.parent_item = parent_item 1114 + self.child_count = 0 1115 + self.child_items = [] 1116 + self.data = data[1:] 1117 + self.dbid = data[0] 1118 + self.level = 1 1119 + self.query_done = False 1120 + 1121 + def getChildItem(self, row): 1122 + return self.child_items[row] 1123 + 1124 + def getParentItem(self): 1125 + return self.parent_item 1126 + 1127 + def getRow(self): 1128 + return self.row 1129 + 1130 + def Select(self): 1131 + self.query_done = True 1132 + 1133 + if not self.glb.have_disassembler: 1134 + return 1135 + 1136 + query = QSqlQuery(self.glb.db) 1137 + 1138 + QueryExec(query, "SELECT cpu, to_dso_id, to_symbol_id, to_sym_offset, short_name, long_name, build_id, sym_start, to_ip" 1139 + " FROM samples" 1140 + " INNER JOIN dsos ON samples.to_dso_id = dsos.id" 1141 + " INNER JOIN symbols ON samples.to_symbol_id = symbols.id" 1142 + " WHERE samples.id = " + str(self.dbid)) 1143 + if not query.next(): 1144 + return 1145 + cpu = query.value(0) 1146 + dso = query.value(1) 1147 + sym = query.value(2) 1148 + if dso == 0 or sym == 0: 1149 + return 1150 + off = query.value(3) 1151 + short_name = query.value(4) 1152 + long_name = query.value(5) 1153 + build_id = query.value(6) 1154 + sym_start = query.value(7) 1155 + ip = query.value(8) 1156 + 1157 + QueryExec(query, "SELECT samples.dso_id, symbol_id, sym_offset, sym_start" 1158 + " FROM samples" 1159 + " INNER JOIN symbols ON samples.symbol_id = symbols.id" 1160 + " WHERE samples.id > " + str(self.dbid) + " AND cpu = " + str(cpu) + 1161 + " ORDER BY samples.id" 1162 + " LIMIT 1") 1163 + if not query.next(): 1164 + return 1165 + if query.value(0) != dso: 1166 + # Cannot disassemble from one dso to another 1167 + return 1168 + bsym = query.value(1) 1169 + boff = query.value(2) 1170 + bsym_start = query.value(3) 1171 + if bsym == 0: 1172 + return 1173 + tot = bsym_start + boff + 1 - sym_start - off 1174 + if tot <= 0 or tot > 16384: 1175 + return 1176 + 1177 + inst = self.glb.disassembler.Instruction() 1178 + f = self.glb.FileFromNamesAndBuildId(short_name, long_name, build_id) 1179 + if not f: 1180 + return 1181 + mode = 0 if Is64Bit(f) else 1 1182 + self.glb.disassembler.SetMode(inst, mode) 1183 + 1184 + buf_sz = tot + 16 1185 + buf = create_string_buffer(tot + 16) 1186 + f.seek(sym_start + off) 1187 + buf.value = f.read(buf_sz) 1188 + buf_ptr = addressof(buf) 1189 + i = 0 1190 + while tot > 0: 1191 + cnt, text = self.glb.disassembler.DisassembleOne(inst, buf_ptr, buf_sz, ip) 1192 + if cnt: 1193 + byte_str = tohex(ip).rjust(16) 1194 + for k in xrange(cnt): 1195 + byte_str += " %02x" % ord(buf[i]) 1196 + i += 1 1197 + while k < 15: 1198 + byte_str += " " 1199 + k += 1 1200 + self.child_items.append(BranchLevelTwoItem(0, byte_str + " " + text, self)) 1201 + self.child_count += 1 1202 + else: 1203 + return 1204 + buf_ptr += cnt 1205 + tot -= cnt 1206 + buf_sz -= cnt 1207 + ip += cnt 1208 + 1209 + def childCount(self): 1210 + if not self.query_done: 1211 + self.Select() 1212 + if not self.child_count: 1213 + return -1 1214 + return self.child_count 1215 + 1216 + def hasChildren(self): 1217 + if not self.query_done: 1218 + return True 1219 + return self.child_count > 0 1220 + 1221 + def getData(self, column): 1222 + return self.data[column] 1223 + 1224 + # Brance data model root item 1225 + 1226 + class BranchRootItem(): 1227 + 1228 + def __init__(self): 1229 + self.child_count = 0 1230 + self.child_items = [] 1231 + self.level = 0 1232 + 1233 + def getChildItem(self, row): 1234 + return self.child_items[row] 1235 + 1236 + def getParentItem(self): 1237 + return None 1238 + 1239 + def getRow(self): 1240 + return 0 1241 + 1242 + def childCount(self): 1243 + return self.child_count 1244 + 1245 + def hasChildren(self): 1246 + return self.child_count > 0 1247 + 1248 + def getData(self, column): 1249 + return "" 1250 + 1251 + # Branch data preparation 1252 + 1253 + def BranchDataPrep(query): 1254 + data = [] 1255 + for i in xrange(0, 8): 1256 + data.append(query.value(i)) 1257 + data.append(tohex(query.value(8)).rjust(16) + " " + query.value(9) + offstr(query.value(10)) + 1258 + " (" + dsoname(query.value(11)) + ")" + " -> " + 1259 + tohex(query.value(12)) + " " + query.value(13) + offstr(query.value(14)) + 1260 + " (" + dsoname(query.value(15)) + ")") 1261 + return data 1262 + 1263 + # Branch data model 1264 + 1265 + class BranchModel(TreeModel): 1266 + 1267 + progress = Signal(object) 1268 + 1269 + def __init__(self, glb, event_id, where_clause, parent=None): 1270 + super(BranchModel, self).__init__(BranchRootItem(), parent) 1271 + self.glb = glb 1272 + self.event_id = event_id 1273 + self.more = True 1274 + self.populated = 0 1275 + sql = ("SELECT samples.id, time, cpu, comm, pid, tid, branch_types.name," 1276 + " CASE WHEN in_tx = '0' THEN 'No' ELSE 'Yes' END," 1277 + " ip, symbols.name, sym_offset, dsos.short_name," 1278 + " to_ip, to_symbols.name, to_sym_offset, to_dsos.short_name" 1279 + " FROM samples" 1280 + " INNER JOIN comms ON comm_id = comms.id" 1281 + " INNER JOIN threads ON thread_id = threads.id" 1282 + " INNER JOIN branch_types ON branch_type = branch_types.id" 1283 + " INNER JOIN symbols ON symbol_id = symbols.id" 1284 + " INNER JOIN symbols to_symbols ON to_symbol_id = to_symbols.id" 1285 + " INNER JOIN dsos ON samples.dso_id = dsos.id" 1286 + " INNER JOIN dsos AS to_dsos ON samples.to_dso_id = to_dsos.id" 1287 + " WHERE samples.id > $$last_id$$" + where_clause + 1288 + " AND evsel_id = " + str(self.event_id) + 1289 + " ORDER BY samples.id" 1290 + " LIMIT " + str(glb_chunk_sz)) 1291 + self.fetcher = SQLFetcher(glb, sql, BranchDataPrep, self.AddSample) 1292 + self.fetcher.done.connect(self.Update) 1293 + self.fetcher.Fetch(glb_chunk_sz) 1294 + 1295 + def columnCount(self, parent=None): 1296 + return 8 1297 + 1298 + def columnHeader(self, column): 1299 + return ("Time", "CPU", "Command", "PID", "TID", "Branch Type", "In Tx", "Branch")[column] 1300 + 1301 + def columnFont(self, column): 1302 + if column != 7: 1303 + return None 1304 + return QFont("Monospace") 1305 + 1306 + def DisplayData(self, item, index): 1307 + if item.level == 1: 1308 + self.FetchIfNeeded(item.row) 1309 + return item.getData(index.column()) 1310 + 1311 + def AddSample(self, data): 1312 + child = BranchLevelOneItem(self.glb, self.populated, data, self.root) 1313 + self.root.child_items.append(child) 1314 + self.populated += 1 1315 + 1316 + def Update(self, fetched): 1317 + if not fetched: 1318 + self.more = False 1319 + self.progress.emit(0) 1320 + child_count = self.root.child_count 1321 + count = self.populated - child_count 1322 + if count > 0: 1323 + parent = QModelIndex() 1324 + self.beginInsertRows(parent, child_count, child_count + count - 1) 1325 + self.insertRows(child_count, count, parent) 1326 + self.root.child_count += count 1327 + self.endInsertRows() 1328 + self.progress.emit(self.root.child_count) 1329 + 1330 + def FetchMoreRecords(self, count): 1331 + current = self.root.child_count 1332 + if self.more: 1333 + self.fetcher.Fetch(count) 1334 + else: 1335 + self.progress.emit(0) 1336 + return current 1337 + 1338 + def HasMoreRecords(self): 1339 + return self.more 1340 + 1341 + # Branch window 1342 + 1343 + class BranchWindow(QMdiSubWindow): 1344 + 1345 + def __init__(self, glb, event_id, name, where_clause, parent=None): 1346 + super(BranchWindow, self).__init__(parent) 1347 + 1348 + model_name = "Branch Events " + str(event_id) 1349 + if len(where_clause): 1350 + model_name = where_clause + " " + model_name 1351 + 1352 + self.model = LookupCreateModel(model_name, lambda: BranchModel(glb, event_id, where_clause)) 1353 + 1354 + self.view = QTreeView() 1355 + self.view.setUniformRowHeights(True) 1356 + self.view.setModel(self.model) 1357 + 1358 + self.ResizeColumnsToContents() 1359 + 1360 + self.find_bar = FindBar(self, self, True) 1361 + 1362 + self.finder = ChildDataItemFinder(self.model.root) 1363 + 1364 + self.fetch_bar = FetchMoreRecordsBar(self.model, self) 1365 + 1366 + self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget()) 1367 + 1368 + self.setWidget(self.vbox.Widget()) 1369 + 1370 + AddSubWindow(glb.mainwindow.mdi_area, self, name + " Branch Events") 1371 + 1372 + def ResizeColumnToContents(self, column, n): 1373 + # Using the view's resizeColumnToContents() here is extrememly slow 1374 + # so implement a crude alternative 1375 + mm = "MM" if column else "MMMM" 1376 + font = self.view.font() 1377 + metrics = QFontMetrics(font) 1378 + max = 0 1379 + for row in xrange(n): 1380 + val = self.model.root.child_items[row].data[column] 1381 + len = metrics.width(str(val) + mm) 1382 + max = len if len > max else max 1383 + val = self.model.columnHeader(column) 1384 + len = metrics.width(str(val) + mm) 1385 + max = len if len > max else max 1386 + self.view.setColumnWidth(column, max) 1387 + 1388 + def ResizeColumnsToContents(self): 1389 + n = min(self.model.root.child_count, 100) 1390 + if n < 1: 1391 + # No data yet, so connect a signal to notify when there is 1392 + self.model.rowsInserted.connect(self.UpdateColumnWidths) 1393 + return 1394 + columns = self.model.columnCount() 1395 + for i in xrange(columns): 1396 + self.ResizeColumnToContents(i, n) 1397 + 1398 + def UpdateColumnWidths(self, *x): 1399 + # This only needs to be done once, so disconnect the signal now 1400 + self.model.rowsInserted.disconnect(self.UpdateColumnWidths) 1401 + self.ResizeColumnsToContents() 1402 + 1403 + def Find(self, value, direction, pattern, context): 1404 + self.view.setFocus() 1405 + self.find_bar.Busy() 1406 + self.finder.Find(value, direction, pattern, context, self.FindDone) 1407 + 1408 + def FindDone(self, row): 1409 + self.find_bar.Idle() 1410 + if row >= 0: 1411 + self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex())) 1412 + else: 1413 + self.find_bar.NotFound() 1414 + 1415 + # Event list 1416 + 1417 + def GetEventList(db): 1418 + events = [] 1419 + query = QSqlQuery(db) 1420 + QueryExec(query, "SELECT name FROM selected_events WHERE id > 0 ORDER BY id") 1421 + while query.next(): 1422 + events.append(query.value(0)) 1423 + return events 1424 + 1132 1425 # SQL data preparation 1133 1426 1134 1427 def SQLTableDataPrep(query, count): ··· 1845 1448 reports_menu = menu.addMenu("&Reports") 1846 1449 reports_menu.addAction(CreateAction("Context-Sensitive Call &Graph", "Create a new window containing a context-sensitive call graph", self.NewCallGraph, self)) 1847 1450 1451 + self.EventMenu(GetEventList(glb.db), reports_menu) 1452 + 1848 1453 self.TableMenu(GetTableList(glb), menu) 1849 1454 1850 1455 self.window_menu = WindowMenu(self.mdi_area, menu) ··· 1875 1476 win = self.mdi_area.activeSubWindow() 1876 1477 EnlargeFont(win.view) 1877 1478 1479 + def EventMenu(self, events, reports_menu): 1480 + branches_events = 0 1481 + for event in events: 1482 + event = event.split(":")[0] 1483 + if event == "branches": 1484 + branches_events += 1 1485 + dbid = 0 1486 + for event in events: 1487 + dbid += 1 1488 + event = event.split(":")[0] 1489 + if event == "branches": 1490 + label = "All branches" if branches_events == 1 else "All branches " + "(id=" + dbid + ")" 1491 + reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewBranchView(x), self)) 1492 + 1878 1493 def TableMenu(self, tables, menu): 1879 1494 table_menu = menu.addMenu("&Tables") 1880 1495 for table in tables: ··· 1897 1484 def NewCallGraph(self): 1898 1485 CallGraphWindow(self.glb, self) 1899 1486 1487 + def NewBranchView(self, event_id): 1488 + BranchWindow(self.glb, event_id, "", "", self) 1489 + 1900 1490 def NewTableView(self, table_name): 1901 1491 TableWindow(self.glb, table_name, self) 1492 + 1493 + # XED Disassembler 1494 + 1495 + class xed_state_t(Structure): 1496 + 1497 + _fields_ = [ 1498 + ("mode", c_int), 1499 + ("width", c_int) 1500 + ] 1501 + 1502 + class XEDInstruction(): 1503 + 1504 + def __init__(self, libxed): 1505 + # Current xed_decoded_inst_t structure is 192 bytes. Use 512 to allow for future expansion 1506 + xedd_t = c_byte * 512 1507 + self.xedd = xedd_t() 1508 + self.xedp = addressof(self.xedd) 1509 + libxed.xed_decoded_inst_zero(self.xedp) 1510 + self.state = xed_state_t() 1511 + self.statep = addressof(self.state) 1512 + # Buffer for disassembled instruction text 1513 + self.buffer = create_string_buffer(256) 1514 + self.bufferp = addressof(self.buffer) 1515 + 1516 + class LibXED(): 1517 + 1518 + def __init__(self): 1519 + self.libxed = CDLL("libxed.so") 1520 + 1521 + self.xed_tables_init = self.libxed.xed_tables_init 1522 + self.xed_tables_init.restype = None 1523 + self.xed_tables_init.argtypes = [] 1524 + 1525 + self.xed_decoded_inst_zero = self.libxed.xed_decoded_inst_zero 1526 + self.xed_decoded_inst_zero.restype = None 1527 + self.xed_decoded_inst_zero.argtypes = [ c_void_p ] 1528 + 1529 + self.xed_operand_values_set_mode = self.libxed.xed_operand_values_set_mode 1530 + self.xed_operand_values_set_mode.restype = None 1531 + self.xed_operand_values_set_mode.argtypes = [ c_void_p, c_void_p ] 1532 + 1533 + self.xed_decoded_inst_zero_keep_mode = self.libxed.xed_decoded_inst_zero_keep_mode 1534 + self.xed_decoded_inst_zero_keep_mode.restype = None 1535 + self.xed_decoded_inst_zero_keep_mode.argtypes = [ c_void_p ] 1536 + 1537 + self.xed_decode = self.libxed.xed_decode 1538 + self.xed_decode.restype = c_int 1539 + self.xed_decode.argtypes = [ c_void_p, c_void_p, c_uint ] 1540 + 1541 + self.xed_format_context = self.libxed.xed_format_context 1542 + self.xed_format_context.restype = c_uint 1543 + self.xed_format_context.argtypes = [ c_int, c_void_p, c_void_p, c_int, c_ulonglong, c_void_p, c_void_p ] 1544 + 1545 + self.xed_tables_init() 1546 + 1547 + def Instruction(self): 1548 + return XEDInstruction(self) 1549 + 1550 + def SetMode(self, inst, mode): 1551 + if mode: 1552 + inst.state.mode = 4 # 32-bit 1553 + inst.state.width = 4 # 4 bytes 1554 + else: 1555 + inst.state.mode = 1 # 64-bit 1556 + inst.state.width = 8 # 8 bytes 1557 + self.xed_operand_values_set_mode(inst.xedp, inst.statep) 1558 + 1559 + def DisassembleOne(self, inst, bytes_ptr, bytes_cnt, ip): 1560 + self.xed_decoded_inst_zero_keep_mode(inst.xedp) 1561 + err = self.xed_decode(inst.xedp, bytes_ptr, bytes_cnt) 1562 + if err: 1563 + return 0, "" 1564 + # Use AT&T mode (2), alternative is Intel (3) 1565 + ok = self.xed_format_context(2, inst.xedp, inst.bufferp, sizeof(inst.buffer), ip, 0, 0) 1566 + if not ok: 1567 + return 0, "" 1568 + # Return instruction length and the disassembled instruction text 1569 + # For now, assume the length is in byte 166 1570 + return inst.xedd[166], inst.buffer.value 1571 + 1572 + def TryOpen(file_name): 1573 + try: 1574 + return open(file_name, "rb") 1575 + except: 1576 + return None 1577 + 1578 + def Is64Bit(f): 1579 + result = sizeof(c_void_p) 1580 + # ELF support only 1581 + pos = f.tell() 1582 + f.seek(0) 1583 + header = f.read(7) 1584 + f.seek(pos) 1585 + magic = header[0:4] 1586 + eclass = ord(header[4]) 1587 + encoding = ord(header[5]) 1588 + version = ord(header[6]) 1589 + if magic == chr(127) + "ELF" and eclass > 0 and eclass < 3 and encoding > 0 and encoding < 3 and version == 1: 1590 + result = True if eclass == 2 else False 1591 + return result 1902 1592 1903 1593 # Global data 1904 1594 ··· 2011 1495 self.dbref = dbref 2012 1496 self.db = db 2013 1497 self.dbname = dbname 1498 + self.home_dir = os.path.expanduser("~") 1499 + self.buildid_dir = os.getenv("PERF_BUILDID_DIR") 1500 + if self.buildid_dir: 1501 + self.buildid_dir += "/.build-id/" 1502 + else: 1503 + self.buildid_dir = self.home_dir + "/.debug/.build-id/" 2014 1504 self.app = None 2015 1505 self.mainwindow = None 2016 1506 self.instances_to_shutdown_on_exit = weakref.WeakSet() 1507 + try: 1508 + self.disassembler = LibXED() 1509 + self.have_disassembler = True 1510 + except: 1511 + self.have_disassembler = False 1512 + 1513 + def FileFromBuildId(self, build_id): 1514 + file_name = self.buildid_dir + build_id[0:2] + "/" + build_id[2:] + "/elf" 1515 + return TryOpen(file_name) 1516 + 1517 + def FileFromNamesAndBuildId(self, short_name, long_name, build_id): 1518 + # Assume current machine i.e. no support for virtualization 1519 + if short_name[0:7] == "[kernel" and os.path.basename(long_name) == "kcore": 1520 + file_name = os.getenv("PERF_KCORE") 1521 + f = TryOpen(file_name) if file_name else None 1522 + if f: 1523 + return f 1524 + # For now, no special handling if long_name is /proc/kcore 1525 + f = TryOpen(long_name) 1526 + if f: 1527 + return f 1528 + f = self.FileFromBuildId(build_id) 1529 + if f: 1530 + return f 1531 + return None 2017 1532 2018 1533 def AddInstanceToShutdownOnExit(self, instance): 2019 1534 self.instances_to_shutdown_on_exit.add(instance)