Skip to content

Instantly share code, notes, and snippets.

@ArnCarveris
Last active November 5, 2021 13:23
Show Gist options
  • Save ArnCarveris/994380390b31e119c3bad07f7419733d to your computer and use it in GitHub Desktop.
Save ArnCarveris/994380390b31e119c3bad07f7419733d to your computer and use it in GitHub Desktop.
command script import -c test_item.py
command script import -c test_list.py
command script import -c nlohmann_json.py
import lldb
'''
enum class value_t : std::uint8_t
{
null, ///< null value
object, ///< object (unordered set of name/value pairs)
array, ///< array (ordered collection of values)
string, ///< string value
boolean, ///< boolean value
number_integer, ///< number value (signed integer)
number_unsigned, ///< number value (unsigned integer)
number_float, ///< number value (floating-point)
binary, ///< binary array (ordered collection of bytes)
discarded ///< discarded by the parser callback function
};
union json_value
{
/// object (stored with pointer to save storage)
object_t* object;
/// array (stored with pointer to save storage)
array_t* array;
/// string (stored with pointer to save storage)
string_t* string;
/// binary (stored with pointer to save storage)
binary_t* binary;
/// boolean
boolean_t boolean;
/// number (integer)
number_integer_t number_integer;
/// number (unsigned integer)
number_unsigned_t number_unsigned;
/// number (floating-point)
number_float_t number_float;
};
template<
template<typename, typename, typename...> class ObjectType,
template<typename, typename...> class ArrayType,
class StringType,
class BooleanType,
class NumberIntegerType,
class NumberUnsignedType,
class NumberFloatType,
template<typename> class AllocatorType,
template<typename, typename = void> class JSONSerializer,
class BinaryType
>
struct basic_json
{
value_t m_type;
json_value m_value;
};
template<typename BasicJsonType>
struct internal_iterator
{
/// iterator for JSON objects
typename BasicJsonType::object_t::iterator object_iterator {};
/// iterator for JSON arrays
typename BasicJsonType::array_t::iterator array_iterator {};
/// generic iterator for all other types
primitive_iterator_t primitive_iterator {};
};
template<typename BasicJsonType>
struct iter_impl
{
pointer m_object = nullptr;
internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it {};
};
template<typename BinaryType>
struct byte_container_with_subtype : BinaryType
{
std::uint8_t m_subtype = 0;
bool m_has_subtype = false;
};
'''
class ValueType:
def __init__(self, valobj):
self.null = 0; #< null value
self.object = 1; #< object (unordered set of name/value pairs)
self.array = 2; #< array (ordered collection of values)
self.string = 3; #< string value
self.boolean = 4; #< boolean value
self.number_integer = 5; #< number value (signed integer)
self.number_unsigned = 6; #< number value (unsigned integer)
self.number_float = 7; #< number value (floating-point)
self.binary = 8; #< binary array (ordered collection of bytes)
self.discarded = 9; #< discarded by the parser callback function
self.valobj = valobj.GetNonSyntheticValue()
self.type = self.valobj.GetValueAsUnsigned(self.null)
def IsNull(self):
return self.type == self.null
def IsObject(self):
return self.type == self.object
def IsArray(self):
return self.type == self.array
def IsString(self):
return self.type == self.string
def IsBool(self):
return self.type == self.boolean
def IsInt(self):
return self.type == self.number_integer
def IsUint(self):
return self.type == self.number_unsigned
def IsFloat(self):
return self.type == self.number_float
def IsBinary(self):
return self.type == self.binary
def IsDiscarded(self):
return self.type == self.discarded
def GetSummary(self):
return self.valobj.GetValue()
class Value:
def __init__(self, valobj):
self.valobj = valobj.GetNonSyntheticValue()
self.type = ValueType(self.valobj.GetChildMemberWithName('m_type'))
self.m_value = self.valobj.GetChildMemberWithName('m_value')
self.val = self.Cast()
self.base_val = self.CastToBase()
def GetSummary(self):
if self.val is None:
return self.type.GetSummary()
if self.type.IsBinary():
s_subtype = ""
if self.val.GetChildMemberWithName("m_has_subtype").GetValueAsUnsigned(0) > 0:
s_subtype = "subtype=" + str(self.val.GetChildMemberWithName("m_subtype").GetValueAsUnsigned(0)) + ","
return "binary(" + s_subtype + str(self.base_val.GetSummary()) + ")"
return SummaryOrValue(self.val)
def GetCount(self):
if self.val is None:
return 0
return self.val.GetNumChildren()
def IndexOf(self, name):
if self.type.IsArray():
return self.val.GetIndexOfChildWithName(name)
if self.type.IsObject():
return self.val.GetIndexOfChildWithName(name)
if self.type.IsString():
return self.val.GetIndexOfChildWithName(name)
if self.type.IsBinary():
return self.base_val.GetIndexOfChildWithName(name)
return None
def At(self, index):
if self.type.IsArray():
return self.val.GetChildAtIndex(index)
if self.type.IsObject():
pair = self.val.GetChildAtIndex(index)
first = pair.GetChildMemberWithName("first")
second = pair.GetChildMemberWithName("second")
return self.m_value.CreateValueFromData("[%s]" % SummaryOrValue(first), second.GetData(), second.GetType())
if self.type.IsString():
return self.val.GetChildAtIndex(index)
if self.type.IsBinary():
return self.base_val.GetChildAtIndex(index)
return None
def Cast(self):
if self.type.IsArray():
return self.m_value.GetChildMemberWithName("array").deref
if self.type.IsObject():
return self.m_value.GetChildMemberWithName("object").deref
if self.type.IsString():
return self.m_value.GetChildMemberWithName("string").deref
if self.type.IsBinary():
return self.m_value.GetChildMemberWithName("binary").deref
if self.type.IsBool():
return self.m_value.GetChildMemberWithName("boolean")
if self.type.IsInt():
return self.m_value.GetChildMemberWithName("number_integer")
if self.type.IsUint():
return self.m_value.GetChildMemberWithName("number_unsigned")
if self.type.IsFloat():
return self.m_value.GetChildMemberWithName("number_float")
return None
def CastToBase(self):
if self.type.IsBinary():
return self.val.Cast(self.val.GetType().GetDirectBaseClassAtIndex(0).GetType())
return None
class Iterator:
def __init__(self, valobj):
self.valobj = valobj.GetNonSyntheticValue()
self.value = None
self.m_object = Value(self.valobj.GetChildMemberWithName("m_object"))
if self.TryGetKeyAndOrValue():
self.value = Value(self.m_value)
def GetSummary(self):
if self.m_key is None:
if self.value is None:
if self.m_value is None:
if self.m_object is None:
return 'invalid'
if self.m_primitive is None:
return self.m_object.type.GetSummary()
summary = self.m_object.GetSummary()
index = self.m_primitive.GetValueAsUnsigned(0)
if self.m_object.type.IsString():
if index < (len(summary) - 2):
return "[%d] = %s" % (index, summary[index+1])
return 'invalid'
return summary
return SummaryOrValue(self.m_value)
return self.value.GetSummary()
return "%s: %s" % (SummaryOrValue(self.m_key), self.value.GetSummary())
def GetCount(self):
if self.value is None:
return 0
return self.value.GetCount()
def IndexOf(self, name):
if self.value is None:
return None
return self.value.IndexOf(name)
def At(self, index):
if self.value is None:
return None
return self.value.At(index)
def TryGetKeyAndOrValue(self):
self.m_key = None
self.m_value = None
self.m_primitive = None
if self.m_object.type.IsNull():
return False
if self.m_object.type.IsObject():
self.m_key = self.valobj.GetValueForExpressionPath(".m_it.object_iterator.first")
self.m_value = self.valobj.GetValueForExpressionPath(".m_it.object_iterator.second")
return True
if self.m_object.type.IsArray():
self.m_value = self.valobj.GetValueForExpressionPath(".m_it.array_iterator").GetChildAtIndex(0)
return True
self.m_primitive = self.valobj.GetValueForExpressionPath(".m_it.primitive_iterator").GetChildAtIndex(0)
return False
class Synthetic:
def __init__(self, valobj, internal_dict):
self.valobj = valobj
self.value = Value(valobj)
#this call should initialize the Python object using valobj as the variable to provide synthetic children for
def num_children(self):
#this call should return the number of children that you want your object to have
return self.value.GetCount()
def get_child_index(self,name):
#this call should return the index of the synthetic child whose name is given as argument
return self.value.IndexOf(name)
def get_child_at_index(self,index):
#this call should return a new LLDB SBValue object representing the child at the index given as argument
return self.value.At(index)
def update(self):
#this call should be used to update the internal state of this Python object whenever the state of the variables in LLDB changes.[1]
pass
def has_children(self):
#this call should return True if this object might have children, and False if this object can be guaranteed not to have children.[2]]
if self.value.GetCount() > 0:
return True
return False
def get_value(self):
#this call can return an SBValue to be presented as the value of the synthetic value under consideration.[3]
return self.valobj
class IteratorSynthetic:
def __init__(self, valobj, internal_dict):
self.valobj = valobj
self.iterator = Iterator(valobj)
#this call should initialize the Python object using valobj as the variable to provide synthetic children for
def num_children(self):
#this call should return the number of children that you want your object to have
return self.iterator.GetCount()
def get_child_index(self,name):
#this call should return the index of the synthetic child whose name is given as argument
return self.iterator.IndexOf(name)
def get_child_at_index(self,index):
#this call should return a new LLDB SBValue object representing the child at the index given as argument
return self.iterator.At(index)
def update(self):
#this call should be used to update the internal state of this Python object whenever the state of the variables in LLDB changes.[1]
pass
def has_children(self):
#this call should return True if this object might have children, and False if this object can be guaranteed not to have children.[2]]
if self.iterator.GetCount() > 0:
return True
return False
def get_value(self):
#this call can return an SBValue to be presented as the value of the synthetic value under consideration.[3]
return self.valobj
def SummaryOrValue (valobj):
summary = valobj.GetSummary()
if summary is None:
return valobj.GetValue()
return summary
def Summary (valobj,internal_dict,options):
return Value(valobj).GetSummary()
def IteratorSummary(valobj,internal_dict,options):
return Iterator(valobj).GetSummary()
def __lldb_init_module( debugger, internal_dict ):
debugger.HandleCommand('type summary add -x "^nlohmann::basic_json<.+>(( )?&)?$" -F nlohmann_json.Summary')
debugger.HandleCommand('type synthetic add -x "^nlohmann::basic_json<.+>(( )?&)?$" -l nlohmann_json.Synthetic')
debugger.HandleCommand('type summary add -x "^nlohmann::detail::iter_impl<.+>(( )?&)?$" -F nlohmann_json.IteratorSummary')
debugger.HandleCommand('type synthetic add -x "^nlohmann::detail::iter_impl<.+>(( )?&)?$" -l nlohmann_json.IteratorSynthetic')
import lldb
'''
struct TestItem
{
unsigned width = 0;
unsigned height = 0;
};
'''
def TestItem (valobj,internal_dict,options):
height_val = valobj.GetChildMemberWithName('height')
width_val = valobj.GetChildMemberWithName('width')
height = height_val.GetValueAsUnsigned(0)
width = width_val.GetValueAsUnsigned(0)
area = height*width
perimeter = 2*(height + width)
return 'Area: ' + str(area) + ', Perimeter: ' + str(perimeter)
def __lldb_init_module( debugger, internal_dict ):
debugger.HandleCommand("type summary add TestItem -F test_item.TestItem")
import lldb
'''
template<typename T>
struct TestList
{
unsigned count = 0;
T* data;
};
'''
class Synthetic:
def __init__(self, valobj, internal_dict):
#this call should initialize the Python object using valobj as the variable to provide synthetic children for
self.valobj = valobj
self.count = valobj.GetChildMemberWithName("count")
self.data = valobj.GetChildMemberWithName("data")
self.element_type = valobj.GetType().GetTemplateArgumentType(0)
self.element_size = self.element_type.GetByteSize()
self.element_base_addr = self.data.GetValueAsUnsigned(0)
def num_children(self):
#this call should return the number of children that you want your object to have
return self.count.GetValueAsUnsigned(0)
def get_child_index(self,name):
#this call should return the index of the synthetic child whose name is given as argument
try:
index = int(name)
if index >= self.num_children():
return None
# Ideally we'd use the exception type, but it's unclear what that is
# without knowing how to trigger the original exception.
except: # NOQA: E501, E722
pass
return None
def get_child_at_index(self,index):
#this call should return a new LLDB SBValue object representing the child at the index given as argument
if index >= self.num_children():
return None
addr = self.element_base_addr + index * self.element_size
return self.valobj.CreateValueFromAddress(
"[%d]" % index, addr, self.element_type
)
#def update(self):
#this call should be used to update the internal state of this Python object whenever the state of the variables in LLDB changes.[1]
#def has_children(self):
#this call should return True if this object might have children, and False if this object can be guaranteed not to have children.[2]
#def get_value(self):
#this call can return an SBValue to be presented as the value of the synthetic value under consideration.[3]
def Summary(valobj,internal_dict,options):
count = valobj.GetNumChildren()
return "count=%s" % count
def __lldb_init_module( debugger, internal_dict ):
debugger.HandleCommand('type summary add -x "^TestList<.+>(( )?&)?$" -F test_list.Summary')
debugger.HandleCommand('type synthetic add -x "^TestList<.+>(( )?&)?$" -l test_list.Synthetic')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment