1# This Source Code Form is subject to the terms of the Mozilla Public
2# License, v. 2.0. If a copy of the MPL was not distributed with this file,
3# You can obtain one at http://mozilla.org/MPL/2.0/.
4
5# Pretty-printers for SpiderMonkey strings.
6
7import gdb
8import mozilla.prettyprinters
9from mozilla.prettyprinters import ptr_pretty_printer
10from mozilla.CellHeader import get_header_length_and_flags
11
12try:
13    chr(10000)  # UPPER RIGHT PENCIL
14except ValueError:  # yuck, we are in Python 2.x, so chr() is 8-bit
15    chr = unichr  # replace with teh unicodes
16
17# Forget any printers from previous loads of this module.
18mozilla.prettyprinters.clear_module_printers(__name__)
19
20
21class JSStringTypeCache(object):
22    # Cache information about the JSString type for this objfile.
23    def __init__(self, cache):
24        dummy = gdb.Value(0).cast(cache.JSString_ptr_t)
25        self.ATOM_BIT = dummy["ATOM_BIT"]
26        self.LINEAR_BIT = dummy["LINEAR_BIT"]
27        self.INLINE_CHARS_BIT = dummy["INLINE_CHARS_BIT"]
28        self.TYPE_FLAGS_MASK = dummy["TYPE_FLAGS_MASK"]
29        self.LATIN1_CHARS_BIT = dummy["LATIN1_CHARS_BIT"]
30
31
32class Common(mozilla.prettyprinters.Pointer):
33    def __init__(self, value, cache):
34        super(Common, self).__init__(value, cache)
35        if not cache.mod_JSString:
36            cache.mod_JSString = JSStringTypeCache(cache)
37        self.stc = cache.mod_JSString
38
39
40@ptr_pretty_printer("JSString")
41class JSStringPtr(Common):
42    def display_hint(self):
43        return "string"
44
45    def chars(self):
46        d = self.value["d"]
47        length, flags = get_header_length_and_flags(self.value, self.cache)
48
49        corrupt = {
50            0x2F2F2F2F: "JS_FRESH_NURSERY_PATTERN",
51            0x2B2B2B2B: "JS_SWEPT_NURSERY_PATTERN",
52            0xE5E5E5E5: "jemalloc freed memory",
53        }.get(flags & 0xFFFFFFFF)
54        if corrupt:
55            for ch in "<CORRUPT:%s>" % corrupt:
56                yield ch
57            return
58        is_rope = (flags & self.stc.LINEAR_BIT) == 0
59        if is_rope:
60            for c in JSStringPtr(d["s"]["u2"]["left"], self.cache).chars():
61                yield c
62            for c in JSStringPtr(d["s"]["u3"]["right"], self.cache).chars():
63                yield c
64        else:
65            is_inline = (flags & self.stc.INLINE_CHARS_BIT) != 0
66            is_latin1 = (flags & self.stc.LATIN1_CHARS_BIT) != 0
67            if is_inline:
68                if is_latin1:
69                    chars = d["inlineStorageLatin1"]
70                else:
71                    chars = d["inlineStorageTwoByte"]
72            else:
73                if is_latin1:
74                    chars = d["s"]["u2"]["nonInlineCharsLatin1"]
75                else:
76                    chars = d["s"]["u2"]["nonInlineCharsTwoByte"]
77            for i in range(int(length)):
78                yield chars[i]
79
80    def to_string(self, maxlen=200):
81        s = ""
82        invalid_chars_allowed = 2
83        for c in self.chars():
84            if len(s) >= maxlen:
85                s += "..."
86                break
87
88            try:
89                # Convert from gdb.Value to string.
90                s += chr(c)
91            except ValueError:
92                if invalid_chars_allowed == 0:
93                    s += "<TOO_MANY_INVALID_CHARS>"
94                    break
95                else:
96                    invalid_chars_allowed -= 1
97                    s += "\\x%04x" % (c & 0xFFFF)
98        return s
99
100
101@ptr_pretty_printer("JSAtom")
102class JSAtomPtr(Common):
103    def to_string(self):
104        return self.value.cast(self.cache.JSString_ptr_t)
105