-
Notifications
You must be signed in to change notification settings - Fork 121
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Julian Harbarth
authored
Nov 16, 2021
1 parent
7027047
commit 73fa8e6
Showing
7 changed files
with
385 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
import re | ||
import gdb.xmethod | ||
|
||
def is_cista_hash_storage(gdb_type): | ||
type_str = str(gdb_type.strip_typedefs()) | ||
return type_str.startswith("cista::hash_storage") and not type_str.endswith("::ctrl_t") | ||
|
||
class CistaHashStorage: | ||
def __init__(self, val): | ||
self.val = val | ||
self.entries = self.val['entries_'] | ||
self.capacity = self.val['capacity_'] | ||
self.ctrl = self.val['ctrl_'] | ||
|
||
regex = re.compile("cista::offset_ptr") | ||
if regex.match(str(self.entries.type.strip_typedefs())): | ||
self.entries = OffsetPointer(self.entries) | ||
self.ctrl = OffsetPointer(self.ctrl) | ||
|
||
def is_valid_entry(self, idx): | ||
return (self.ctrl + idx).dereference() & int('0b10000000', 2) == 0 | ||
|
||
def __len__(self): | ||
return int(self.val['size_']) | ||
|
||
def __getitem__(self, key): | ||
for i in range(self.val['capacity_']): | ||
if not self.is_valid_entry(i): | ||
continue | ||
|
||
entry = (self.entries + i).dereference() | ||
if str(entry['first']) == str(key): | ||
return entry['second'] | ||
|
||
class CistaHashStoragePrinter: | ||
def __init__(self, val): | ||
self.val = CistaHashStorage(val) | ||
|
||
def children(self): | ||
current_idx = 0 | ||
for i in range(self.val.capacity): | ||
if self.val.is_valid_entry(i): | ||
yield '[' + str(current_idx) + ']', (self.val.entries + i).dereference() | ||
current_idx += 1 | ||
|
||
def to_string(self): | ||
return str(self.val) | ||
|
||
def my_pp_func(val): | ||
if is_cista_hash_storage(val.type): | ||
return CistaHashStoragePrinter(val) | ||
|
||
### XMethod cista::vector::operator[] | ||
|
||
class CistaHashStorageWorker_operator_brackets(gdb.xmethod.XMethodWorker): | ||
def __init__(self, class_type): | ||
self.class_type = class_type | ||
|
||
def get_arg_types(self): | ||
return self.class_type.template_argument(0) | ||
|
||
def get_result_type(self, obj): | ||
return obj.type.strip_typedefs().template_argument(1) | ||
|
||
def __call__(self, this, key): | ||
hash_storage = CistaHashStorage(this.dereference()) | ||
return hash_storage[key] | ||
|
||
class CistaHashStorageWorker_operator_brackets_char_ptr(gdb.xmethod.XMethodWorker): | ||
def __init__(self, class_type): | ||
self.class_type = class_type | ||
|
||
def get_arg_types(self): | ||
return gdb.lookup_type('const char* const') | ||
|
||
def get_result_type(self, obj): | ||
return obj.type.strip_typedefs().template_argument(1) | ||
|
||
def __call__(self, this, key): | ||
hash_storage = CistaHashStorage(this.dereference()) | ||
key = key.cast(gdb.lookup_type("const char* const")) | ||
return hash_storage[str(key).split()[1]] | ||
|
||
class CistaHashStorage_operator_brackets(gdb.xmethod.XMethod): | ||
def __init__(self): | ||
gdb.xmethod.XMethod.__init__(self, 'operator[]') | ||
|
||
def get_worker(self, method_name, class_type): | ||
worker = [] | ||
if method_name == 'operator[]': | ||
worker.append(CistaHashStorageWorker_operator_brackets(class_type)) | ||
|
||
temp_arg = class_type.template_argument(0).name | ||
is_string = temp_arg.startswith("std::__cxx11::basic_string") \ | ||
or temp_arg.startswith("cista::basic_string") | ||
if method_name == 'operator[]' and is_string: | ||
worker.append(CistaHashStorageWorker_operator_brackets_char_ptr(class_type)) | ||
|
||
return worker | ||
|
||
### XMethod cista::vector::size | ||
|
||
class CistaHashStorageWorker_size(gdb.xmethod.XMethodWorker): | ||
def get_arg_types(self): | ||
return None | ||
|
||
def get_result_type(self): | ||
return gdb.lookup_type('unsigned long int') | ||
|
||
def __call__(self, this): | ||
hash_storage = CistaHashStorage(this.dereference()) | ||
return len(hash_storage) | ||
|
||
class CistaHashStorage_size(gdb.xmethod.XMethod): | ||
def __init__(self): | ||
gdb.xmethod.XMethod.__init__(self, 'size') | ||
|
||
def get_worker(self, method_name, _): | ||
if method_name == 'size': | ||
return [CistaHashStorageWorker_size()] | ||
|
||
class CistaHashStorageMatcher(gdb.xmethod.XMethodMatcher): | ||
def __init__(self): | ||
gdb.xmethod.XMethodMatcher.__init__(self, 'CistaHashStorageMatcher') | ||
# List of methods 'managed' by this matcher | ||
self.methods = [CistaHashStorage_operator_brackets(), CistaHashStorage_size()] | ||
|
||
def match(self, class_type, method_name): | ||
if not is_cista_hash_storage(class_type): | ||
return None | ||
|
||
workers = [] | ||
for method in self.methods: | ||
if method.enabled: | ||
worker = method.get_worker(method_name, class_type.template_argument(0)) | ||
if worker: | ||
workers.extend(worker) | ||
|
||
return workers | ||
|
||
gdb.pretty_printers.append(my_pp_func) | ||
gdb.xmethod.register_xmethod_matcher(None, CistaHashStorageMatcher()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import re | ||
|
||
class CistaOffsetPointerPrinter: | ||
def __init__(self, val): | ||
self.val = OffsetPointer(val) | ||
|
||
def children(self): | ||
yield "*", self.val.dereference() | ||
|
||
def to_string(self): | ||
return str(self.val) | ||
|
||
def my_pp_func(val): | ||
regex = re.compile("cista::offset_ptr") | ||
if regex.match(str(val.type.strip_typedefs())): | ||
return CistaOffsetPointerPrinter(val) | ||
|
||
gdb.pretty_printers.append(my_pp_func) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import re | ||
|
||
class CistaString: | ||
def __init__(self, val): | ||
self.val = val | ||
self.GDB_CHAR_PTR = gdb.lookup_type("char*") | ||
|
||
def is_short(self): | ||
return self.val['s_']['is_short_'] | ||
|
||
def data(self): | ||
return self.val['s_']['s_'] if self.is_short() else self.val['h_']['ptr_'] | ||
|
||
def str(self): | ||
if self.is_short(): | ||
return self.data().address.cast(self.GDB_CHAR_PTR) | ||
|
||
if is_offset_ptr(self.data().type): | ||
return OffsetPointer(self.data()).as_raw_ptr() | ||
|
||
return self.data() | ||
|
||
class CistaStringPrinter: | ||
def __init__(self, val): | ||
self.val = CistaString(val) | ||
|
||
def to_string(self): | ||
return self.val.str() | ||
|
||
def my_pp_func(val): | ||
regex = re.compile("cista::basic_string") | ||
if regex.match(str(val.type.strip_typedefs())): | ||
return CistaStringPrinter(val) | ||
|
||
gdb.pretty_printers.append(my_pp_func) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import re | ||
|
||
class CistaTuplePrinter: | ||
def __init__(self, val): | ||
self.val = val | ||
|
||
def children(self): | ||
yield '[0]', self.val['head_'] | ||
|
||
field_count = 1 | ||
local_val = self.val[self.val.type.fields()[0]] | ||
while True: | ||
yield '[' + str(field_count) + ']', local_val['head_'] | ||
field_count += 1 | ||
if (len(local_val.type.fields()) == 1): | ||
return | ||
else: | ||
local_val = local_val[local_val.type.fields()[0]] | ||
|
||
def to_string(self): | ||
return str(self.val) | ||
|
||
def my_pp_func(val): | ||
regex = re.compile("cista::tuple") | ||
if regex.match(str(val.type.strip_typedefs())): | ||
return CistaTuplePrinter(val) | ||
|
||
gdb.pretty_printers.append(my_pp_func) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import re | ||
|
||
class CistaVariantPrinter: | ||
def __init__(self, val): | ||
self.val = val | ||
|
||
def get_actual_type(self): | ||
return self.val.type.template_argument(self.val['idx_']) | ||
|
||
def children(self): | ||
for field in self.val.type.fields(): | ||
if (field.name == "storage_"): | ||
yield field.name, self.val[field.name].cast(self.get_actual_type()) | ||
else: | ||
yield field.name, self.val[field.name].cast(field.type) | ||
|
||
def to_string(self): | ||
return str(self.val) | ||
|
||
|
||
def my_pp_func(val): | ||
regex = re.compile("cista::variant") | ||
if regex.match(str(val.type.strip_typedefs())): | ||
return CistaVariantPrinter(val) | ||
|
||
gdb.pretty_printers.append(my_pp_func) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import re | ||
import gdb.xmethod | ||
|
||
def is_cista_vector(gdb_type): | ||
return str(gdb_type.strip_typedefs()).startswith("cista::basic_vector") | ||
|
||
def is_raw_vector(gdb_type): | ||
return not str(gdb_type.strip_typedefs().template_argument(1)).startswith("cista::offset_ptr") | ||
|
||
class CistaVector: | ||
def __init__(self, val): | ||
self.val = val | ||
self.size = val['used_size_'] | ||
self.el = val['el_'] if is_raw_vector(val.type) else OffsetPointer(val['el_']) | ||
|
||
def __len__(self): | ||
return self.size | ||
|
||
def __getitem__(self, idx): | ||
return (self.el + idx).dereference() | ||
|
||
def at(self, idx): | ||
if (self.size < idx): | ||
print("Accessing vector out of bounds") | ||
return None | ||
|
||
return self[idx] | ||
|
||
class CistaVectorPrinter: | ||
def __init__(self, val): | ||
self.val = CistaVector(val) | ||
|
||
def children(self): | ||
for idx in range(len(self.val)): | ||
yield '[' + str(idx) + ']', self.val[idx] | ||
|
||
def to_string(self): | ||
return str(self.val) | ||
|
||
def my_pp_func(val): | ||
if not is_cista_vector(val.type): | ||
return | ||
|
||
return CistaVectorPrinter(val) | ||
|
||
### XMethod cista::vector::at | ||
|
||
class CistaVectorWorker_at(gdb.xmethod.XMethodWorker): | ||
def get_arg_types(self): | ||
return gdb.lookup_type('unsigned long int') | ||
|
||
def get_result_type(self, obj): | ||
return obj.type.strip_typedefs().template_argument(0) | ||
|
||
def __call__(self, this, idx): | ||
vec = CistaVector(this.dereference()) | ||
return vec.at(idx) | ||
|
||
class CistaVector_at(gdb.xmethod.XMethod): | ||
def __init__(self): | ||
gdb.xmethod.XMethod.__init__(self, 'at') | ||
|
||
def get_worker(self, method_name): | ||
if method_name == 'at': | ||
return CistaVectorWorker_at() | ||
|
||
### XMethod cista::vector::operator[] | ||
|
||
class CistaVectorWorker_operator_brackets(gdb.xmethod.XMethodWorker): | ||
def get_arg_types(self): | ||
return gdb.lookup_type('unsigned long int') | ||
|
||
def get_result_type(self, obj): | ||
return obj.type.strip_typedefs().template_argument(0) | ||
|
||
def __call__(self, this, idx): | ||
vec = CistaVector(this.dereference()) | ||
return vec[idx] | ||
|
||
class CistaVector_operator_brackets(gdb.xmethod.XMethod): | ||
def __init__(self): | ||
gdb.xmethod.XMethod.__init__(self, 'operator[]') | ||
|
||
def get_worker(self, method_name): | ||
if method_name == 'operator[]': | ||
return CistaVectorWorker_operator_brackets() | ||
|
||
class CistaVectorMatcher(gdb.xmethod.XMethodMatcher): | ||
def __init__(self): | ||
gdb.xmethod.XMethodMatcher.__init__(self, 'CistaVectorMatcher') | ||
# List of methods 'managed' by this matcher | ||
self.methods = [CistaVector_at(), CistaVector_operator_brackets()] | ||
|
||
def match(self, class_type, method_name): | ||
if not is_cista_vector(class_type): | ||
return None | ||
|
||
workers = [] | ||
for method in self.methods: | ||
if method.enabled: | ||
worker = method.get_worker(method_name) | ||
if worker: | ||
workers.append(worker) | ||
|
||
return workers | ||
|
||
gdb.pretty_printers.append(my_pp_func) | ||
gdb.xmethod.register_xmethod_matcher(None, CistaVectorMatcher()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
class OffsetPointer: | ||
def __init__(self, val): | ||
self.val = val | ||
self.offset = val['offset_'] | ||
self.pointer_type = val.type.template_argument(0).pointer() | ||
|
||
def this_as_intptr_t(self): | ||
intptr_t = gdb.lookup_type("intptr_t") | ||
return self.val.address.reinterpret_cast(intptr_t) | ||
|
||
def as_raw_ptr(self): | ||
return (self.this_as_intptr_t() + self.offset).reinterpret_cast(self.pointer_type) | ||
|
||
def add(self, offset): | ||
return self.as_raw_ptr() + offset | ||
|
||
def __add__(self, o): | ||
return self.add(o) | ||
|
||
def dereference(self): | ||
return self.as_raw_ptr().dereference() | ||
|
||
def is_offset_ptr(type): | ||
return str(type.strip_typedefs()).startswith("cista::offset_ptr") |