rust.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. '''
  2. Copyright (c) 2016 Vadim Chugunov
  3. SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. '''
  5. from __future__ import print_function, division
  6. import sys
  7. import logging
  8. import lldb
  9. import weakref
  10. if sys.version_info[0] == 2:
  11. # python2-based LLDB accepts utf8-encoded ascii strings only.
  12. def to_lldb_str(s): return s.encode('utf8', 'backslashreplace') if isinstance(s, unicode) else s
  13. range = xrange
  14. else:
  15. to_lldb_str = str
  16. log = logging.getLogger(__name__)
  17. module = sys.modules[__name__]
  18. rust_category = None
  19. def initialize_category(debugger, internal_dict):
  20. global module, rust_category
  21. rust_category = debugger.CreateCategory('Rust')
  22. # rust_category.AddLanguage(lldb.eLanguageTypeRust)
  23. rust_category.SetEnabled(True)
  24. attach_summary_to_type(tuple_summary_provider, r'^\(.*\)$', True)
  25. attach_synthetic_to_type(MsvcTupleSynthProvider, r'^tuple\$?<.+>$',
  26. True) # *-windows-msvc uses this name since 1.47
  27. attach_synthetic_to_type(StrSliceSynthProvider, '&str')
  28. attach_synthetic_to_type(StrSliceSynthProvider, 'str*')
  29. attach_synthetic_to_type(StrSliceSynthProvider, 'str') # *-windows-msvc uses this name since 1.5?
  30. attach_synthetic_to_type(StdStringSynthProvider, '^(collections|alloc)::string::String$', True)
  31. attach_synthetic_to_type(StdVectorSynthProvider, r'^(collections|alloc)::vec::Vec<.+>$', True)
  32. attach_synthetic_to_type(StdVecDequeSynthProvider,
  33. r'^(collections|alloc::collections)::vec_deque::VecDeque<.+>$', True)
  34. attach_synthetic_to_type(MsvcEnumSynthProvider, r'^enum\$<.+>$', True)
  35. attach_synthetic_to_type(MsvcEnum2SynthProvider, r'^enum2\$<.+>$', True)
  36. attach_synthetic_to_type(SliceSynthProvider, r'^&(mut *)?\[.*\]$', True)
  37. attach_synthetic_to_type(MsvcSliceSynthProvider, r'^(mut *)?slice\$?<.+>.*$', True)
  38. attach_synthetic_to_type(StdCStringSynthProvider, '^(std|alloc)::ffi::c_str::CString$', True)
  39. attach_synthetic_to_type(StdCStrSynthProvider, '^&?(std|core)::ffi::c_str::CStr$', True)
  40. attach_synthetic_to_type(StdOsStringSynthProvider, 'std::ffi::os_str::OsString')
  41. attach_synthetic_to_type(StdOsStrSynthProvider, '^&?std::ffi::os_str::OsStr', True)
  42. attach_synthetic_to_type(StdPathBufSynthProvider, 'std::path::PathBuf')
  43. attach_synthetic_to_type(StdPathSynthProvider, '^&?std::path::Path', True)
  44. attach_synthetic_to_type(StdRcSynthProvider, r'^alloc::rc::Rc<.+>$', True)
  45. attach_synthetic_to_type(StdRcSynthProvider, r'^alloc::rc::Weak<.+>$', True)
  46. attach_synthetic_to_type(StdArcSynthProvider, r'^alloc::(sync|arc)::Arc<.+>$', True)
  47. attach_synthetic_to_type(StdArcSynthProvider, r'^alloc::(sync|arc)::Weak<.+>$', True)
  48. attach_synthetic_to_type(StdMutexSynthProvider, r'^std::sync::mutex::Mutex<.+>$', True)
  49. attach_synthetic_to_type(StdCellSynthProvider, r'^core::cell::Cell<.+>$', True)
  50. attach_synthetic_to_type(StdRefCellSynthProvider, r'^core::cell::RefCell<.+>$', True)
  51. attach_synthetic_to_type(StdRefCellBorrowSynthProvider, r'^core::cell::Ref<.+>$', True)
  52. attach_synthetic_to_type(StdRefCellBorrowSynthProvider, r'^core::cell::RefMut<.+>$', True)
  53. attach_synthetic_to_type(StdHashMapSynthProvider, r'^std::collections::hash::map::HashMap<.+>$', True)
  54. attach_synthetic_to_type(StdHashSetSynthProvider, r'^std::collections::hash::set::HashSet<.+>$', True)
  55. attach_synthetic_to_type(GenericEnumSynthProvider, r'^core::option::Option<.+>$', True)
  56. attach_synthetic_to_type(GenericEnumSynthProvider, r'^core::result::Result<.+>$', True)
  57. attach_synthetic_to_type(GenericEnumSynthProvider, r'^alloc::borrow::Cow<.+>$', True)
  58. if 'rust' in internal_dict.get('source_languages', []):
  59. lldb.SBDebugger.SetInternalVariable('target.process.thread.step-avoid-regexp',
  60. '^<?(std|core|alloc)::', debugger.GetInstanceName())
  61. def attach_synthetic_to_type(synth_class, type_name, is_regex=False):
  62. global module, rust_category
  63. # log.debug('attaching synthetic %s to "%s", is_regex=%s', synth_class.__name__, type_name, is_regex)
  64. synth = lldb.SBTypeSynthetic.CreateWithClassName(__name__ + '.' + synth_class.__name__)
  65. synth.SetOptions(lldb.eTypeOptionCascade)
  66. rust_category.AddTypeSynthetic(lldb.SBTypeNameSpecifier(type_name, is_regex), synth)
  67. def summary_fn(valobj, dict): return get_synth_summary(synth_class, valobj, dict)
  68. # LLDB accesses summary fn's by name, so we need to create a unique one.
  69. summary_fn.__name__ = '_get_synth_summary_' + synth_class.__name__
  70. setattr(module, summary_fn.__name__, summary_fn)
  71. attach_summary_to_type(summary_fn, type_name, is_regex)
  72. def attach_summary_to_type(summary_fn, type_name, is_regex=False):
  73. global module, rust_category
  74. # log.debug('attaching summary %s to "%s", is_regex=%s', summary_fn.__name__, type_name, is_regex)
  75. summary = lldb.SBTypeSummary.CreateWithFunctionName(__name__ + '.' + summary_fn.__name__)
  76. summary.SetOptions(lldb.eTypeOptionCascade)
  77. rust_category.AddTypeSummary(lldb.SBTypeNameSpecifier(type_name, is_regex), summary)
  78. # 'get_summary' is annoyingly not a part of the standard LLDB synth provider API.
  79. # This trick allows us to share data extraction logic between synth providers and their sibling summary providers.
  80. def get_synth_summary(synth_class, valobj, dict):
  81. try:
  82. obj_id = valobj.GetIndexOfChildWithName('$$object-id$$')
  83. summary = RustSynthProvider.synth_by_id[obj_id].get_summary()
  84. return to_lldb_str(summary)
  85. except Exception as e:
  86. log.exception('%s', e)
  87. raise
  88. # Chained GetChildMemberWithName lookups
  89. def gcm(valobj, *chain):
  90. for name in chain:
  91. valobj = valobj.GetChildMemberWithName(name)
  92. return valobj
  93. # Get a pointer out of core::ptr::Unique<T>
  94. def read_unique_ptr(valobj):
  95. pointer = valobj.GetChildMemberWithName('pointer')
  96. if pointer.TypeIsPointerType(): # Between 1.33 and 1.63 pointer was just *const T
  97. return pointer
  98. return pointer.GetChildAtIndex(0)
  99. def string_from_ptr(pointer, length):
  100. if length <= 0:
  101. return u''
  102. error = lldb.SBError()
  103. process = pointer.GetProcess()
  104. data = process.ReadMemory(pointer.GetValueAsUnsigned(), length, error)
  105. if error.Success():
  106. return data.decode('utf8', 'replace')
  107. else:
  108. log.error('ReadMemory error: %s', error.GetCString())
  109. def get_template_params(type_name):
  110. params = []
  111. level = 0
  112. start = 0
  113. for i, c in enumerate(type_name):
  114. if c == '<':
  115. level += 1
  116. if level == 1:
  117. start = i + 1
  118. elif c == '>':
  119. level -= 1
  120. if level == 0:
  121. params.append(type_name[start:i].strip())
  122. elif c == ',' and level == 1:
  123. params.append(type_name[start:i].strip())
  124. start = i + 1
  125. return params
  126. def obj_summary(valobj, unavailable='{...}'):
  127. summary = valobj.GetSummary()
  128. if summary is not None:
  129. return summary
  130. summary = valobj.GetValue()
  131. if summary is not None:
  132. return summary
  133. return unavailable
  134. def sequence_summary(children, maxsize=32):
  135. s = ''
  136. for child in children:
  137. if len(s) > 0:
  138. s += ', '
  139. s += obj_summary(child)
  140. if len(s) > maxsize:
  141. s += ', ...'
  142. break
  143. return s
  144. def tuple_summary(obj, skip_first=0):
  145. fields = [obj_summary(obj.GetChildAtIndex(i)) for i in range(skip_first, obj.GetNumChildren())]
  146. return '(%s)' % ', '.join(fields)
  147. # ----- Summaries -----
  148. def tuple_summary_provider(valobj, dict={}):
  149. return tuple_summary(valobj)
  150. # ----- Synth providers ------
  151. class RustSynthProvider(object):
  152. synth_by_id = weakref.WeakValueDictionary()
  153. next_id = 0
  154. def __init__(self, valobj, dict={}):
  155. self.valobj = valobj
  156. self.obj_id = RustSynthProvider.next_id
  157. RustSynthProvider.synth_by_id[self.obj_id] = self
  158. RustSynthProvider.next_id += 1
  159. def update(self):
  160. return True
  161. def has_children(self):
  162. return False
  163. def num_children(self):
  164. return 0
  165. def get_child_at_index(self, index):
  166. return None
  167. def get_child_index(self, name):
  168. if name == '$$object-id$$':
  169. return self.obj_id
  170. try:
  171. return self.get_index_of_child(name)
  172. except Exception as e:
  173. log.exception('%s', e)
  174. raise
  175. def get_summary(self):
  176. return None
  177. class ArrayLikeSynthProvider(RustSynthProvider):
  178. '''Base class for providers that represent array-like objects'''
  179. def update(self):
  180. self.ptr, self.len = self.ptr_and_len(self.valobj) # type: ignore
  181. self.item_type = self.ptr.GetType().GetPointeeType()
  182. self.item_size = self.item_type.GetByteSize()
  183. def ptr_and_len(self, obj):
  184. pass # abstract
  185. def num_children(self):
  186. return self.len
  187. def has_children(self):
  188. return True
  189. def get_child_at_index(self, index):
  190. try:
  191. if not 0 <= index < self.len:
  192. return None
  193. offset = index * self.item_size
  194. return self.ptr.CreateChildAtOffset('[%s]' % index, offset, self.item_type)
  195. except Exception as e:
  196. log.exception('%s', e)
  197. raise
  198. def get_index_of_child(self, name):
  199. return int(name.lstrip('[').rstrip(']'))
  200. def get_summary(self):
  201. return '(%d)' % (self.len,)
  202. class StdVectorSynthProvider(ArrayLikeSynthProvider):
  203. def ptr_and_len(self, vec):
  204. return (
  205. read_unique_ptr(gcm(vec, 'buf', 'ptr')),
  206. gcm(vec, 'len').GetValueAsUnsigned()
  207. )
  208. def get_summary(self):
  209. return '(%d) vec![%s]' % (self.len, sequence_summary((self.get_child_at_index(i) for i in range(self.len))))
  210. class StdVecDequeSynthProvider(RustSynthProvider):
  211. def update(self):
  212. self.ptr = read_unique_ptr(gcm(self.valobj, 'buf', 'ptr'))
  213. self.cap = gcm(self.valobj, 'buf', 'cap').GetValueAsUnsigned()
  214. head = gcm(self.valobj, 'head').GetValueAsUnsigned()
  215. # rust 1.67 changed from a head, tail implementation to a head, length impl
  216. # https://github.com/rust-lang/rust/pull/102991
  217. vd_len = gcm(self.valobj, 'len')
  218. if vd_len.IsValid():
  219. self.len = vd_len.GetValueAsUnsigned()
  220. self.startptr = head
  221. else:
  222. tail = gcm(self.valobj, 'tail').GetValueAsUnsigned()
  223. self.len = head - tail
  224. self.startptr = tail
  225. self.item_type = self.ptr.GetType().GetPointeeType()
  226. self.item_size = self.item_type.GetByteSize()
  227. def num_children(self):
  228. return self.len
  229. def has_children(self):
  230. return True
  231. def get_child_at_index(self, index):
  232. try:
  233. if not 0 <= index < self.num_children():
  234. return None
  235. offset = ((self.startptr + index) % self.cap) * self.item_size
  236. return self.ptr.CreateChildAtOffset('[%s]' % index, offset, self.item_type)
  237. except Exception as e:
  238. log.exception('%s', e)
  239. raise
  240. def get_index_of_child(self, name):
  241. return int(name.lstrip('[').rstrip(']'))
  242. def get_summary(self):
  243. return '(%d) VecDeque[%s]' % (self.num_children(), sequence_summary((self.get_child_at_index(i) for i in range(self.num_children()))))
  244. ##################################################################################################################
  245. class SliceSynthProvider(ArrayLikeSynthProvider):
  246. def ptr_and_len(self, vec):
  247. return (
  248. gcm(vec, 'data_ptr'),
  249. gcm(vec, 'length').GetValueAsUnsigned()
  250. )
  251. def get_summary(self):
  252. return '(%d) &[%s]' % (self.len, sequence_summary((self.get_child_at_index(i) for i in range(self.len))))
  253. class MsvcSliceSynthProvider(SliceSynthProvider):
  254. def get_type_name(self):
  255. tparams = get_template_params(self.valobj.GetTypeName())
  256. return '&[' + tparams[0] + ']'
  257. # Base class for *String providers
  258. class StringLikeSynthProvider(ArrayLikeSynthProvider):
  259. def get_child_at_index(self, index):
  260. ch = ArrayLikeSynthProvider.get_child_at_index(self, index)
  261. ch.SetFormat(lldb.eFormatChar)
  262. return ch
  263. def get_summary(self):
  264. # Limit string length to 1000 characters to cope with uninitialized values whose
  265. # length field contains garbage.
  266. strval = string_from_ptr(self.ptr, min(self.len, 1000))
  267. if strval == None:
  268. return None
  269. if self.len > 1000:
  270. strval += u'...'
  271. return u'"%s"' % strval
  272. class StrSliceSynthProvider(StringLikeSynthProvider):
  273. def ptr_and_len(self, valobj):
  274. return (
  275. gcm(valobj, 'data_ptr'),
  276. gcm(valobj, 'length').GetValueAsUnsigned()
  277. )
  278. class StdStringSynthProvider(StringLikeSynthProvider):
  279. def ptr_and_len(self, valobj):
  280. vec = gcm(valobj, 'vec')
  281. return (
  282. read_unique_ptr(gcm(vec, 'buf', 'ptr')),
  283. gcm(vec, 'len').GetValueAsUnsigned()
  284. )
  285. class StdCStringSynthProvider(StringLikeSynthProvider):
  286. def ptr_and_len(self, valobj):
  287. vec = gcm(valobj, 'inner')
  288. return (
  289. gcm(vec, 'data_ptr'),
  290. gcm(vec, 'length').GetValueAsUnsigned() - 1
  291. )
  292. class StdOsStringSynthProvider(StringLikeSynthProvider):
  293. def ptr_and_len(self, valobj):
  294. vec = gcm(valobj, 'inner', 'inner')
  295. tmp = gcm(vec, 'bytes') # Windows OSString has an extra layer
  296. if tmp.IsValid():
  297. vec = tmp
  298. return (
  299. read_unique_ptr(gcm(vec, 'buf', 'ptr')),
  300. gcm(vec, 'len').GetValueAsUnsigned()
  301. )
  302. class FFISliceSynthProvider(StringLikeSynthProvider):
  303. def ptr_and_len(self, valobj):
  304. process = valobj.GetProcess()
  305. slice_ptr = valobj.GetLoadAddress()
  306. data_ptr_type = valobj.GetTarget().GetBasicType(lldb.eBasicTypeChar).GetPointerType()
  307. # Unsized slice objects have incomplete debug info, so here we just assume standard slice
  308. # reference layout: [<pointer to data>, <data size>]
  309. error = lldb.SBError()
  310. pointer = valobj.CreateValueFromAddress('data', slice_ptr, data_ptr_type)
  311. length = process.ReadPointerFromMemory(slice_ptr + process.GetAddressByteSize(), error)
  312. return pointer, length
  313. class StdCStrSynthProvider(FFISliceSynthProvider):
  314. def ptr_and_len(self, valobj):
  315. ptr, len = FFISliceSynthProvider.ptr_and_len(self, valobj)
  316. return (ptr, len-1) # drop terminaing '\0'
  317. class StdOsStrSynthProvider(FFISliceSynthProvider):
  318. pass
  319. class StdPathBufSynthProvider(StdOsStringSynthProvider):
  320. def ptr_and_len(self, valobj):
  321. return StdOsStringSynthProvider.ptr_and_len(self, gcm(valobj, 'inner'))
  322. class StdPathSynthProvider(FFISliceSynthProvider):
  323. pass
  324. ##################################################################################################################
  325. class DerefSynthProvider(RustSynthProvider):
  326. deref = lldb.SBValue()
  327. def has_children(self):
  328. return self.deref.MightHaveChildren()
  329. def num_children(self):
  330. return self.deref.GetNumChildren()
  331. def get_child_at_index(self, index):
  332. return self.deref.GetChildAtIndex(index)
  333. def get_index_of_child(self, name):
  334. return self.deref.GetIndexOfChildWithName(name)
  335. def get_summary(self):
  336. return obj_summary(self.deref)
  337. # Base for Rc and Arc
  338. class StdRefCountedSynthProvider(DerefSynthProvider):
  339. weak = 0
  340. strong = 0
  341. def get_summary(self):
  342. if self.weak != 0:
  343. s = '(refs:%d,weak:%d) ' % (self.strong, self.weak)
  344. else:
  345. s = '(refs:%d) ' % self.strong
  346. if self.strong > 0:
  347. s += obj_summary(self.deref)
  348. else:
  349. s += '<disposed>'
  350. return s
  351. class StdRcSynthProvider(StdRefCountedSynthProvider):
  352. def update(self):
  353. inner = read_unique_ptr(gcm(self.valobj, 'ptr'))
  354. self.strong = gcm(inner, 'strong', 'value', 'value').GetValueAsUnsigned()
  355. self.weak = gcm(inner, 'weak', 'value', 'value').GetValueAsUnsigned()
  356. if self.strong > 0:
  357. self.deref = gcm(inner, 'value')
  358. self.weak -= 1 # There's an implicit weak reference communally owned by all the strong pointers
  359. else:
  360. self.deref = lldb.SBValue()
  361. self.deref.SetPreferSyntheticValue(True)
  362. class StdArcSynthProvider(StdRefCountedSynthProvider):
  363. def update(self):
  364. inner = read_unique_ptr(gcm(self.valobj, 'ptr'))
  365. self.strong = gcm(inner, 'strong', 'v', 'value').GetValueAsUnsigned()
  366. self.weak = gcm(inner, 'weak', 'v', 'value').GetValueAsUnsigned()
  367. if self.strong > 0:
  368. self.deref = gcm(inner, 'data')
  369. self.weak -= 1 # There's an implicit weak reference communally owned by all the strong pointers
  370. else:
  371. self.deref = lldb.SBValue()
  372. self.deref.SetPreferSyntheticValue(True)
  373. class StdMutexSynthProvider(DerefSynthProvider):
  374. def update(self):
  375. self.deref = gcm(self.valobj, 'data', 'value')
  376. self.deref.SetPreferSyntheticValue(True)
  377. class StdCellSynthProvider(DerefSynthProvider):
  378. def update(self):
  379. self.deref = gcm(self.valobj, 'value', 'value')
  380. self.deref.SetPreferSyntheticValue(True)
  381. class StdRefCellSynthProvider(DerefSynthProvider):
  382. def update(self):
  383. self.deref = gcm(self.valobj, 'value', 'value')
  384. self.deref.SetPreferSyntheticValue(True)
  385. def get_summary(self):
  386. borrow = gcm(self.valobj, 'borrow', 'value', 'value').GetValueAsSigned()
  387. s = ''
  388. if borrow < 0:
  389. s = '(borrowed:mut) '
  390. elif borrow > 0:
  391. s = '(borrowed:%d) ' % borrow
  392. return s + obj_summary(self.deref)
  393. class StdRefCellBorrowSynthProvider(DerefSynthProvider):
  394. def update(self):
  395. self.deref = gcm(self.valobj, 'value', 'pointer').Dereference()
  396. self.deref.SetPreferSyntheticValue(True)
  397. ##################################################################################################################
  398. class EnumSynthProvider(RustSynthProvider):
  399. variant = lldb.SBValue()
  400. summary = ''
  401. skip_first = 0
  402. def has_children(self):
  403. return self.variant.MightHaveChildren()
  404. def num_children(self):
  405. return self.variant.GetNumChildren() - self.skip_first
  406. def get_child_at_index(self, index):
  407. return self.variant.GetChildAtIndex(index + self.skip_first)
  408. def get_index_of_child(self, name):
  409. return self.variant.GetIndexOfChildWithName(name) - self.skip_first
  410. def get_summary(self):
  411. return self.summary
  412. class GenericEnumSynthProvider(EnumSynthProvider):
  413. def update(self):
  414. dyn_type_name = self.valobj.GetTypeName()
  415. variant_name = dyn_type_name[dyn_type_name.rfind(':')+1:]
  416. self.variant = self.valobj
  417. if self.variant.IsValid() and self.variant.GetNumChildren() > self.skip_first:
  418. if self.variant.GetChildAtIndex(self.skip_first).GetName() in ['0', '__0']:
  419. self.summary = variant_name + tuple_summary(self.variant)
  420. else:
  421. self.summary = variant_name + '{...}'
  422. else:
  423. self.summary = variant_name
  424. class MsvcTupleSynthProvider(RustSynthProvider):
  425. def update(self):
  426. tparams = get_template_params(self.valobj.GetTypeName())
  427. self.type_name = '(' + ', '.join(tparams) + ')'
  428. def has_children(self):
  429. return self.valobj.MightHaveChildren()
  430. def num_children(self):
  431. return self.valobj.GetNumChildren()
  432. def get_child_at_index(self, index):
  433. child = self.valobj.GetChildAtIndex(index)
  434. return child.CreateChildAtOffset(str(index), 0, child.GetType())
  435. def get_index_of_child(self, name):
  436. return str(name)
  437. def get_summary(self):
  438. return tuple_summary(self.valobj)
  439. def get_type_name(self):
  440. return self.type_name
  441. class MsvcEnumSynthProvider(EnumSynthProvider):
  442. is_tuple_variant = False
  443. def update(self):
  444. tparams = get_template_params(self.valobj.GetTypeName())
  445. if len(tparams) == 1: # Regular enum
  446. discr = gcm(self.valobj, 'discriminant')
  447. self.variant = gcm(self.valobj, 'variant' + str(discr.GetValueAsUnsigned()))
  448. variant_name = discr.GetValue()
  449. else: # Niche enum
  450. dataful_min = int(tparams[1])
  451. dataful_max = int(tparams[2])
  452. dataful_var = tparams[3]
  453. discr = gcm(self.valobj, 'discriminant')
  454. if dataful_min <= discr.GetValueAsUnsigned() <= dataful_max:
  455. self.variant = gcm(self.valobj, 'dataful_variant')
  456. variant_name = dataful_var
  457. else:
  458. variant_name = discr.GetValue()
  459. self.type_name = tparams[0]
  460. if self.variant.IsValid() and self.variant.GetNumChildren() > self.skip_first:
  461. if self.variant.GetChildAtIndex(self.skip_first).GetName() == '__0':
  462. self.is_tuple_variant = True
  463. self.summary = variant_name + tuple_summary(self.variant, skip_first=self.skip_first)
  464. else:
  465. self.summary = variant_name + '{...}'
  466. else:
  467. self.summary = variant_name
  468. def get_child_at_index(self, index):
  469. child = self.variant.GetChildAtIndex(index + self.skip_first)
  470. if self.is_tuple_variant:
  471. return child.CreateChildAtOffset(str(index), 0, child.GetType())
  472. else:
  473. return child
  474. def get_index_of_child(self, name):
  475. if self.is_tuple_variant:
  476. return int(name)
  477. else:
  478. return self.variant.GetIndexOfChildWithName(name) - self.skip_first
  479. def get_type_name(self):
  480. return self.type_name
  481. class MsvcEnum2SynthProvider(EnumSynthProvider):
  482. is_tuple_variant = False
  483. def update(self):
  484. tparams = get_template_params(self.valobj.GetTypeName())
  485. self.type_name = tparams[0]
  486. def get_child_at_index(self, index):
  487. return self.valobj.GetChildAtIndex(index)
  488. def get_index_of_child(self, name):
  489. return self.valobj.GetChildIndex(name)
  490. def get_type_name(self):
  491. return self.type_name
  492. ##################################################################################################################
  493. class StdHashMapSynthProvider(RustSynthProvider):
  494. def update(self):
  495. self.initialize_table(gcm(self.valobj, 'base', 'table'))
  496. def initialize_table(self, table):
  497. assert table.IsValid()
  498. if table.type.GetNumberOfTemplateArguments() > 0:
  499. item_ty = table.type.GetTemplateArgumentType(0)
  500. else: # we must be on windows-msvc - try to look up item type by name
  501. table_ty_name = table.GetType().GetName() # "hashbrown::raw::RawTable<ITEM_TY>"
  502. item_ty_name = get_template_params(table_ty_name)[0]
  503. item_ty = table.GetTarget().FindTypes(item_ty_name).GetTypeAtIndex(0)
  504. if item_ty.IsTypedefType():
  505. item_ty = item_ty.GetTypedefedType()
  506. inner_table = table.GetChildMemberWithName('table')
  507. if inner_table.IsValid():
  508. self.initialize_hashbrown_v2(inner_table, item_ty) # 1.52 <= std_version
  509. else:
  510. if not table.GetChildMemberWithName('data'):
  511. self.initialize_hashbrown_v2(table, item_ty) # ? <= std_version < 1.52
  512. else:
  513. self.initialize_hashbrown_v1(table, item_ty) # 1.36 <= std_version < ?
  514. def initialize_hashbrown_v2(self, table, item_ty):
  515. self.num_buckets = gcm(table, 'bucket_mask').GetValueAsUnsigned() + 1
  516. ctrl_ptr = gcm(table, 'ctrl', 'pointer')
  517. ctrl = ctrl_ptr.GetPointeeData(0, self.num_buckets)
  518. # Buckets are located above `ctrl`, in reverse order.
  519. start_addr = ctrl_ptr.GetValueAsUnsigned() - item_ty.GetByteSize() * self.num_buckets
  520. buckets_ty = item_ty.GetArrayType(self.num_buckets)
  521. self.buckets = self.valobj.CreateValueFromAddress('data', start_addr, buckets_ty)
  522. error = lldb.SBError()
  523. self.valid_indices = []
  524. for i in range(self.num_buckets):
  525. if ctrl.GetUnsignedInt8(error, i) & 0x80 == 0:
  526. self.valid_indices.append(self.num_buckets - 1 - i)
  527. def initialize_hashbrown_v1(self, table, item_ty):
  528. self.num_buckets = gcm(table, 'bucket_mask').GetValueAsUnsigned() + 1
  529. ctrl_ptr = gcm(table, 'ctrl', 'pointer')
  530. ctrl = ctrl_ptr.GetPointeeData(0, self.num_buckets)
  531. buckets_ty = item_ty.GetArrayType(self.num_buckets)
  532. self.buckets = gcm(table, 'data', 'pointer').Dereference().Cast(buckets_ty)
  533. error = lldb.SBError()
  534. self.valid_indices = []
  535. for i in range(self.num_buckets):
  536. if ctrl.GetUnsignedInt8(error, i) & 0x80 == 0:
  537. self.valid_indices.append(i)
  538. def has_children(self):
  539. return True
  540. def num_children(self):
  541. return len(self.valid_indices)
  542. def get_child_at_index(self, index):
  543. bucket_idx = self.valid_indices[index]
  544. item = self.buckets.GetChildAtIndex(bucket_idx)
  545. return item.CreateChildAtOffset('[%d]' % index, 0, item.GetType())
  546. def get_index_of_child(self, name):
  547. return int(name.lstrip('[').rstrip(']'))
  548. def get_summary(self):
  549. return 'size=%d, capacity=%d' % (self.num_children(), self.num_buckets)
  550. class StdHashSetSynthProvider(StdHashMapSynthProvider):
  551. def update(self):
  552. table = gcm(self.valobj, 'base', 'map', 'table') # std_version >= 1.48
  553. if not table.IsValid():
  554. table = gcm(self.valobj, 'map', 'base', 'table') # std_version < 1.48
  555. self.initialize_table(table)
  556. def get_child_at_index(self, index):
  557. bucket_idx = self.valid_indices[index]
  558. item = self.buckets.GetChildAtIndex(bucket_idx).GetChildAtIndex(0)
  559. return item.CreateChildAtOffset('[%d]' % index, 0, item.GetType())
  560. ##################################################################################################################
  561. def __lldb_init_module(debugger_obj, internal_dict):
  562. log.info('Initializing')
  563. initialize_category(debugger_obj, internal_dict)