forked from qt-creator/qt-creator
		
	
		
			
				
	
	
		
			363 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			363 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
 | |
| cdbLoaded = False
 | |
| lldbLoaded = False
 | |
| gdbLoaded = False
 | |
| 
 | |
| try:
 | |
|     #import cdb_bridge
 | |
|     cdbLoaded = True
 | |
| 
 | |
| except:
 | |
|     pass
 | |
| 
 | |
| try:
 | |
|     #import lldb_bridge
 | |
|     lldbLoaded = True
 | |
| 
 | |
| except:
 | |
|     pass
 | |
| 
 | |
| 
 | |
| try:
 | |
|     import gdb
 | |
|     gdbLoaded = True
 | |
| 
 | |
|     #######################################################################
 | |
|     #
 | |
|     # Infrastructure
 | |
|     #
 | |
|     #######################################################################
 | |
| 
 | |
|     def registerCommand(name, func):
 | |
| 
 | |
|         class Command(gdb.Command):
 | |
|             def __init__(self):
 | |
|                 super(Command, self).__init__(name, gdb.COMMAND_OBSCURE)
 | |
|             def invoke(self, args, from_tty):
 | |
|                 output = func(args)
 | |
|                 try:
 | |
|                     print(output)
 | |
|                 except:
 | |
|                     out = ""
 | |
|                     for c in output:
 | |
|                         cc = ord(c)
 | |
|                         if cc > 127:
 | |
|                             out += "\\\\%d" % cc
 | |
|                         elif cc < 0:
 | |
|                             out += "\\\\%d" % (cc + 256)
 | |
|                         else:
 | |
|                             out += c
 | |
|                     print(out)
 | |
| 
 | |
| 
 | |
| 
 | |
|         Command()
 | |
| 
 | |
| 
 | |
|     def isGoodGdb():
 | |
|         #return gdb.VERSION.startswith("6.8.50.2009") \
 | |
|         #   and gdb.VERSION != "6.8.50.20090630-cvs"
 | |
|         return 'parse_and_eval' in __builtin__.dir(gdb)
 | |
| 
 | |
| 
 | |
|     def parseAndEvaluate(exp):
 | |
|         if isGoodGdb():
 | |
|             return gdb.parse_and_eval(exp)
 | |
|         # Work around non-existing gdb.parse_and_eval as in released 7.0
 | |
|         gdb.execute("set logging redirect on")
 | |
|         gdb.execute("set logging on")
 | |
|         try:
 | |
|             gdb.execute("print %s" % exp)
 | |
|         except:
 | |
|             gdb.execute("set logging off")
 | |
|             gdb.execute("set logging redirect off")
 | |
|             return None
 | |
|         gdb.execute("set logging off")
 | |
|         gdb.execute("set logging redirect off")
 | |
|         return gdb.history(0)
 | |
| 
 | |
| 
 | |
|     def listOfLocals(varList):
 | |
|         frame = gdb.selected_frame()
 | |
|         try:
 | |
|             frame = gdb.selected_frame()
 | |
|             #warn("FRAME %s: " % frame)
 | |
|         except RuntimeError, error:
 | |
|             warn("FRAME NOT ACCESSIBLE: %s" % error)
 | |
|             return []
 | |
|         except:
 | |
|             warn("FRAME NOT ACCESSIBLE FOR UNKNOWN REASONS")
 | |
|             return []
 | |
| 
 | |
|         # New in 7.2
 | |
|         hasBlock = 'block' in __builtin__.dir(frame)
 | |
| 
 | |
|         items = []
 | |
|         #warn("HAS BLOCK: %s" % hasBlock)
 | |
|         if hasBlock and isGoodGdb():
 | |
|             #warn("IS GOOD: %s " % varList)
 | |
|             try:
 | |
|                 block = frame.block()
 | |
|                 #warn("BLOCK: %s " % block)
 | |
|             except RuntimeError, error:
 | |
|                 warn("BLOCK IN FRAME NOT ACCESSIBLE: %s" % error)
 | |
|                 return items
 | |
|             except:
 | |
|                 warn("BLOCK NOT ACCESSIBLE FOR UNKNOWN REASONS")
 | |
|                 return items
 | |
| 
 | |
|             shadowed = {}
 | |
|             while True:
 | |
|                 if block is None:
 | |
|                     warn("UNEXPECTED 'None' BLOCK")
 | |
|                     break
 | |
|                 for symbol in block:
 | |
|                     name = symbol.print_name
 | |
| 
 | |
|                     if name == "__in_chrg":
 | |
|                         continue
 | |
| 
 | |
|                     # "NotImplementedError: Symbol type not yet supported in
 | |
|                     # Python scripts."
 | |
|                     #warn("SYMBOL %s  (%s): " % (symbol, name))
 | |
|                     if name in shadowed:
 | |
|                         level = shadowed[name]
 | |
|                         name1 = "%s@%s" % (name, level)
 | |
|                         shadowed[name] = level + 1
 | |
|                     else:
 | |
|                         name1 = name
 | |
|                         shadowed[name] = 1
 | |
|                     #warn("SYMBOL %s  (%s, %s)): " % (symbol, name, symbol.name))
 | |
|                     item = LocalItem()
 | |
|                     item.iname = "local." + name1
 | |
|                     item.name = name1
 | |
|                     try:
 | |
|                         item.value = frame.read_var(name, block)
 | |
|                         #warn("READ 1: %s" % item.value)
 | |
|                         if not item.value.is_optimized_out:
 | |
|                             #warn("ITEM 1: %s" % item.value)
 | |
|                             items.append(item)
 | |
|                             continue
 | |
|                     except:
 | |
|                         pass
 | |
| 
 | |
|                     try:
 | |
|                         item.value = frame.read_var(name)
 | |
|                         #warn("READ 2: %s" % item.value)
 | |
|                         if not item.value.is_optimized_out:
 | |
|                             #warn("ITEM 2: %s" % item.value)
 | |
|                             items.append(item)
 | |
|                             continue
 | |
|                     except:
 | |
|                         # RuntimeError: happens for
 | |
|                         #     void foo() { std::string s; std::wstring w; }
 | |
|                         # ValueError: happens for (as of 2010/11/4)
 | |
|                         #     a local struct as found e.g. in
 | |
|                         #     gcc sources in gcc.c, int execute()
 | |
|                         pass
 | |
| 
 | |
|                     try:
 | |
|                         #warn("READ 3: %s %s" % (name, item.value))
 | |
|                         item.value = gdb.parse_and_eval(name)
 | |
|                         #warn("ITEM 3: %s" % item.value)
 | |
|                         items.append(item)
 | |
|                     except:
 | |
|                         # Can happen in inlined code (see last line of
 | |
|                         # RowPainter::paintChars(): "RuntimeError:
 | |
|                         # No symbol \"__val\" in current context.\n"
 | |
|                         pass
 | |
| 
 | |
|                 # The outermost block in a function has the function member
 | |
|                 # FIXME: check whether this is guaranteed.
 | |
|                 if not block.function is None:
 | |
|                     break
 | |
| 
 | |
|                 block = block.superblock
 | |
|         else:
 | |
|             # Assuming gdb 7.0 release or 6.8-symbianelf.
 | |
|             filename, file = createTempFile()
 | |
|             #warn("VARLIST: %s " % varList)
 | |
|             #warn("FILENAME: %s " % filename)
 | |
|             gdb.execute("set logging off")
 | |
|             gdb.execute("set logging redirect off")
 | |
|             gdb.execute("set logging file %s" % filename)
 | |
|             gdb.execute("set logging redirect on")
 | |
|             gdb.execute("set logging on")
 | |
|             try:
 | |
|                 gdb.execute("info args")
 | |
|                 # We cannot use "info locals" as at least 6.8-symbianelf
 | |
|                 # aborts as soon as we hit unreadable memory.
 | |
|                 # gdb.execute("interpreter mi '-stack-list-locals 0'")
 | |
|                 # results in &"Recursive internal problem.\n", so we have
 | |
|                 # the frontend pass us the list of locals.
 | |
| 
 | |
|                 # There are two cases, either varList is empty, so we have
 | |
|                 # to fetch the list here, or it is not empty with the
 | |
|                 # first entry being a dummy.
 | |
|                 if len(varList) == 0:
 | |
|                     gdb.execute("info locals")
 | |
|                 else:
 | |
|                     varList = varList[1:]
 | |
|             except:
 | |
|                 pass
 | |
|             gdb.execute("set logging off")
 | |
|             gdb.execute("set logging redirect off")
 | |
| 
 | |
|             try:
 | |
|                 temp = open(filename, "r")
 | |
|                 for line in temp:
 | |
|                     if len(line) == 0 or line.startswith(" "):
 | |
|                         continue
 | |
|                     # The function parameters
 | |
|                     pos = line.find(" = ")
 | |
|                     if pos < 0:
 | |
|                         continue
 | |
|                     varList.append(line[0:pos])
 | |
|                 temp.close()
 | |
|             except:
 | |
|                 pass
 | |
|             removeTempFile(filename, file)
 | |
|             #warn("VARLIST: %s " % varList)
 | |
|             for name in varList:
 | |
|                 #warn("NAME %s " % name)
 | |
|                 item = LocalItem()
 | |
|                 item.iname = "local." + name
 | |
|                 item.name = name
 | |
|                 try:
 | |
|                     item.value = frame.read_var(name)  # this is a gdb value
 | |
|                 except RuntimeError:
 | |
|                     pass
 | |
|                     #continue
 | |
|                 except:
 | |
|                     # Something breaking the list, like intermediate gdb warnings
 | |
|                     # like 'Warning: can't find linker symbol for virtual table for
 | |
|                     # `std::less<char const*>' value\n\nwarning:  found
 | |
|                     # `myns::QHashData::shared_null' instead [...]
 | |
|                     # that break subsequent parsing. Chicken out and take the
 | |
|                     # next "usable" line.
 | |
|                     continue
 | |
|                 items.append(item)
 | |
| 
 | |
|         return items
 | |
| 
 | |
| 
 | |
|     def catchCliOutput(command):
 | |
|         try:
 | |
|             return gdb.execute(command, to_string=True).split("\n")
 | |
|         except:
 | |
|             pass
 | |
|         filename, file = createTempFile()
 | |
|         gdb.execute("set logging off")
 | |
|         gdb.execute("set logging redirect off")
 | |
|         gdb.execute("set logging file %s" % filename)
 | |
|         gdb.execute("set logging redirect on")
 | |
|         gdb.execute("set logging on")
 | |
|         msg = ""
 | |
|         try:
 | |
|             gdb.execute(command)
 | |
|         except RuntimeError, error:
 | |
|             # For the first phase of core file loading this yield
 | |
|             # "No symbol table is loaded.  Use the \"file\" command."
 | |
|             msg = str(error)
 | |
|         except:
 | |
|             msg = "Unknown error"
 | |
|         gdb.execute("set logging off")
 | |
|         gdb.execute("set logging redirect off")
 | |
|         if len(msg):
 | |
|             # Having that might confuse result handlers in the gdbengine.
 | |
|             #warn("CLI ERROR: %s " % msg)
 | |
|             return "CLI ERROR: %s " % msg
 | |
|         temp = open(filename, "r")
 | |
|         lines = []
 | |
|         for line in temp:
 | |
|             lines.append(line)
 | |
|         temp.close()
 | |
|         removeTempFile(filename, file)
 | |
|         return lines
 | |
| 
 | |
|     #######################################################################
 | |
|     #
 | |
|     # Types
 | |
|     #
 | |
|     #######################################################################
 | |
| 
 | |
|     PointerCode = gdb.TYPE_CODE_PTR
 | |
|     ArrayCode = gdb.TYPE_CODE_ARRAY
 | |
|     StructCode = gdb.TYPE_CODE_STRUCT
 | |
|     UnionCode = gdb.TYPE_CODE_UNION
 | |
|     EnumCode = gdb.TYPE_CODE_ENUM
 | |
|     FlagsCode = gdb.TYPE_CODE_FLAGS
 | |
|     FunctionCode = gdb.TYPE_CODE_FUNC
 | |
|     IntCode = gdb.TYPE_CODE_INT
 | |
|     FloatCode = gdb.TYPE_CODE_FLT # Parts of GDB assume that this means complex.
 | |
|     VoidCode = gdb.TYPE_CODE_VOID
 | |
|     #SetCode = gdb.TYPE_CODE_SET
 | |
|     RangeCode = gdb.TYPE_CODE_RANGE
 | |
|     StringCode = gdb.TYPE_CODE_STRING
 | |
|     #BitStringCode = gdb.TYPE_CODE_BITSTRING
 | |
|     #ErrorTypeCode = gdb.TYPE_CODE_ERROR
 | |
|     MethodCode = gdb.TYPE_CODE_METHOD
 | |
|     #MethodPointerCode = gdb.TYPE_CODE_METHODPTR
 | |
|     #MemberPointerCode = gdb.TYPE_CODE_MEMBERPTR
 | |
|     ReferenceCode = gdb.TYPE_CODE_REF
 | |
|     CharCode = gdb.TYPE_CODE_CHAR
 | |
|     BoolCode = gdb.TYPE_CODE_BOOL
 | |
|     ComplexCode = gdb.TYPE_CODE_COMPLEX # Fortran ?
 | |
|     TypedefCode = gdb.TYPE_CODE_TYPEDEF
 | |
|     NamespaceCode = gdb.TYPE_CODE_NAMESPACE
 | |
|     #Code = gdb.TYPE_CODE_DECFLOAT # Decimal floating point.
 | |
|     #Code = gdb.TYPE_CODE_MODULE # Fortran
 | |
|     #Code = gdb.TYPE_CODE_INTERNAL_FUNCTION
 | |
| 
 | |
|     #######################################################################
 | |
|     #
 | |
|     # Step Command
 | |
|     #
 | |
|     #######################################################################
 | |
| 
 | |
|     def sal(args):
 | |
|         (cmd, addr) = args.split(",")
 | |
|         lines = catchCliOutput("info line *" + addr)
 | |
|         fromAddr = "0x0"
 | |
|         toAddr = "0x0"
 | |
|         for line in lines:
 | |
|             pos0from = line.find(" starts at address") + 19
 | |
|             pos1from = line.find(" ", pos0from)
 | |
|             pos0to = line.find(" ends at", pos1from) + 9
 | |
|             pos1to = line.find(" ", pos0to)
 | |
|             if pos1to > 0:
 | |
|                 fromAddr = line[pos0from : pos1from]
 | |
|                 toAddr = line[pos0to : pos1to]
 | |
|         gdb.execute("maint packet sal%s,%s,%s" % (cmd,fromAddr, toAddr))
 | |
| 
 | |
|     registerCommand("sal", sal)
 | |
| 
 | |
| 
 | |
|     #######################################################################
 | |
|     #
 | |
|     # Convenience
 | |
|     #
 | |
|     #######################################################################
 | |
| 
 | |
|     # Just convienience for 'python print ...'
 | |
|     class PPCommand(gdb.Command):
 | |
|         def __init__(self):
 | |
|             super(PPCommand, self).__init__("pp", gdb.COMMAND_OBSCURE)
 | |
|         def invoke(self, args, from_tty):
 | |
|             print(eval(args))
 | |
| 
 | |
|     registerCommand("pp", pp)
 | |
|         
 | |
|     # Just convienience for 'python print gdb.parse_and_eval(...)'
 | |
|     class PPPCommand(gdb.Command):
 | |
|         def __init__(self):
 | |
|             super(PPPCommand, self).__init__("ppp", gdb.COMMAND_OBSCURE)
 | |
|         def invoke(self, args, from_tty):
 | |
|             print(gdb.parse_and_eval(args))
 | |
| 
 | |
|     PPPCommand()
 | |
| 
 | |
| except:
 | |
|     pass
 | |
| 
 |