gdbbridge.py 65 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
        lister = getattr(printer, "children", None)
        children = [] if lister is None else list(lister())
        d.putType(self.printer.name)
174 175 176 177 178 179
        val = printer.to_string()
        if isinstance(val, str):
            d.putValue(val)
        else: # Assuming LazyString
            d.putStdStringHelper(val.address, val.length, val.type.sizeof)

180 181 182 183 184 185 186
        d.putNumChild(len(children))
        if d.isExpanded():
            with Children(d):
                for child in children:
                    d.putSubItem(child[0], child[1])

def importPlainDumpers(args):
187
    theDumper.importPlainDumpers()
188 189 190 191

registerCommand("importPlainDumpers", importPlainDumpers)


192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212

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):
213 214
#    typeobj = lookupType("unsigned int")
#    ptr = gdb.Value(p).cast(typeobj)
215 216 217 218 219 220 221 222 223
#    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



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


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

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


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

def bbedit(args):
249
    theDumper.bbedit(args)
250 251 252 253 254 255 256 257 258 259

registerCommand("bbedit", bbedit)


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

260

261
def bb(args):
262 263 264 265 266
    try:
        print(theDumper.run(args))
    except:
        import traceback
        traceback.print_exc()
267 268

registerCommand("bb", bb)
269

270 271 272 273 274 275 276
#######################################################################
#
# The Dumper Class
#
#######################################################################


277 278
class Dumper(DumperBase):

279
    def __init__(self):
280 281
        DumperBase.__init__(self)

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

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

305 306 307 308 309
        # 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

310 311 312 313
        self.watchers = ""
        self.resultVarName = ""
        self.varList = []
        self.options = []
314 315 316 317

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

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

359 360 361 362 363 364 365
    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)

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 445 446 447
    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


448 449 450
    def run(self, args):
        self.prepare(args)

451 452 453
        #
        # Locals
        #
454
        self.output.append('data=[')
455
        if self.partialUpdate and len(self.varList) == 1:
456 457
            #warn("PARTIAL: %s" % self.varList)
            parts = self.varList[0].split('.')
458 459 460
            #warn("PARTIAL PARTS: %s" % parts)
            name = parts[1]
            #warn("PARTIAL VAR: %s" % name)
461 462 463
            item = LocalItem()
            item.iname = parts[0] + '.' + name
            item.name = name
464
            try:
465 466 467 468 469 470 471 472
                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
473
            except:
474 475 476 477
                item.value = "<no value>"
            locals = [item]
            #warn("PARTIAL LOCALS: %s" % locals)
        else:
478
            locals = self.listOfLocals()
479 480

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

        for item in locals:
493
            value = self.downcast(item.value) if self.useDynamicType else item.value
494 495 496
            with OutputSafer(self):
                self.anonNumber = -1

497 498
                if item.iname == "local.argv" and str(value.type) == "char **":
                    self.putSpecialArgv(value)
499 500 501 502 503 504 505
                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)

506
        self.handleWatches()
507

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

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

520
        if "forcens" in self.options:
521
            self.qtNamepaceToReport = self.qtNamespace()
522

523 524 525 526
        if self.qtNamespaceToReport:
            self.output.append(',qtnamespace="%s"' % self.qtNamespaceToReport)
            self.qtNamespaceToReport = None

527
        return "".join(self.output)
528

529 530 531 532 533 534 535 536 537 538 539 540 541
    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
542 543
        self.currentValue = ReportItem();
        self.currentType = ReportItem();
544 545 546
        self.currentAddress = None

    def exitSubItem(self, item, exType, exValue, exTraceBack):
hjk's avatar
hjk committed
547
        #warn("CURRENT VALUE: %s: %s %s" % (self.currentIName, self.currentValue, self.currentType))
548 549 550 551 552 553
        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
554
            if self.currentType.value:
555
                typeName = self.stripClassTag(self.currentType.value)
hjk's avatar
hjk committed
556 557
                if len(typeName) > 0 and typeName != self.currentChildType:
                    self.put('type="%s",' % typeName) # str(type.unqualified()) ?
558

559
            if  self.currentValue.value is None:
560 561
                self.put('value="<not accessible>",numchild="0",')
            else:
562 563 564 565 566
                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)
567 568 569 570 571 572 573 574 575 576 577
        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

578 579 580
    def parseAndEvaluate(self, exp):
        return gdb.parse_and_eval(exp)

581
    def callHelper(self, value, func, args):
582 583 584 585 586 587 588 589 590 591 592 593
        # 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))
594
        typeName = self.stripClassTag(str(value.type))
595 596
        if typeName.find(":") >= 0:
            typeName = "'" + typeName + "'"
597
        # 'class' is needed, see http://sourceware.org/bugzilla/show_bug.cgi?id=11912
598 599 600
        #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)
601
        #warn("CALL: %s" % exp)
602
        result = gdb.parse_and_eval(exp)
603
        #warn("  -> %s" % result)
604 605
        if not value.address:
            gdb.parse_and_eval("free(0x%x)" % ptr)
606 607
        return result

hjk's avatar
hjk committed
608
    def childWithName(self, value, name):
609
        try:
hjk's avatar
hjk committed
610
            return value[name]
611
        except:
hjk's avatar
hjk committed
612
            return None
613

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

    def makeExpression(self, value):
626 627 628 629
        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
630 631 632 633 634 635 636 637
        #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
638
        value = gdb.parse_and_eval("$d").dereference()
hjk's avatar
hjk committed
639 640 641 642 643
        #warn("  TYPE: %s" % value.type)
        #warn("  ADDR: %s" % value.address)
        #warn("  VALUE: %s" % value)
        return value

644 645
    def childAt(self, value, index):
        field = value.type.fields()[index]
646 647 648 649 650 651 652 653 654 655 656 657 658
        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
659

660 661 662 663 664 665
        # 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

666 667
    def fieldAt(self, typeobj, index):
        return typeobj.fields()[index]
668

669 670 671
    def simpleValue(self, value):
        return str(value)

672
    def directBaseClass(self, typeobj, index = 0):
673 674 675 676 677
        for f in typeobj.fields():
            if f.is_base_class:
                if index == 0:
                    return f.type
                index -= 1;
hjk's avatar
hjk committed
678 679 680 681 682 683 684 685
        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;
686
        return None
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701

    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
702
        #    return p.cast(self.lookupType("void").pointer()) == 0
703 704 705 706 707 708 709 710
        #except:
        #    return False
        try:
            # Can fail with: "RuntimeError: Cannot access memory at address 0x5"
            return toInteger(p) == 0
        except:
            return False

711
    def templateArgument(self, typeobj, position):
712 713 714 715 716 717 718
        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))
719 720

    def numericTemplateArgument(self, typeobj, position):
721 722 723 724 725 726 727 728 729 730 731 732
        # 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)
733

734
    def intType(self):
735 736 737
        self.cachedIntType = self.lookupType('int')
        self.intType = lambda: self.cachedIntType
        return self.cachedIntType
738 739

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

    def sizetType(self):
hjk's avatar
hjk committed
743
        return self.lookupType('size_t')
744 745

    def charPtrType(self):
hjk's avatar
hjk committed
746
        return self.lookupType('char*')
747 748

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

751
    def addressOf(self, value):
752
        return toInteger(value.address)
753

754
    def createPointerValue(self, address, pointeeType):
755 756 757 758 759 760 761 762
        # 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))
763 764 765 766 767

    def intSize(self):
        return 4

    def ptrSize(self):
768 769 770
        self.cachedPtrSize = self.lookupType('void*').sizeof
        self.ptrSize = lambda: self.cachedPtrSize
        return self.cachedPtrSize
771

772 773 774 775 776 777 778 779 780 781 782 783 784 785
    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))


786
    def createValue(self, address, referencedType):
787 788 789 790 791
        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))
792

793 794
    def setValue(self, address, typename, value):
        cmd = "set {%s}%s=%s" % (typename, address, value)
795 796
        gdb.execute(cmd)

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

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

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

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

820 821 822
    def extractInt64(self, addr):
        return struct.unpack("q", self.readRawMemory(addr, 8))[0]

823
    def extractInt(self, addr):
824
        return struct.unpack("i", self.readRawMemory(addr, 4))[0]
825

826
    def extractByte(self, addr):
827
        return struct.unpack("b", self.readRawMemory(addr, 1))[0]
828

829 830
    def findStaticMetaObject(self, typename):
        return self.findSymbol(typename + "::staticMetaObject")
831

832 833 834 835 836 837 838 839
    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:
840
            address = gdb.parse_and_eval("&'%s'" % symbolName)
841 842
            typeobj = gdb.lookup_type(self.qtNamespace() + "QMetaObject")
            return self.createPointerValue(address, typeobj)
843 844
        except:
            return 0
845

846 847 848 849 850
    def put(self, value):
        self.output.append(value)

    def childRange(self):
        if self.currentMaxNumChild is None:
851 852
            return xrange(0, toInteger(self.currentNumChild))
        return xrange(min(toInteger(self.currentMaxNumChild), toInteger(self.currentNumChild)))
853

854 855 856 857 858 859
    def isArmArchitecture(self):
        return 'arm' in gdb.TARGET_CONFIG.lower()

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

860 861 862 863
    def isWindowsTarget(self):
        # We get i686-w64-mingw32
        return 'mingw' in gdb.TARGET_CONFIG.lower()

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

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

887 888 889 890 891 892 893 894 895 896 897 898 899 900 901
    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

902
    def putAddress(self, addr):
903
        if self.currentPrintsAddress and not self.isCli:
904
            try:
905 906 907
                # addr can be "None", int(None) fails.
                #self.put('addr="0x%x",' % int(addr))
                self.currentAddress = 'addr="0x%x",' % toInteger(addr)
908 909 910 911 912 913 914 915
            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
916 917 918
    def putSimpleValue(self, value, encoding = None, priority = 0):
        self.putValue(value, encoding, priority)

919 920 921 922 923 924
    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
925
                self.lookupType("unsigned long")), None, -1)
926 927

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

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

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

951 952 953 954 955 956
    def isSimpleType(self, typeobj):
        code = typeobj.code
        return code == BoolCode \
            or code == CharCode \
            or code == IntCode \
            or code == FloatCode \
957
            or code == EnumCode
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 986 987 988

    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
989 990 991 992 993 994
    def isReferenceType(self, typeobj):
        return typeobj.code == gdb.TYPE_CODE_REF

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

995 996
    def isFunctionType(self, typeobj):
        return typeobj.code == MethodCode or typeobj.code == FunctionCode
hjk's avatar
hjk committed
997

998 999 1000 1001 1002 1003 1004 1005 1006
    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

1007 1008
        typeobj = value.type.unqualified()
        typeName = str(typeobj)
1009 1010 1011 1012 1013 1014 1015

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

1016
        tryDynamic &= self.useDynamicType
1017
        self.addToCache(typeobj) # Fill type cache
1018 1019 1020 1021 1022
        if tryDynamic:
            self.putAddress(value.address)

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

1028
        if typeobj.code == ReferenceCode:
1029 1030
            try:
                # Try to recognize null references explicitly.
1031
                if toInteger(value.address) == 0:
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
                    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.
1056
                self.putItem(value.cast(typeobj.target().unqualified()))
hjk's avatar
hjk committed
1057
                self.putBetterType("%s &" % self.currentType.value)
1058 1059 1060 1061 1062 1063 1064
                return
            except RuntimeError:
                self.putValue("<optimized out reference>")
                self.putType(typeName)
                self.putNumChild(0)
                return

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

1075
        if typeobj.code == FloatCode or typeobj.code == BoolCode:
1076
            self.putType(typeName)
1077
            self.putValue(value)
1078 1079 1080
            self.putNumChild(0)
            return

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

1087
        if typeobj.code == ComplexCode:
1088
            self.putType(typeName)
1089
            self.putValue("%s" % value)
1090 1091 1092
            self.putNumChild(0)
            return

1093
        if typeobj.code == TypedefCode:
1094
            if typeName in self.qqDumpers:
1095
                self.putType(typeName)
1096
                self.qqDumpers[typeName](self, value)
1097 1098
                return

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

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

1118
        if typeobj.code == ArrayCode:
1119
            self.putCStyleArray(value)
1120 1121
            return

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

1128 1129 1130 1131
        if typeobj.code == MethodPointerCode \
                or typeobj.code == MethodCode \
                or typeobj.code == FunctionCode \
                or typeobj.code == MemberPointerCode:
1132 1133 1134 1135 1136 1137 1138 1139
            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.
1140
            self.putType(typeobj)
1141 1142 1143
            self.putValue("{...}")
            self.anonNumber += 1
            with Children(self, 1):
1144
                self.listAnonymous(value, "#%d" % self.anonNumber, typeobj)
1145 1146
            return

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

1154 1155
        if typeobj.code != StructCode and typeobj.code != UnionCode:
            warn("WRONG ASSUMPTION HERE: %s " % typeobj.code)
1156 1157 1158