Currently supports pretty printing of: - tint::Utils::Vector, VectorRef, and Slice - tint::Utils::Hashset, Hashmap Change-Id: Ifbf2547b0f87d7fde8d9ff0dd458aa35c5fd57f4 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/106720 Reviewed-by: dan sinclair <dsinclair@google.com> Reviewed-by: Dan Sinclair <dsinclair@chromium.org> Commit-Queue: Antonio Maiorano <amaiorano@google.com> Kokoro: Kokoro <noreply+kokoro@google.com>main
parent
c3cbc35650
commit
14b5fb6f17
@ -0,0 +1,249 @@ |
||||
# Copyright 2022 The Tint Authors. |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
|
||||
# Pretty printers for the Tint project. |
||||
# Add a line to your ~/.gdbinit to source this file, e.g.: |
||||
# |
||||
# source /path/to/dawn/src/tint/tint_gdb.py |
||||
|
||||
import gdb |
||||
import gdb.printing |
||||
from itertools import chain |
||||
|
||||
# When debugging this module, set _DEBUGGING = True so that re-sourcing this file in gdb replaces |
||||
# the existing printers. |
||||
_DEBUGGING = True |
||||
|
||||
# Enable to display other data members along with child elements of compound data types (arrays, etc.). |
||||
# This is useful in debuggers like VS Code that doesn't display the `to_string()` result in the watch window. |
||||
# OTOH, it's less useful when using gdb/lldb's print command. |
||||
_DISPLAY_MEMBERS_AS_CHILDREN = False |
||||
|
||||
|
||||
# Tips for debugging using VS Code: |
||||
# - Set a breakpoint where you can view the types you want to debug/write pretty printers for. |
||||
# - Debug Console: source /path/to/dawn/src/tint/tint_gdb.py |
||||
# - To execute Python code, in the Debug Console: |
||||
# -exec python foo = gdb.parse_and_eval('map.set_') |
||||
# -exec python v = (foo['slots_']['impl_']['slice']['data'] + 8).dereference()['value'] |
||||
# |
||||
# - Useful docs: |
||||
# Python API: https://sourceware.org/gdb/onlinedocs/gdb/Python-API.html#Python-API |
||||
# Especially: |
||||
# Types: https://sourceware.org/gdb/onlinedocs/gdb/Types-In-Python.html#Types-In-Python |
||||
# Values: https://sourceware.org/gdb/onlinedocs/gdb/Values-From-Inferior.html#Values-From-Inferior |
||||
|
||||
|
||||
pp_set = gdb.printing.RegexpCollectionPrettyPrinter("tint") |
||||
|
||||
|
||||
class Printer(object): |
||||
'''Base class for Printers''' |
||||
|
||||
def __init__(self, val): |
||||
self.val = val |
||||
|
||||
def template_type(self, index): |
||||
'''Returns template type at index''' |
||||
return self.val.type.template_argument(index) |
||||
|
||||
|
||||
class UtilsSlicePrinter(Printer): |
||||
'''Printer for tint::utils::Slice<T>''' |
||||
|
||||
def __init__(self, val): |
||||
super(UtilsSlicePrinter, self).__init__(val) |
||||
self.len = self.val['len'] |
||||
self.cap = self.val['cap'] |
||||
self.data = self.val['data'] |
||||
self.elem_type = self.data.type.target().unqualified() |
||||
|
||||
def length(self): |
||||
return self.len |
||||
|
||||
def value_at(self, index): |
||||
'''Returns array value at index''' |
||||
return (self.data + index).dereference().cast(self.elem_type) |
||||
|
||||
def to_string(self): |
||||
return 'length={} capacity={}'.format(self.len, self.cap) |
||||
|
||||
def members(self): |
||||
if _DISPLAY_MEMBERS_AS_CHILDREN: |
||||
return [ |
||||
('length', self.len), |
||||
('capacity', self.cap), |
||||
] |
||||
else: |
||||
return [] |
||||
|
||||
def children(self): |
||||
for m in self.members(): |
||||
yield m |
||||
for i in range(self.len): |
||||
yield str(i), self.value_at(i) |
||||
|
||||
def display_hint(self): |
||||
return 'array' |
||||
|
||||
|
||||
pp_set.add_printer('UtilsSlicePrinter', |
||||
'^tint::utils::Slice<.*>$', UtilsSlicePrinter) |
||||
|
||||
|
||||
class UtilsVectorPrinter(Printer): |
||||
'''Printer for tint::utils::Vector<T, N>''' |
||||
|
||||
def __init__(self, val): |
||||
super(UtilsVectorPrinter, self).__init__(val) |
||||
self.slice = self.val['impl_']['slice'] |
||||
self.using_heap = self.slice['cap'] > self.template_type(1) |
||||
|
||||
def slice_printer(self): |
||||
return UtilsSlicePrinter(self.slice) |
||||
|
||||
def to_string(self): |
||||
return 'heap={} {}'.format(self.using_heap, self.slice) |
||||
|
||||
def members(self): |
||||
if _DISPLAY_MEMBERS_AS_CHILDREN: |
||||
return [ |
||||
('heap', self.using_heap), |
||||
] |
||||
else: |
||||
return [] |
||||
|
||||
def children(self): |
||||
return chain(self.members(), self.slice_printer().children()) |
||||
|
||||
def display_hint(self): |
||||
return 'array' |
||||
|
||||
|
||||
pp_set.add_printer( |
||||
'UtilsVector', '^tint::utils::Vector<.*>$', UtilsVectorPrinter) |
||||
|
||||
|
||||
class UtilsVectorRefPrinter(Printer): |
||||
'''Printer for tint::utils::VectorRef<T>''' |
||||
|
||||
def __init__(self, val): |
||||
super(UtilsVectorRefPrinter, self).__init__(val) |
||||
self.slice = self.val['slice_'] |
||||
self.can_move = self.val['can_move_'] |
||||
|
||||
def to_string(self): |
||||
return 'can_move={} {}'.format(self.can_move, self.slice) |
||||
|
||||
def members(self): |
||||
if _DISPLAY_MEMBERS_AS_CHILDREN: |
||||
return [ |
||||
('can_move', self.can_move), |
||||
] |
||||
else: |
||||
return [] |
||||
|
||||
def children(self): |
||||
return chain(self.members(), UtilsSlicePrinter(self.slice).children()) |
||||
|
||||
def display_hint(self): |
||||
return 'array' |
||||
|
||||
|
||||
pp_set.add_printer( |
||||
'UtilsVector', '^tint::utils::VectorRef<.*>$', UtilsVectorRefPrinter) |
||||
|
||||
|
||||
class UtilsHashsetPrinter(Printer): |
||||
'''Printer for Hashset<T, N, HASH, EQUAL>''' |
||||
|
||||
def __init__(self, val): |
||||
super(UtilsHashsetPrinter, self).__init__(val) |
||||
self.slice = UtilsVectorPrinter(self.val['slots_']).slice_printer() |
||||
self.try_read_std_optional_func = self.try_read_std_optional |
||||
|
||||
def to_string(self): |
||||
length = 0 |
||||
for slot in range(0, self.slice.length()): |
||||
v = self.slice.value_at(slot) |
||||
if v['hash'] != 0: |
||||
length += 1 |
||||
return 'length={}'.format(length) |
||||
|
||||
def children(self): |
||||
for slot in range(0, self.slice.length()): |
||||
v = self.slice.value_at(slot) |
||||
if v['hash'] != 0: |
||||
value = v['value'] |
||||
|
||||
# value is a std::optional, let's try to extract its value for display |
||||
kvp = self.try_read_std_optional_func(slot, value) |
||||
if kvp is None: |
||||
# If we failed, just output the slot and value as is, which will use |
||||
# the default visualizer for each. |
||||
kvp = slot, value |
||||
|
||||
yield str(kvp[0]), kvp[1] |
||||
|
||||
def display_hint(self): |
||||
return 'array' |
||||
|
||||
def try_read_std_optional(self, slot, value): |
||||
try: |
||||
# libstdc++ |
||||
v = value['_M_payload']['_M_payload']['_M_value'] |
||||
return slot, v |
||||
# return str(kvp['key']), kvp['value'] |
||||
except: |
||||
return None |
||||
|
||||
|
||||
pp_set.add_printer( |
||||
'UtilsHashset', '^tint::utils::Hashset<.*>$', UtilsHashsetPrinter) |
||||
|
||||
|
||||
class UtilsHashmapPrinter(Printer): |
||||
'''Printer for Hashmap<K, V, N, HASH, EQUAL>''' |
||||
|
||||
def __init__(self, val): |
||||
super(UtilsHashmapPrinter, self).__init__(val) |
||||
self.hash_set = UtilsHashsetPrinter(self.val['set_']) |
||||
# Replace the lookup function so we can extract the key and value out of the std::optionals in the Hashset |
||||
self.hash_set.try_read_std_optional_func = self.try_read_std_optional |
||||
|
||||
def to_string(self): |
||||
return self.hash_set.to_string() |
||||
|
||||
def children(self): |
||||
return self.hash_set.children() |
||||
|
||||
def display_hint(self): |
||||
return 'array' |
||||
|
||||
def try_read_std_optional(self, slot, value): |
||||
try: |
||||
# libstdc++ |
||||
kvp = value['_M_payload']['_M_payload']['_M_value'] |
||||
return str(kvp['key']), kvp['value'] |
||||
except: |
||||
pass |
||||
# Failed, fall back on hash_set |
||||
return self.hash_set.try_read_std_optional(slot, value) |
||||
|
||||
|
||||
pp_set.add_printer( |
||||
'UtilsHashmap', '^tint::utils::Hashmap<.*>$', UtilsHashmapPrinter) |
||||
|
||||
|
||||
gdb.printing.register_pretty_printer(gdb, pp_set, replace=_DEBUGGING) |
@ -0,0 +1,397 @@ |
||||
# Copyright 2022 The Tint Authors. |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
|
||||
# Pretty printers for the Tint project. |
||||
# |
||||
# If using lldb from command line, add a line to your ~/.lldbinit to import the printers: |
||||
# |
||||
# command script import /path/to/dawn/src/tint/tint_lldb.py |
||||
# |
||||
# |
||||
# If using VS Code on MacOS with the Microsoft C/C++ extension, add the following to |
||||
# your launch.json (make sure you specify an absolute path to tint_lldb.py): |
||||
# |
||||
# "name": "Launch", |
||||
# "type": "cppdbg", |
||||
# "request": "launch", |
||||
# ... |
||||
# "setupCommands": [ |
||||
# { |
||||
# "description": "Load tint pretty printers", |
||||
# "ignoreFailures": false, |
||||
# "text": "command script import /path/to/dawn/src/tint/tint_lldb.py, |
||||
# } |
||||
# ] |
||||
# |
||||
# If using VS Code with the CodeLLDB extension (https://github.com/vadimcn/vscode-lldb), |
||||
# add the following to your launch.json: |
||||
# |
||||
# "name": "Launch", |
||||
# "type": "lldb", |
||||
# "request": "launch", |
||||
# ... |
||||
# "initCommands": [ |
||||
# "command script import /path/to/dawn/src/tint/tint_lldb.py" |
||||
# ] |
||||
|
||||
# Based on pretty printers for: |
||||
# Rust: https://github.com/vadimcn/vscode-lldb/blob/master/formatters/rust.py |
||||
# Dlang: https://github.com/Pure-D/dlang-debug/blob/master/lldb_dlang.py |
||||
# |
||||
# |
||||
# Tips for debugging using VS Code: |
||||
# |
||||
# - Set a breakpoint where you can view the types you want to debug/write pretty printers for. |
||||
# - Debug Console: -exec command script import /path/to/dawn/src/tint/tint_lldb.py |
||||
# - You can re-run the above command to reload the printers after modifying the python script. |
||||
|
||||
# - Useful docs: |
||||
# Formattesr: https://lldb.llvm.org/use/variable.html |
||||
# Python API: https://lldb.llvm.org/python_api.html |
||||
# Especially: |
||||
# SBType: https://lldb.llvm.org/python_api/lldb.SBType.html |
||||
# SBValue: https://lldb.llvm.org/python_api/lldb.SBValue.html |
||||
|
||||
from __future__ import print_function, division |
||||
import sys |
||||
import logging |
||||
import re |
||||
import lldb |
||||
import types |
||||
|
||||
if sys.version_info[0] == 2: |
||||
# python2-based LLDB accepts utf8-encoded ascii strings only. |
||||
def to_lldb_str(s): return s.encode( |
||||
'utf8', 'backslashreplace') if isinstance(s, unicode) else s |
||||
range = xrange |
||||
else: |
||||
to_lldb_str = str |
||||
|
||||
string_encoding = "escape" # remove | unicode | escape |
||||
|
||||
log = logging.getLogger(__name__) |
||||
|
||||
module = sys.modules[__name__] |
||||
tint_category = None |
||||
|
||||
|
||||
def __lldb_init_module(debugger, dict): |
||||
global tint_category |
||||
|
||||
tint_category = debugger.CreateCategory('tint') |
||||
tint_category.SetEnabled(True) |
||||
|
||||
attach_synthetic_to_type( |
||||
UtilsSlicePrinter, r'^tint::utils::Slice<.+>$', True) |
||||
|
||||
attach_synthetic_to_type( |
||||
UtilsVectorPrinter, r'^tint::utils::Vector<.+>$', True) |
||||
|
||||
attach_synthetic_to_type( |
||||
UtilsVectorRefPrinter, r'^tint::utils::VectorRef<.+>$', True) |
||||
|
||||
attach_synthetic_to_type( |
||||
UtilsHashsetPrinter, r'^tint::utils::Hashset<.+>$', True) |
||||
|
||||
attach_synthetic_to_type( |
||||
UtilsHashmapPrinter, r'^tint::utils::Hashmap<.+>$', True) |
||||
|
||||
|
||||
def attach_synthetic_to_type(synth_class, type_name, is_regex=False): |
||||
global module, tint_category |
||||
synth = lldb.SBTypeSynthetic.CreateWithClassName( |
||||
__name__ + '.' + synth_class.__name__) |
||||
synth.SetOptions(lldb.eTypeOptionCascade) |
||||
ret = tint_category.AddTypeSynthetic( |
||||
lldb.SBTypeNameSpecifier(type_name, is_regex), synth) |
||||
log.debug('attaching synthetic %s to "%s", is_regex=%s -> %s', |
||||
synth_class.__name__, type_name, is_regex, ret) |
||||
|
||||
def summary_fn(valobj, dict): return get_synth_summary( |
||||
synth_class, valobj, dict) |
||||
# LLDB accesses summary fn's by name, so we need to create a unique one. |
||||
summary_fn.__name__ = '_get_synth_summary_' + synth_class.__name__ |
||||
setattr(module, summary_fn.__name__, summary_fn) |
||||
attach_summary_to_type(summary_fn, type_name, is_regex) |
||||
|
||||
|
||||
def attach_summary_to_type(summary_fn, type_name, is_regex=False): |
||||
global module, tint_category |
||||
summary = lldb.SBTypeSummary.CreateWithFunctionName( |
||||
__name__ + '.' + summary_fn.__name__) |
||||
summary.SetOptions(lldb.eTypeOptionCascade) |
||||
ret = tint_category.AddTypeSummary( |
||||
lldb.SBTypeNameSpecifier(type_name, is_regex), summary) |
||||
log.debug('attaching summary %s to "%s", is_regex=%s -> %s', |
||||
summary_fn.__name__, type_name, is_regex, ret) |
||||
|
||||
|
||||
def get_synth_summary(synth_class, valobj, dict): |
||||
'''' |
||||
get_summary' is annoyingly not a part of the standard LLDB synth provider API. |
||||
This trick allows us to share data extraction logic between synth providers and their sibling summary providers. |
||||
''' |
||||
synth = synth_class(valobj.GetNonSyntheticValue(), dict) |
||||
synth.update() |
||||
summary = synth.get_summary() |
||||
return to_lldb_str(summary) |
||||
|
||||
|
||||
def member(valobj, *chain): |
||||
'''Performs chained GetChildMemberWithName lookups''' |
||||
for name in chain: |
||||
valobj = valobj.GetChildMemberWithName(name) |
||||
return valobj |
||||
|
||||
|
||||
class Printer(object): |
||||
'''Base class for Printers''' |
||||
|
||||
def __init__(self, valobj, dict={}): |
||||
self.valobj = valobj |
||||
self.initialize() |
||||
|
||||
def initialize(self): |
||||
return None |
||||
|
||||
def update(self): |
||||
return False |
||||
|
||||
def num_children(self): |
||||
return 0 |
||||
|
||||
def has_children(self): |
||||
return False |
||||
|
||||
def get_child_at_index(self, index): |
||||
return None |
||||
|
||||
def get_child_index(self, name): |
||||
return None |
||||
|
||||
def get_summary(self): |
||||
return None |
||||
|
||||
def member(self, *chain): |
||||
'''Performs chained GetChildMemberWithName lookups''' |
||||
return member(self.valobj, *chain) |
||||
|
||||
def template_params(self): |
||||
'''Returns list of template params values (as strings)''' |
||||
type_name = self.valobj.GetTypeName() |
||||
params = [] |
||||
level = 0 |
||||
start = 0 |
||||
for i, c in enumerate(type_name): |
||||
if c == '<': |
||||
level += 1 |
||||
if level == 1: |
||||
start = i + 1 |
||||
elif c == '>': |
||||
level -= 1 |
||||
if level == 0: |
||||
params.append(type_name[start:i].strip()) |
||||
elif c == ',' and level == 1: |
||||
params.append(type_name[start:i].strip()) |
||||
start = i + 1 |
||||
return params |
||||
|
||||
def template_param_at(self, index): |
||||
'''Returns template param value at index (as string)''' |
||||
return self.template_params()[index] |
||||
|
||||
|
||||
class UtilsSlicePrinter(Printer): |
||||
'''Printer for tint::utils::Slice<T>''' |
||||
|
||||
def initialize(self): |
||||
self.len = self.valobj.GetChildMemberWithName('len') |
||||
self.cap = self.valobj.GetChildMemberWithName('cap') |
||||
self.data = self.valobj.GetChildMemberWithName('data') |
||||
self.elem_type = self.data.GetType().GetPointeeType() |
||||
self.elem_size = self.elem_type.GetByteSize() |
||||
|
||||
def get_summary(self): |
||||
return 'length={} capacity={}'.format(self.len.GetValueAsUnsigned(), self.cap.GetValueAsUnsigned()) |
||||
|
||||
def num_children(self): |
||||
# NOTE: VS Code on MacOS hangs if we try to expand something too large, so put an artificial limit |
||||
# until we can figure out how to know if this is a valid instance. |
||||
return min(self.len.GetValueAsUnsigned(), 256) |
||||
|
||||
def has_children(self): |
||||
return True |
||||
|
||||
def get_child_at_index(self, index): |
||||
try: |
||||
if not 0 <= index < self.num_children(): |
||||
return None |
||||
# TODO: return self.value_at(index) |
||||
offset = index * self.elem_size |
||||
return self.data.CreateChildAtOffset('[%s]' % index, offset, self.elem_type) |
||||
except Exception as e: |
||||
log.error('%s', e) |
||||
raise |
||||
|
||||
def value_at(self, index): |
||||
'''Returns array value at index''' |
||||
offset = index * self.elem_size |
||||
return self.data.CreateChildAtOffset('[%s]' % index, offset, self.elem_type) |
||||
|
||||
|
||||
class UtilsVectorPrinter(Printer): |
||||
'''Printer for tint::utils::Vector<T, N>''' |
||||
|
||||
def initialize(self): |
||||
self.slice = self.member('impl_', 'slice') |
||||
self.slice_printer = UtilsSlicePrinter(self.slice) |
||||
self.fixed_size = int(self.template_param_at(1)) |
||||
self.cap = self.slice_printer.member('cap') |
||||
|
||||
def get_summary(self): |
||||
using_heap = self.cap.GetValueAsUnsigned() > self.fixed_size |
||||
return 'heap={} {}'.format(using_heap, self.slice_printer.get_summary()) |
||||
|
||||
def num_children(self): |
||||
return self.slice_printer.num_children() |
||||
|
||||
def has_children(self): |
||||
return self.slice_printer.has_children() |
||||
|
||||
def get_child_at_index(self, index): |
||||
return self.slice_printer.get_child_at_index(index) |
||||
|
||||
def make_slice_printer(self): |
||||
return UtilsSlicePrinter(self.slice) |
||||
|
||||
|
||||
class UtilsVectorRefPrinter(Printer): |
||||
'''Printer for tint::utils::VectorRef<T>''' |
||||
|
||||
def initialize(self): |
||||
self.slice = self.member('slice_') |
||||
self.slice_printer = UtilsSlicePrinter(self.slice) |
||||
self.can_move = self.member('can_move_') |
||||
|
||||
def get_summary(self): |
||||
return 'can_move={} {}'.format(self.can_move.GetValue(), self.slice_printer.get_summary()) |
||||
|
||||
def num_children(self): |
||||
return self.slice_printer.num_children() |
||||
|
||||
def has_children(self): |
||||
return self.slice_printer.has_children() |
||||
|
||||
def get_child_at_index(self, index): |
||||
return self.slice_printer.get_child_at_index(index) |
||||
|
||||
|
||||
class UtilsHashsetPrinter(Printer): |
||||
'''Printer for Hashset<T, N, HASH, EQUAL>''' |
||||
|
||||
def initialize(self): |
||||
self.slice = UtilsVectorPrinter( |
||||
self.member('slots_')).make_slice_printer() |
||||
|
||||
self.try_read_std_optional_func = self.try_read_std_optional |
||||
|
||||
def update(self): |
||||
self.valid_slots = [] |
||||
for slot in range(0, self.slice.num_children()): |
||||
v = self.slice.value_at(slot) |
||||
if member(v, 'hash').GetValueAsUnsigned() != 0: |
||||
self.valid_slots.append(slot) |
||||
return False |
||||
|
||||
def get_summary(self): |
||||
return 'length={}'.format(self.num_children()) |
||||
|
||||
def num_children(self): |
||||
return len(self.valid_slots) |
||||
|
||||
def has_children(self): |
||||
return True |
||||
|
||||
def get_child_at_index(self, index): |
||||
slot = self.valid_slots[index] |
||||
v = self.slice.value_at(slot) |
||||
value = member(v, 'value') |
||||
|
||||
# value is a std::optional, let's try to extract its value for display |
||||
kvp = self.try_read_std_optional_func(slot, value) |
||||
if kvp is None: |
||||
# If we failed, just output the slot and value as is, which will use |
||||
# the default printer for std::optional. |
||||
kvp = slot, value |
||||
|
||||
return kvp[1].CreateChildAtOffset('[{}]'.format(kvp[0]), 0, kvp[1].GetType()) |
||||
|
||||
def try_read_std_optional(self, slot, value): |
||||
try: |
||||
# libc++ |
||||
v = value.EvaluateExpression('__val_') |
||||
if v.name is not None: |
||||
return slot, v |
||||
|
||||
# libstdc++ |
||||
v = value.EvaluateExpression('_M_payload._M_payload._M_value') |
||||
if v.name is not None: |
||||
return slot, v |
||||
return None |
||||
except: |
||||
return None |
||||
|
||||
|
||||
class UtilsHashmapPrinter(Printer): |
||||
'''Printer for Hashmap<K, V, N, HASH, EQUAL>''' |
||||
|
||||
def initialize(self): |
||||
self.hash_set = UtilsHashsetPrinter(self.member('set_')) |
||||
# Replace the lookup function so we can extract the key and value out of the std::optionals in the Hashset |
||||
self.hash_set.try_read_std_optional_func = self.try_read_std_optional |
||||
|
||||
def update(self): |
||||
self.hash_set.update() |
||||
|
||||
def get_summary(self): |
||||
return self.hash_set.get_summary() |
||||
|
||||
def num_children(self): |
||||
return self.hash_set.num_children() |
||||
|
||||
def has_children(self): |
||||
return self.hash_set.has_children() |
||||
|
||||
def get_child_at_index(self, index): |
||||
return self.hash_set.get_child_at_index(index) |
||||
|
||||
def try_read_std_optional(self, slot, value): |
||||
try: |
||||
# libc++ |
||||
val = value.EvaluateExpression('__val_') |
||||
k = val.EvaluateExpression('key') |
||||
v = val.EvaluateExpression('value') |
||||
if k.name is not None and v.name is not None: |
||||
return k.GetValue(), v |
||||
|
||||
# libstdc++ |
||||
val = value.EvaluateExpression('_M_payload._M_payload._M_value') |
||||
k = val.EvaluateExpression('key') |
||||
v = val.EvaluateExpression('value') |
||||
if k.name is not None and v.name is not None: |
||||
return k.GetValue(), v |
||||
except: |
||||
pass |
||||
# Failed, fall back on hash_set |
||||
return self.hash_set.try_read_std_optional(slot, value) |
Loading…
Reference in new issue