5030 lines · 153.7 KB · Python
RawDownload
			self.FindSelect()		if not len(self.rows):			return -1		return self.rows[self.pos] 	def FindThread(self):		if self.direction == 0 or self.value != self.last_value or self.pattern != self.last_pattern:			row = self.FindValue()		elif len(self.rows):			if self.direction > 0:				self.pos += 1				if self.pos >= len(self.rows):					self.pos = 0			else:				self.pos -= 1				if self.pos < 0:					self.pos = len(self.rows) - 1			row = self.rows[self.pos]		else:			row = -1		return (True, row) 	def Find(self, value, direction, pattern, context, callback):		self.value, self.direction, self.pattern, self.last_value, self.last_pattern = (value, direction,pattern, self.value, self.pattern)		# Use a thread so the UI is not blocked		thread = Thread(self.FindThread)		thread.done.connect(lambda row, t=thread, c=callback: self.FindDone(t, c, row), Qt.QueuedConnection)		thread.start() 	def FindDone(self, thread, callback, row):		callback(row) # Number of database records to fetch in one go glb_chunk_sz = 10000 # Background process for SQL data fetcher class SQLFetcherProcess(): 	def __init__(self, dbref, sql, buffer, head, tail, fetch_count, fetching_done, process_target, wait_event, fetched_event, prep):		# Need a unique connection name		conn_name = "SQLFetcher" + str(os.getpid())		self.db, dbname = dbref.Open(conn_name)		self.sql = sql		self.buffer = buffer		self.head = head		self.tail = tail		self.fetch_count = fetch_count		self.fetching_done = fetching_done		self.process_target = process_target		self.wait_event = wait_event		self.fetched_event = fetched_event		self.prep = prep		self.query = QSqlQuery(self.db)		self.query_limit = 0 if "$$last_id$$" in sql else 2		self.last_id = -1		self.fetched = 0		self.more = True		self.local_head = self.head.value		self.local_tail = self.tail.value 	def Select(self):		if self.query_limit:			if self.query_limit == 1:				return			self.query_limit -= 1		stmt = self.sql.replace("$$last_id$$", str(self.last_id))		QueryExec(self.query, stmt) 	def Next(self):		if not self.query.next():			self.Select()			if not self.query.next():				return None		self.last_id = self.query.value(0)		return self.prep(self.query) 	def WaitForTarget(self):		while True:			self.wait_event.clear()			target = self.process_target.value			if target > self.fetched or target < 0:				break			self.wait_event.wait()		return target 	def HasSpace(self, sz):		if self.local_tail <= self.local_head:			space = len(self.buffer) - self.local_head			if space > sz:				return True			if space >= glb_nsz:				# Use 0 (or space < glb_nsz) to mean there is no more at the top of the buffer				nd = pickle.dumps(0, pickle.HIGHEST_PROTOCOL)				self.buffer[self.local_head : self.local_head + len(nd)] = nd			self.local_head = 0		if self.local_tail - self.local_head > sz:			return True		return False 	def WaitForSpace(self, sz):		if self.HasSpace(sz):			return		while True:			self.wait_event.clear()			self.local_tail = self.tail.value			if self.HasSpace(sz):				return			self.wait_event.wait() 	def AddToBuffer(self, obj):		d = pickle.dumps(obj, pickle.HIGHEST_PROTOCOL)		n = len(d)		nd = pickle.dumps(n, pickle.HIGHEST_PROTOCOL)		sz = n + glb_nsz		self.WaitForSpace(sz)		pos = self.local_head		self.buffer[pos : pos + len(nd)] = nd		self.buffer[pos + glb_nsz : pos + sz] = d		self.local_head += sz 	def FetchBatch(self, batch_size):		fetched = 0		while batch_size > fetched:			obj = self.Next()			if obj is None:				self.more = False				break			self.AddToBuffer(obj)			fetched += 1		if fetched:			self.fetched += fetched			with self.fetch_count.get_lock():				self.fetch_count.value += fetched			self.head.value = self.local_head			self.fetched_event.set() 	def Run(self):		while self.more:			target = self.WaitForTarget()			if target < 0:				break			batch_size = min(glb_chunk_sz, target - self.fetched)			self.FetchBatch(batch_size)		self.fetching_done.value = True		self.fetched_event.set() def SQLFetcherFn(*x):	process = SQLFetcherProcess(*x)	process.Run() # SQL data fetcher class SQLFetcher(QObject): 	done = Signal(object) 	def __init__(self, glb, sql, prep, process_data, parent=None):		super(SQLFetcher, self).__init__(parent)		self.process_data = process_data		self.more = True		self.target = 0		self.last_target = 0		self.fetched = 0		self.buffer_size = 16 * 1024 * 1024		self.buffer = Array(c_char, self.buffer_size, lock=False)		self.head = Value(c_longlong)		self.tail = Value(c_longlong)		self.local_tail = 0		self.fetch_count = Value(c_longlong)		self.fetching_done = Value(c_bool)		self.last_count = 0		self.process_target = Value(c_longlong)		self.wait_event = Event()		self.fetched_event = Event()		glb.AddInstanceToShutdownOnExit(self)		self.process = Process(target=SQLFetcherFn, args=(glb.dbref, sql, self.buffer, self.head, self.tail, self.fetch_count, self.fetching_done, self.process_target, self.wait_event, self.fetched_event, prep))		self.process.start()		self.thread = Thread(self.Thread)		self.thread.done.connect(self.ProcessData, Qt.QueuedConnection)		self.thread.start() 	def Shutdown(self):		# Tell the thread and process to exit		self.process_target.value = -1		self.wait_event.set()		self.more = False		self.fetching_done.value = True		self.fetched_event.set() 	def Thread(self):		if not self.more:			return True, 0		while True:			self.fetched_event.clear()			fetch_count = self.fetch_count.value			if fetch_count != self.last_count:				break			if self.fetching_done.value:				self.more = False				return True, 0			self.fetched_event.wait()		count = fetch_count - self.last_count		self.last_count = fetch_count		self.fetched += count		return False, count 	def Fetch(self, nr):		if not self.more:			# -1 inidcates there are no more			return -1		result = self.fetched		extra = result + nr - self.target		if extra > 0:			self.target += extra			# process_target < 0 indicates shutting down			if self.process_target.value >= 0:				self.process_target.value = self.target			self.wait_event.set()		return result 	def RemoveFromBuffer(self):		pos = self.local_tail		if len(self.buffer) - pos < glb_nsz:			pos = 0		n = pickle.loads(self.buffer[pos : pos + glb_nsz])		if n == 0:			pos = 0			n = pickle.loads(self.buffer[0 : glb_nsz])		pos += glb_nsz		obj = pickle.loads(self.buffer[pos : pos + n])		self.local_tail = pos + n		return obj 	def ProcessData(self, count):		for i in xrange(count):			obj = self.RemoveFromBuffer()			self.process_data(obj)		self.tail.value = self.local_tail		self.wait_event.set()		self.done.emit(count) # Fetch more records bar class FetchMoreRecordsBar(): 	def __init__(self, model, parent):		self.model = model 		self.label = QLabel("Number of records (x " + "{:,}".format(glb_chunk_sz) + ") to fetch:")		self.label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 		self.fetch_count = QSpinBox()		self.fetch_count.setRange(1, 1000000)		self.fetch_count.setValue(10)		self.fetch_count.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 		self.fetch = QPushButton("Go!")		self.fetch.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)		self.fetch.released.connect(self.FetchMoreRecords) 		self.progress = QProgressBar()		self.progress.setRange(0, 100)		self.progress.hide() 		self.done_label = QLabel("All records fetched")		self.done_label.hide() 		self.spacer = QLabel("") 		self.close_button = QToolButton()		self.close_button.setIcon(parent.style().standardIcon(QStyle.SP_DockWidgetCloseButton))		self.close_button.released.connect(self.Deactivate) 		self.hbox = QHBoxLayout()		self.hbox.setContentsMargins(0, 0, 0, 0) 		self.hbox.addWidget(self.label)		self.hbox.addWidget(self.fetch_count)		self.hbox.addWidget(self.fetch)		self.hbox.addWidget(self.spacer)		self.hbox.addWidget(self.progress)		self.hbox.addWidget(self.done_label)		self.hbox.addWidget(self.close_button) 		self.bar = QWidget()		self.bar.setLayout(self.hbox)		self.bar.show() 		self.in_progress = False		self.model.progress.connect(self.Progress) 		self.done = False 		if not model.HasMoreRecords():			self.Done() 	def Widget(self):		return self.bar 	def Activate(self):		self.bar.show()		self.fetch.setFocus() 	def Deactivate(self):		self.bar.hide() 	def Enable(self, enable):		self.fetch.setEnabled(enable)		self.fetch_count.setEnabled(enable) 	def Busy(self):		self.Enable(False)		self.fetch.hide()		self.spacer.hide()		self.progress.show() 	def Idle(self):		self.in_progress = False		self.Enable(True)		self.progress.hide()		self.fetch.show()		self.spacer.show() 	def Target(self):		return self.fetch_count.value() * glb_chunk_sz 	def Done(self):		self.done = True		self.Idle()		self.label.hide()		self.fetch_count.hide()		self.fetch.hide()		self.spacer.hide()		self.done_label.show() 	def Progress(self, count):		if self.in_progress:			if count:				percent = ((count - self.start) * 100) / self.Target()				if percent >= 100:					self.Idle()				else:					self.progress.setValue(percent)		if not count:			# Count value of zero means no more records			self.Done() 	def FetchMoreRecords(self):		if self.done:			return		self.progress.setValue(0)		self.Busy()		self.in_progress = True		self.start = self.model.FetchMoreRecords(self.Target()) # Brance data model level two item class BranchLevelTwoItem(): 	def __init__(self, row, col, text, parent_item):		self.row = row		self.parent_item = parent_item		self.data = [""] * (col + 1)		self.data[col] = text		self.level = 2 	def getParentItem(self):		return self.parent_item 	def getRow(self):		return self.row 	def childCount(self):		return 0 	def hasChildren(self):		return False 	def getData(self, column):		return self.data[column] # Brance data model level one item class BranchLevelOneItem(): 	def __init__(self, glb, row, data, parent_item):		self.glb = glb		self.row = row		self.parent_item = parent_item		self.child_count = 0		self.child_items = []		self.data = data[1:]		self.dbid = data[0]		self.level = 1		self.query_done = False		self.br_col = len(self.data) - 1 	def getChildItem(self, row):		return self.child_items[row] 	def getParentItem(self):		return self.parent_item 	def getRow(self):		return self.row 	def Select(self):		self.query_done = True 		if not self.glb.have_disassembler:			return 		query = QSqlQuery(self.glb.db) 		QueryExec(query, "SELECT cpu, to_dso_id, to_symbol_id, to_sym_offset, short_name, long_name, build_id, sym_start, to_ip"				  " FROM samples"				  " INNER JOIN dsos ON samples.to_dso_id = dsos.id"				  " INNER JOIN symbols ON samples.to_symbol_id = symbols.id"				  " WHERE samples.id = " + str(self.dbid))		if not query.next():			return		cpu = query.value(0)		dso = query.value(1)		sym = query.value(2)		if dso == 0 or sym == 0:			return		off = query.value(3)		short_name = query.value(4)		long_name = query.value(5)		build_id = query.value(6)		sym_start = query.value(7)		ip = query.value(8) 		QueryExec(query, "SELECT samples.dso_id, symbol_id, sym_offset, sym_start"				  " FROM samples"				  " INNER JOIN symbols ON samples.symbol_id = symbols.id"				  " WHERE samples.id > " + str(self.dbid) + " AND cpu = " + str(cpu) +				  " ORDER BY samples.id"				  " LIMIT 1")		if not query.next():			return		if query.value(0) != dso:			# Cannot disassemble from one dso to another			return		bsym = query.value(1)		boff = query.value(2)		bsym_start = query.value(3)		if bsym == 0:			return		tot = bsym_start + boff + 1 - sym_start - off		if tot <= 0 or tot > 16384:			return 		inst = self.glb.disassembler.Instruction()		f = self.glb.FileFromNamesAndBuildId(short_name, long_name, build_id)		if not f:			return		mode = 0 if Is64Bit(f) else 1		self.glb.disassembler.SetMode(inst, mode) 		buf_sz = tot + 16		buf = create_string_buffer(tot + 16)		f.seek(sym_start + off)		buf.value = f.read(buf_sz)		buf_ptr = addressof(buf)		i = 0		while tot > 0:			cnt, text = self.glb.disassembler.DisassembleOne(inst, buf_ptr, buf_sz, ip)			if cnt:				byte_str = tohex(ip).rjust(16)				for k in xrange(cnt):					byte_str += " %02x" % ord(buf[i])					i += 1				while k < 15:					byte_str += "   "					k += 1				self.child_items.append(BranchLevelTwoItem(0, self.br_col, byte_str + " " + text, self))				self.child_count += 1			else:				return			buf_ptr += cnt			tot -= cnt			buf_sz -= cnt			ip += cnt 	def childCount(self):		if not self.query_done:			self.Select()			if not self.child_count:				return -1		return self.child_count 	def hasChildren(self):		if not self.query_done:			return True		return self.child_count > 0 	def getData(self, column):

Lines 2501–3000 of 5030. Previous lines