gdbbridge.py 64.8 KB
Newer Older
hjk's avatar
hjk committed
1

2 3 4 5 6 7 8 9 10
try:
    import __builtin__
except:
    import builtins
try:
    import gdb
except:
    pass

hjk's avatar
hjk committed
11
import os
12
import os.path
13
import sys
14
import struct
15
import types
16

17
import importlib
hjk's avatar
hjk committed
18

19 20
def warn(message):
    print("XXX: %s\n" % message.encode("latin1"))
21

22
from dumper import *
23 24 25 26 27 28 29 30 31 32 33 34

dumpermodules = [
    "qttypes",
    "stdtypes",
    "misctypes",
    "boosttypes",
    "creatortypes",
    "personaltypes",
]

for mod in dumpermodules:
    importlib.import_module(mod)
hjk's avatar
hjk committed
35

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130

#######################################################################
#
# Infrastructure
#
#######################################################################

def savePrint(output):
    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)

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):
            savePrint(func(args))

    Command()



#######################################################################
#
# 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
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


#######################################################################
#
# 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))

PPCommand()

# 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()


def scanStack(p, n):
131
    p = int(p)
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
    r = []
    for i in xrange(n):
        f = gdb.parse_and_eval("{void*}%s" % p)
        m = gdb.execute("info symbol %s" % f, to_string=True)
        if not m.startswith("No symbol matches"):
            r.append(m)
        p += f.type.sizeof
    return r

class ScanStackCommand(gdb.Command):
    def __init__(self):
        super(ScanStackCommand, self).__init__("scanStack", gdb.COMMAND_OBSCURE)
    def invoke(self, args, from_tty):
        if len(args) == 0:
            args = 20
        savePrint(scanStack(gdb.parse_and_eval("$sp"), int(args)))

ScanStackCommand()

hjk's avatar
hjk committed
151

152
def bbsetup(args = ''):
153 154
    theDumper.bbsetup()
    print(theDumper.reportDumpers())
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169

registerCommand("bbsetup", bbsetup)


#######################################################################
#
# Import plain gdb pretty printers
#
#######################################################################

class PlainDumper:
    def __init__(self, printer):
        self.printer = printer

    def __call__(self, d, value):
170
        printer = self.printer.invoke(value)
171 172 173 174 175 176 177 178 179 180 181 182 183
        lister = getattr(printer, "children", None)
        children = [] if lister is None else list(lister())
        d.putType(self.printer.name)
        val = printer.to_string().encode("hex")
        d.putValue(val, Hex2EncodedLatin1)
        d.putValue(printer.to_string())
        d.putNumChild(len(children))
        if d.isExpanded():
            with Children(d):
                for child in children:
                    d.putSubItem(child[0], child[1])

def importPlainDumpers(args):
184
    theDumper.importPlainDumpers()
185 186 187 188

registerCommand("importPlainDumpers", importPlainDumpers)


189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209

class OutputSafer:
    def __init__(self, d):
        self.d = d

    def __enter__(self):
        self.savedOutput = self.d.output
        self.d.output = []

    def __exit__(self, exType, exValue, exTraceBack):
        if self.d.passExceptions and not exType is None:
            showException("OUTPUTSAFER", exType, exValue, exTraceBack)
            self.d.output = self.savedOutput
        else:
            self.savedOutput.extend(self.d.output)
            self.d.output = self.savedOutput
        return False



#def couldBePointer(p, align):
210 211
#    typeobj = lookupType("unsigned int")
#    ptr = gdb.Value(p).cast(typeobj)
212 213 214 215 216 217 218 219 220
#    d = int(str(ptr))
#    warn("CHECKING : %s %d " % (p, ((d & 3) == 0 and (d > 1000 or d == 0))))
#    return (d & (align - 1)) and (d > 1000 or d == 0)


Value = gdb.Value



221 222 223 224 225
def stripTypedefs(typeobj):
    typeobj = typeobj.unqualified()
    while typeobj.code == TypedefCode:
        typeobj = typeobj.strip_typedefs().unqualified()
    return typeobj
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245


#######################################################################
#
# LocalItem
#
#######################################################################

# Contains iname, name, and value.
class LocalItem:
    pass


#######################################################################
#
# Edit Command
#
#######################################################################

def bbedit(args):
246
    theDumper.bbedit(args)
247 248 249 250 251 252 253 254 255 256

registerCommand("bbedit", bbedit)


#######################################################################
#
# Frame Command
#
#######################################################################

257

258
def bb(args):
259 260 261 262 263
    try:
        print(theDumper.run(args))
    except:
        import traceback
        traceback.print_exc()
264 265

registerCommand("bb", bb)
266

267 268 269 270 271 272 273
#######################################################################
#
# The Dumper Class
#
#######################################################################


274 275
class Dumper(DumperBase):

276
    def __init__(self):
277 278
        DumperBase.__init__(self)

279
        # These values will be kept between calls to 'run'.
280
        self.isGdb = True
281
        self.childEventAddress = None
282 283
        self.typesReported = {}
        self.typesToReport = {}
284
        self.qtNamespaceToReport = None
285

286
    def prepare(self, args):
287 288 289 290 291 292 293
        self.output = []
        self.currentIName = ""
        self.currentPrintsAddress = True
        self.currentChildType = ""
        self.currentChildNumChild = -1
        self.currentMaxNumChild = -1
        self.currentNumChild = -1
294 295
        self.currentValue = ReportItem()
        self.currentType = ReportItem()
296 297 298 299 300 301
        self.currentAddress = None
        self.typeformats = {}
        self.formats = {}
        self.useDynamicType = True
        self.expandedINames = {}

302 303 304 305 306
        # The guess does not need to be updated during a run()
        # as the result is fixed during that time (ignoring "active"
        # dumpers causing loading of shared objects etc).
        self.currentQtNamespaceGuess = None

307 308 309 310
        self.watchers = ""
        self.resultVarName = ""
        self.varList = []
        self.options = []
311 312 313 314

        for arg in args.split(' '):
            pos = arg.find(":") + 1
            if arg.startswith("options:"):
315
                self.options = arg[pos:].split(",")
316 317
            elif arg.startswith("vars:"):
                if len(arg[pos:]) > 0:
318
                    self.varList = arg[pos:].split(",")
319
            elif arg.startswith("resultvarname:"):
320
                self.resultVarName = arg[pos:]
321 322
            elif arg.startswith("expanded:"):
                self.expandedINames = set(arg[pos:].split(","))
323 324
            elif arg.startswith("stringcutoff:"):
                self.stringCutOff = int(arg[pos:])
325 326
            elif arg.startswith("displaystringlimit:"):
                self.displayStringLimit = int(arg[pos:])
327 328 329 330
            elif arg.startswith("typeformats:"):
                for f in arg[pos:].split(","):
                    pos = f.find("=")
                    if pos != -1:
331 332
                        typeName = self.hexdecode(f[0:pos])
                        self.typeformats[typeName] = int(f[pos+1:])
333 334 335 336 337 338
            elif arg.startswith("formats:"):
                for f in arg[pos:].split(","):
                    pos = f.find("=")
                    if pos != -1:
                        self.formats[f[0:pos]] = int(f[pos+1:])
            elif arg.startswith("watchers:"):
339
                self.watchers = self.hexdecode(arg[pos:])
340

341 342 343 344
        self.useDynamicType = "dyntype" in self.options
        self.useFancy = "fancy" in self.options
        self.forceQtNamespace = "forcens" in self.options
        self.passExceptions = "pe" in self.options
345
        #self.passExceptions = True
346 347 348
        self.autoDerefPointers = "autoderef" in self.options
        self.partialUpdate = "partial" in self.options
        self.tooltipOnly = "tooltiponly" in self.options
349
        self.fallbackQtVersion = 0x50200
350
        #warn("NAMESPACE: '%s'" % self.qtNamespace())
351
        #warn("VARIABLES: %s" % self.varList)
352
        #warn("EXPANDED INAMES: %s" % self.expandedINames)
353
        #warn("WATCHERS: %s" % self.watchers)
354 355
        #warn("PARTIAL: %s" % self.partialUpdate)

356 357 358 359 360 361 362
    def handleWatches(self):
        with OutputSafer(self):
            if len(self.watchers) > 0:
                for watcher in self.watchers.split("##"):
                    (exp, iname) = watcher.split("#")
                    self.handleWatch(exp, exp, iname)

363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
    def listOfLocals(self):
        frame = gdb.selected_frame()


        try:
            block = frame.block()
            #warn("BLOCK: %s " % block)
        except RuntimeError as error:
            #warn("BLOCK IN FRAME NOT ACCESSIBLE: %s" % error)
            return []
        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" or name == "__PRETTY_FUNCTION__":
                    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)
                    items.append(item)
                    continue
                except:
                    pass

                try:
                    #warn("READ 2: %s" % item.value)
                    item.value = frame.read_var(name)
                    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

        return items


445 446 447
    def run(self, args):
        self.prepare(args)

448 449 450
        #
        # Locals
        #
451
        self.output.append('data=[')
452
        if self.partialUpdate and len(self.varList) == 1:
453 454
            #warn("PARTIAL: %s" % self.varList)
            parts = self.varList[0].split('.')
455 456 457
            #warn("PARTIAL PARTS: %s" % parts)
            name = parts[1]
            #warn("PARTIAL VAR: %s" % name)
458 459 460
            item = LocalItem()
            item.iname = parts[0] + '.' + name
            item.name = name
461
            try:
462 463 464 465 466 467 468 469
                if parts[0] == 'local':
                    frame = gdb.selected_frame()
                    item.value = frame.read_var(name)
                else:
                    item.name = self.hexdecode(name)
                    item.value = gdb.parse_and_eval(item.name)
            except RuntimeError as error:
                item.value = error
470
            except:
471 472 473 474
                item.value = "<no value>"
            locals = [item]
            #warn("PARTIAL LOCALS: %s" % locals)
        else:
475
            locals = self.listOfLocals()
476 477

        # Take care of the return value of the last function call.
478
        if len(self.resultVarName) > 0:
479 480
            try:
                item = LocalItem()
481 482 483
                item.name = self.resultVarName
                item.iname = "return." + self.resultVarName
                item.value = self.parseAndEvaluate(self.resultVarName)
484 485 486 487 488 489
                locals.append(item)
            except:
                # Don't bother. It's only supplementary information anyway.
                pass

        for item in locals:
490
            value = self.downcast(item.value) if self.useDynamicType else item.value
491 492 493
            with OutputSafer(self):
                self.anonNumber = -1

494 495
                if item.iname == "local.argv" and str(value.type) == "char **":
                    self.putSpecialArgv(value)
496 497 498 499 500 501 502
                else:
                    # A "normal" local variable or parameter.
                    with TopLevelItem(self, item.iname):
                        self.put('iname="%s",' % item.iname)
                        self.put('name="%s",' % item.name)
                        self.putItem(value)

503
        self.handleWatches()
504

505
        #print('data=[' + locals + sep + self.watchers + ']\n')
506

507 508
        self.output.append('],typeinfo=[')
        for name in self.typesToReport.keys():
509
            typeobj = self.typesToReport[name]
510
            # Happens e.g. for '(anonymous namespace)::InsertDefOperation'
511
            if not typeobj is None:
512
                self.output.append('{name="%s",size="%s"}'
513
                    % (self.hexencode(name), typeobj.sizeof))
514 515
        self.output.append(']')
        self.typesToReport = {}
516

517
        if "forcens" in self.options:
518
            self.qtNamepaceToReport = self.qtNamespace()
519

520 521 522 523
        if self.qtNamespaceToReport:
            self.output.append(',qtnamespace="%s"' % self.qtNamespaceToReport)
            self.qtNamespaceToReport = None

524
        return "".join(self.output)
525

526 527 528 529 530 531 532 533 534 535 536 537 538
    def enterSubItem(self, item):
        if not item.iname:
            item.iname = "%s.%s" % (self.currentIName, item.name)
        #warn("INAME %s" % item.iname)
        self.put('{')
        #if not item.name is None:
        if isinstance(item.name, str):
            self.put('name="%s",' % item.name)
        item.savedIName = self.currentIName
        item.savedValue = self.currentValue
        item.savedType = self.currentType
        item.savedCurrentAddress = self.currentAddress
        self.currentIName = item.iname
539 540
        self.currentValue = ReportItem();
        self.currentType = ReportItem();
541 542 543
        self.currentAddress = None

    def exitSubItem(self, item, exType, exValue, exTraceBack):
hjk's avatar
hjk committed
544
        #warn("CURRENT VALUE: %s: %s %s" % (self.currentIName, self.currentValue, self.currentType))
545 546 547 548 549 550
        if not exType is None:
            if self.passExceptions:
                showException("SUBITEM", exType, exValue, exTraceBack)
            self.putNumChild(0)
            self.putValue("<not accessible>")
        try:
hjk's avatar
hjk committed
551
            if self.currentType.value:
552
                typeName = self.stripClassTag(self.currentType.value)
hjk's avatar
hjk committed
553 554
                if len(typeName) > 0 and typeName != self.currentChildType:
                    self.put('type="%s",' % typeName) # str(type.unqualified()) ?
555

556
            if  self.currentValue.value is None:
557 558
                self.put('value="<not accessible>",numchild="0",')
            else:
559 560 561 562 563
                if not self.currentValue.encoding is None:
                    self.put('valueencoded="%d",' % self.currentValue.encoding)
                if self.currentValue.elided:
                    self.put('valueelided="%d",' % self.currentValue.elided)
                self.put('value="%s",' % self.currentValue.value)
564 565 566 567 568 569 570 571 572 573 574
        except:
            pass
        if not self.currentAddress is None:
            self.put(self.currentAddress)
        self.put('},')
        self.currentIName = item.savedIName
        self.currentValue = item.savedValue
        self.currentType = item.savedType
        self.currentAddress = item.savedCurrentAddress
        return True

575 576 577
    def parseAndEvaluate(self, exp):
        return gdb.parse_and_eval(exp)

578
    def callHelper(self, value, func, args):
579 580 581 582 583 584 585 586 587 588 589 590
        # args is a tuple.
        arg = ""
        for i in range(len(args)):
            if i:
                arg += ','
            a = args[i]
            if (':' in a) and not ("'" in a):
                arg = "'%s'" % a
            else:
                arg += a

        #warn("CALL: %s -> %s(%s)" % (value, func, arg))
591
        typeName = self.stripClassTag(str(value.type))
592 593
        if typeName.find(":") >= 0:
            typeName = "'" + typeName + "'"
594
        # 'class' is needed, see http://sourceware.org/bugzilla/show_bug.cgi?id=11912
595 596 597
        #exp = "((class %s*)%s)->%s(%s)" % (typeName, value.address, func, arg)
        ptr = value.address if value.address else self.pokeValue(value)
        exp = "((%s*)%s)->%s(%s)" % (typeName, ptr, func, arg)
598
        #warn("CALL: %s" % exp)
599
        result = gdb.parse_and_eval(exp)
600
        #warn("  -> %s" % result)
601 602
        if not value.address:
            gdb.parse_and_eval("free(0x%x)" % ptr)
603 604
        return result

hjk's avatar
hjk committed
605
    def childWithName(self, value, name):
606
        try:
hjk's avatar
hjk committed
607
            return value[name]
608
        except:
hjk's avatar
hjk committed
609
            return None
610

611 612
    def makeValue(self, typeobj, init):
        typename = "::" + self.stripClassTag(str(typeobj));
hjk's avatar
hjk committed
613
        # Avoid malloc symbol clash with QVector.
614
        gdb.execute("set $d = (%s*)calloc(sizeof(%s), 1)" % (typename, typename))
hjk's avatar
hjk committed
615
        gdb.execute("set *$d = {%s}" % init)
hjk's avatar
hjk committed
616
        value = gdb.parse_and_eval("$d").dereference()
hjk's avatar
hjk committed
617 618 619 620 621 622
        #warn("  TYPE: %s" % value.type)
        #warn("  ADDR: %s" % value.address)
        #warn("  VALUE: %s" % value)
        return value

    def makeExpression(self, value):
623 624 625 626
        typename = "::" + self.stripClassTag(str(value.type))
        #warn("  TYPE: %s" % typename)
        #exp = "(*(%s*)(&%s))" % (typename, value.address)
        exp = "(*(%s*)(%s))" % (typename, value.address)
hjk's avatar
hjk committed
627 628 629 630 631 632 633 634
        #warn("  EXP: %s" % exp)
        return exp

    def makeStdString(init):
        # Works only for small allocators, but they are usually empty.
        gdb.execute("set $d=(std::string*)calloc(sizeof(std::string), 2)");
        gdb.execute("call($d->basic_string(\"" + init +
            "\",*(std::allocator<char>*)(1+$d)))")
hjk's avatar
hjk committed
635
        value = gdb.parse_and_eval("$d").dereference()
hjk's avatar
hjk committed
636 637 638 639 640
        #warn("  TYPE: %s" % value.type)
        #warn("  ADDR: %s" % value.address)
        #warn("  VALUE: %s" % value)
        return value

641 642
    def childAt(self, value, index):
        field = value.type.fields()[index]
643 644 645 646 647 648 649 650 651 652 653 654 655
        try:
            # Official access in GDB 7.6 or later.
            return value[field]
        except:
            pass

        try:
            # Won't work with anon entities, tradionally with empty
            # field name, but starting with GDB 7.7 commit b5b08fb4
            # with None field name.
            return value[field.name]
        except:
            pass
656

657 658 659 660 661 662
        # FIXME: Cheat. There seems to be no official way to access
        # the real item, so we pass back the value. That at least
        # enables later ...["name"] style accesses as gdb handles
        # them transparently.
        return value

663 664
    def fieldAt(self, typeobj, index):
        return typeobj.fields()[index]
665

666 667 668
    def simpleValue(self, value):
        return str(value)

669
    def directBaseClass(self, typeobj, index = 0):
670 671 672 673 674
        for f in typeobj.fields():
            if f.is_base_class:
                if index == 0:
                    return f.type
                index -= 1;
hjk's avatar
hjk committed
675 676 677 678 679 680 681 682
        return None

    def directBaseObject(self, value, index = 0):
        for f in value.type.fields():
            if f.is_base_class:
                if index == 0:
                    return value.cast(f.type)
                index -= 1;
683
        return None
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698

    def checkPointer(self, p, align = 1):
        if not self.isNull(p):
            p.dereference()

    def pointerValue(self, p):
        return toInteger(p)

    def isNull(self, p):
        # The following can cause evaluation to abort with "UnicodeEncodeError"
        # for invalid char *, as their "contents" is being examined
        #s = str(p)
        #return s == "0x0" or s.startswith("0x0 ")
        #try:
        #    # Can fail with: "RuntimeError: Cannot access memory at address 0x5"
hjk's avatar
hjk committed
699
        #    return p.cast(self.lookupType("void").pointer()) == 0
700 701 702 703 704 705 706 707
        #except:
        #    return False
        try:
            # Can fail with: "RuntimeError: Cannot access memory at address 0x5"
            return toInteger(p) == 0
        except:
            return False

708
    def templateArgument(self, typeobj, position):
709 710 711 712 713 714 715
        try:
            # This fails on stock 7.2 with
            # "RuntimeError: No type named myns::QObject.\n"
            return typeobj.template_argument(position)
        except:
            # That's something like "myns::QList<...>"
            return self.lookupType(self.extractTemplateArgument(str(typeobj.strip_typedefs()), position))
716 717

    def numericTemplateArgument(self, typeobj, position):
718 719 720 721 722 723 724 725 726 727 728 729
        # Workaround for gdb < 7.1
        try:
            return int(typeobj.template_argument(position))
        except RuntimeError as error:
            # ": No type named 30."
            msg = str(error)
            msg = msg[14:-1]
            # gdb at least until 7.4 produces for std::array<int, 4u>
            # for template_argument(1): RuntimeError: No type named 4u.
            if msg[-1] == 'u':
               msg = msg[0:-1]
            return int(msg)
730

731
    def intType(self):
732 733 734
        self.cachedIntType = self.lookupType('int')
        self.intType = lambda: self.cachedIntType
        return self.cachedIntType
735 736

    def charType(self):
hjk's avatar
hjk committed
737
        return self.lookupType('char')
738 739

    def sizetType(self):
hjk's avatar
hjk committed
740
        return self.lookupType('size_t')
741 742

    def charPtrType(self):
hjk's avatar
hjk committed
743
        return self.lookupType('char*')
744 745

    def voidPtrType(self):
hjk's avatar
hjk committed
746
        return self.lookupType('void*')
747

748
    def addressOf(self, value):
749
        return toInteger(value.address)
750

751
    def createPointerValue(self, address, pointeeType):
752 753 754 755 756 757 758 759
        # This might not always work:
        # a Python 3 based GDB due to the bug addressed in
        # https://sourceware.org/ml/gdb-patches/2013-09/msg00571.html
        try:
            return gdb.Value(address).cast(pointeeType.pointer())
        except:
            # Try _some_ fallback (good enough for the std::complex dumper)
            return gdb.parse_and_eval("(%s*)%s" % (pointeeType, address))
760 761 762 763 764

    def intSize(self):
        return 4

    def ptrSize(self):
765 766 767
        self.cachedPtrSize = self.lookupType('void*').sizeof
        self.ptrSize = lambda: self.cachedPtrSize
        return self.cachedPtrSize
768

769 770 771 772 773 774 775 776 777 778 779 780 781 782
    def pokeValue(self, value):
        """
        Allocates inferior memory and copies the contents of value.
        Returns a pointer to the copy.
        """
        # Avoid malloc symbol clash with QVector
        size = value.type.sizeof
        data = value.cast(gdb.lookup_type("unsigned char").array(0, int(size - 1)))
        string = ''.join("\\x%02x" % int(data[i]) for i in range(size))
        exp = '(%s*)memcpy(calloc(%s, 1), "%s", %s)' % (value.type, size, string, size)
        #warn("EXP: %s" % exp)
        return toInteger(gdb.parse_and_eval(exp))


783
    def createValue(self, address, referencedType):
784 785 786 787 788
        try:
            return gdb.Value(address).cast(referencedType.pointer()).dereference()
        except:
            # Try _some_ fallback (good enough for the std::complex dumper)
            return gdb.parse_and_eval("{%s}%s" % (referencedType, address))
789

790 791
    def setValue(self, address, typename, value):
        cmd = "set {%s}%s=%s" % (typename, address, value)
792 793
        gdb.execute(cmd)

794
    def setValues(self, address, typename, values):
795
        cmd = "set {%s[%s]}%s={%s}" \
796
            % (typename, len(values), address, ','.join(map(str, values)))
797 798
        gdb.execute(cmd)

799 800
    def selectedInferior(self):
        try:
801
            # gdb.Inferior is new in gdb 7.2
802
            self.cachedInferior = gdb.selected_inferior()
803 804
        except:
            # Pre gdb 7.4. Right now we don't have more than one inferior anyway.
805 806 807 808 809
            self.cachedInferior = gdb.inferiors()[0]

        # Memoize result.
        self.selectedInferior = lambda: self.cachedInferior
        return self.cachedInferior
810

811
    def readRawMemory(self, addr, size):
812
        mem = self.selectedInferior().read_memory(addr, size)
813 814 815 816
        if sys.version_info[0] >= 3:
            mem.tobytes()
        return mem

817 818 819
    def extractInt64(self, addr):
        return struct.unpack("q", self.readRawMemory(addr, 8))[0]

820
    def extractInt(self, addr):
821
        return struct.unpack("i", self.readRawMemory(addr, 4))[0]
822

823
    def extractByte(self, addr):
824
        return struct.unpack("b", self.readRawMemory(addr, 1))[0]
825

826 827
    def findStaticMetaObject(self, typename):
        return self.findSymbol(typename + "::staticMetaObject")
828

829 830 831 832 833 834 835 836
    def findSymbol(self, symbolName):
        try:
            result = gdb.lookup_global_symbol(symbolName)
            return result.value() if result else 0
        except:
            pass
        # Older GDB ~7.4
        try:
837
            address = gdb.parse_and_eval("&'%s'" % symbolName)
838 839
            typeobj = gdb.lookup_type(self.qtNamespace() + "QMetaObject")
            return self.createPointerValue(address, typeobj)
840 841
        except:
            return 0
842

843 844 845 846 847
    def put(self, value):
        self.output.append(value)

    def childRange(self):
        if self.currentMaxNumChild is None:
848 849
            return xrange(0, toInteger(self.currentNumChild))
        return xrange(min(toInteger(self.currentMaxNumChild), toInteger(self.currentNumChild)))
850

851 852 853 854 855 856
    def isArmArchitecture(self):
        return 'arm' in gdb.TARGET_CONFIG.lower()

    def isQnxTarget(self):
        return 'qnx' in gdb.TARGET_CONFIG.lower()

857 858 859 860
    def isWindowsTarget(self):
        # We get i686-w64-mingw32
        return 'mingw' in gdb.TARGET_CONFIG.lower()

hjk's avatar
hjk committed
861 862 863 864 865
    def qtVersionString(self):
        try:
            return str(gdb.lookup_symbol("qVersion")[0].value()())
        except:
            pass
866
        try:
867
            ns = self.qtNamespace()
hjk's avatar
hjk committed
868 869 870 871 872 873 874 875
            return str(gdb.parse_and_eval("((const char*(*)())'%sqVersion')()" % ns))
        except:
            pass
        return None

    def qtVersion(self):
        try:
            version = self.qtVersionString()
876
            (major, minor, patch) = version[version.find('"')+1:version.rfind('"')].split('.')
hjk's avatar
hjk committed
877 878 879
            qtversion = 0x10000 * int(major) + 0x100 * int(minor) + int(patch)
            self.qtVersion = lambda: qtversion
            return qtversion
880
        except:
881 882
            # Use fallback until we have a better answer.
            return self.fallbackQtVersion
883

884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
    def isQt3Support(self):
        if self.qtVersion() >= 0x050000:
            return False
        else:
            try:
                # This will fail on Qt 4 without Qt 3 support
                gdb.execute("ptype QChar::null", to_string=True)
                self.cachedIsQt3Suport = True
            except:
                self.cachedIsQt3Suport = False

        # Memoize good results.
        self.isQt3Support = lambda: self.cachedIsQt3Suport
        return self.cachedIsQt3Suport

899
    def putAddress(self, addr):
900
        if self.currentPrintsAddress and not self.isCli:
901
            try:
902 903 904
                # addr can be "None", int(None) fails.
                #self.put('addr="0x%x",' % int(addr))
                self.currentAddress = 'addr="0x%x",' % toInteger(addr)
905 906 907 908 909 910 911 912
            except:
                pass

    def putNumChild(self, numchild):
        #warn("NUM CHILD: '%s' '%s'" % (numchild, self.currentChildNumChild))
        if numchild != self.currentChildNumChild:
            self.put('numchild="%s",' % numchild)

hjk's avatar
hjk committed
913 914 915
    def putSimpleValue(self, value, encoding = None, priority = 0):
        self.putValue(value, encoding, priority)

916 917 918 919 920 921
    def putPointerValue(self, value):
        # Use a lower priority
        if value is None:
            self.putEmptyValue(-1)
        else:
            self.putValue("0x%x" % value.cast(
hjk's avatar
hjk committed
922
                self.lookupType("unsigned long")), None, -1)
923 924

    def stripNamespaceFromType(self, typeName):
925
        typename = self.stripClassTag(typeName)
926
        ns = self.qtNamespace()
927 928 929
        if len(ns) > 0 and typename.startswith(ns):
            typename = typename[len(ns):]
        pos = typename.find("<")
930 931
        # FIXME: make it recognize  foo<A>::bar<B>::iterator?
        while pos != -1:
932 933 934 935
            pos1 = typename.rfind(">", pos)
            typename = typename[0:pos] + typename[pos1+1:]
            pos = typename.find("<")
        return typename
936

937 938
    def isMovableType(self, typeobj):
        if typeobj.code == PointerCode:
939
            return True
940
        if self.isSimpleType(typeobj):
941
            return True
942
        return self.isKnownMovableType(self.stripNamespaceFromType(str(typeobj)))
943 944 945 946 947

    def putSubItem(self, component, value, tryDynamic=True):
        with SubItem(self, component):
            self.putItem(value, tryDynamic)

948 949 950 951 952 953
    def isSimpleType(self, typeobj):
        code = typeobj.code
        return code == BoolCode \
            or code == CharCode \
            or code == IntCode \
            or code == FloatCode \
954
            or code == EnumCode
955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985

    def simpleEncoding(self, typeobj):
        code = typeobj.code
        if code == BoolCode or code == CharCode:
            return Hex2EncodedInt1
        if code == IntCode:
            if str(typeobj).find("unsigned") >= 0:
                if typeobj.sizeof == 1:
                    return Hex2EncodedUInt1
                if typeobj.sizeof == 2:
                    return Hex2EncodedUInt2
                if typeobj.sizeof == 4:
                    return Hex2EncodedUInt4
                if typeobj.sizeof == 8:
                    return Hex2EncodedUInt8
            else:
                if typeobj.sizeof == 1:
                    return Hex2EncodedInt1
                if typeobj.sizeof == 2:
                    return Hex2EncodedInt2
                if typeobj.sizeof == 4:
                    return Hex2EncodedInt4
                if typeobj.sizeof == 8:
                    return Hex2EncodedInt8
        if code == FloatCode:
            if typeobj.sizeof == 4:
                return Hex2EncodedFloat4
            if typeobj.sizeof == 8:
                return Hex2EncodedFloat8
        return None

hjk's avatar
hjk committed
986 987 988 989 990 991
    def isReferenceType(self, typeobj):
        return typeobj.code == gdb.TYPE_CODE_REF

    def isStructType(self, typeobj):
        return typeobj.code == gdb.TYPE_CODE_STRUCT

992 993
    def isFunctionType(self, typeobj):
        return typeobj.code == MethodCode or typeobj.code == FunctionCode
hjk's avatar
hjk committed
994

995 996 997 998 999 1000 1001 1002 1003
    def putItem(self, value, tryDynamic=True):
        if value is None:
            # Happens for non-available watchers in gdb versions that
            # need to use gdb.execute instead of gdb.parse_and_eval
            self.putValue("<not available>")
            self.putType("<unknown>")
            self.putNumChild(0)
            return

1004 1005
        typeobj = value.type.unqualified()
        typeName = str(typeobj)
1006 1007 1008 1009 1010 1011 1012

        if value.is_optimized_out:
            self.putValue("<optimized out>")
            self.putType(typeName)
            self.putNumChild(0)
            return

1013
        tryDynamic &= self.useDynamicType
1014
        self.addToCache(typeobj) # Fill type cache
1015 1016 1017 1018 1019
        if tryDynamic:
            self.putAddress(value.address)

        # FIXME: Gui shows references stripped?
        #warn(" ")
1020 1021 1022 1023
        #warn("REAL INAME: %s" % self.currentIName)
        #warn("REAL TYPE: %s" % value.type)
        #warn("REAL CODE: %s" % value.type.code)
        #warn("REAL VALUE: %s" % value)
1024

1025
        if typeobj.code == ReferenceCode:
1026 1027
            try:
                # Try to recognize null references explicitly.
1028
                if toInteger(value.address) == 0:
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052
                    self.putValue("<null reference>")
                    self.putType(typeName)
                    self.putNumChild(0)
                    return
            except:
                pass

            if tryDynamic:
                try:
                    # Dynamic references are not supported by gdb, see
                    # http://sourceware.org/bugzilla/show_bug.cgi?id=14077.
                    # Find the dynamic type manually using referenced_type.
                    value = value.referenced_value()
                    value = value.cast(value.dynamic_type)
                    self.putItem(value)
                    self.putBetterType("%s &" % value.type)
                    return
                except:
                    pass

            try:
                # FIXME: This throws "RuntimeError: Attempt to dereference a
                # generic pointer." with MinGW's gcc 4.5 when it "identifies"
                # a "QWidget &" as "void &" and with optimized out code.
1053
                self.putItem(value.cast(typeobj.target().unqualified()))
hjk's avatar
hjk committed
1054
                self.putBetterType("%s &" % self.currentType.value)
1055 1056 1057 1058 1059 1060 1061
                return
            except RuntimeError:
                self.putValue("<optimized out reference>")
                self.putType(typeName)
                self.putNumChild(0)
                return

1062
        if typeobj.code == IntCode or typeobj.code == CharCode:
1063
            self.putType(typeName)
1064
            if typeobj.sizeof == 1:
1065 1066
                # Force unadorned value transport for char and Co.
                self.putValue(int(value) & 0xff)
1067 1068 1069 1070 1071
            else:
                self.putValue(value)
            self.putNumChild(0)
            return

1072
        if typeobj.code == FloatCode or typeobj.code == BoolCode:
1073
            self.putType(typeName)
1074
            self.putValue(value)
1075 1076 1077
            self.putNumChild(0)
            return

1078
        if typeobj.code == EnumCode:
1079
            self.putType(typeName)
1080
            self.putValue("%s (%d)" % (value, value))
1081 1082 1083
            self.putNumChild(0)
            return

1084
        if typeobj.code == ComplexCode:
1085
            self.putType(typeName)
1086
            self.putValue("%s" % value)
1087 1088 1089
            self.putNumChild(0)
            return

1090
        if typeobj.code == TypedefCode:
1091
            if typeName in self.qqDumpers:
1092
                self.putType(typeName)
1093
                self.qqDumpers[typeName](self, value)
1094 1095
                return

1096
            typeobj = stripTypedefs(typeobj)
1097 1098 1099
            # The cast can destroy the address?
            #self.putAddress(value.address)
            # Workaround for http://sourceware.org/bugzilla/show_bug.cgi?id=13380
1100 1101
            if typeobj.code == ArrayCode:
                value = self.parseAndEvaluate("{%s}%s" % (typeobj, value.address))
1102 1103
            else:
                try:
1104
                    value = value.cast(typeobj)
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
                except:
                    self.putValue("<optimized out typedef>")
                    self.putType(typeName)
                    self.putNumChild(0)
                    return

            self.putItem(value)
            self.putBetterType(typeName)
            return

1115
        if typeobj.code == ArrayCode:
1116
            self.putCStyleArray(value)
1117 1118
            return

1119
        if typeobj.code == PointerCode:
1120 1121
            # This could still be stored in a register and
            # potentially dereferencable.
hjk's avatar
hjk committed
1122
            self.putFormattedPointer(value)
1123 1124
            return

1125 1126 1127 1128
        if typeobj.code == MethodPointerCode \
                or typeobj.code == MethodCode \
                or typeobj.code == FunctionCode \
                or typeobj.code == MemberPointerCode:
1129 1130 1131 1132 1133 1134 1135 1136
            self.putType(typeName)
            self.putValue(value)
            self.putNumChild(0)
            return

        if typeName.startswith("<anon"):
            # Anonymous union. We need a dummy name to distinguish
            # multiple anonymous unions in the struct.
1137
            self.putType(typeobj)
1138 1139 1140
            self.putValue("{...}")
            self.anonNumber += 1
            with Children(self, 1):
1141
                self.listAnonymous(value, "#%d" % self.anonNumber, typeobj)
1142 1143
            return

1144
        if typeobj.code == StringCode:
1145
            # FORTRAN strings
1146
            size = typeobj.sizeof
1147
            data = self.readMemory(value.address, size)
1148
            self.putValue(data, Hex2EncodedLatin1, 1)
1149
            self.putType(typeobj)
1150

1151 1152
        if typeobj.code != StructCode and typeobj.code != UnionCode:
            warn("WRONG ASSUMPTION HERE: %s " % typeobj.code)
1153 1154 1155 1156
            check(False)


        if tryDynamic:
1157
            self.putItem(self.expensiveDowncast(value), False)