diff --git a/lldb/docs/use/variable.rst b/lldb/docs/use/variable.rst --- a/lldb/docs/use/variable.rst +++ b/lldb/docs/use/variable.rst @@ -7,7 +7,7 @@ LLDB has a data formatters subsystem that allows users to define custom display options for their variables. -Usually, when you type frame variable or run some expression LLDB will +Usually, when you type ``frame variable`` or run some expression LLDB will automatically choose the way to display your results on a per-type basis, as in the following example: @@ -17,7 +17,11 @@ (uint8_t) x = 'a' (intptr_t) y = 124752287 -However, in certain cases, you may want to associate a different style to the display for certain datatypes. To do so, you need to give hints to the debugger +Note: ``frame variable`` without additional arguments prints the list of +variables of the current frame. + +However, in certain cases, you may want to associate a different style to the +display for certain datatypes. To do so, you need to give hints to the debugger as to how variables should be displayed. The LLDB type command allows you to do just that. @@ -29,6 +33,63 @@ (uint8_t) x = chr='a' dec=65 hex=0x41 (intptr_t) y = 0x76f919f +In addition, some data structures can encode their data in a way that is not +easily readable to the user, in which case a data formatter can be used to +show the data in a human readable way. For example, without a formatter, +printing a ``std::deque`` with the elements ``{2, 3, 4, 5, 6}`` would +result in something like: + +:: + + (lldb) frame variable a_deque + (std::deque >) $0 = { + std::_Deque_base > = { + _M_impl = { + _M_map = 0x000000000062ceb0 + _M_map_size = 8 + _M_start = { + _M_cur = 0x000000000062cf00 + _M_first = 0x000000000062cf00 + _M_last = 0x000000000062d2f4 + _M_node = 0x000000000062cec8 + } + _M_finish = { + _M_cur = 0x000000000062d300 + _M_first = 0x000000000062d300 + _M_last = 0x000000000062d6f4 + _M_node = 0x000000000062ced0 + } + } + } + } + +which is very hard to make sense of. + +Note: ``frame variable `` prints out the variable ```` in the current +frame. + +On the other hand, a proper formatter is able to produce the following output: + +:: + + (lldb) frame variable a_deque + (std::deque >) $0 = size=5 { + [0] = 2 + [1] = 3 + [2] = 4 + [3] = 5 + [4] = 6 + } + +which is what the user would expect from a good debugger. + +Note: you can also use ``v `` instead of ``frame variable ``. + +It's worth mentioning that the ``size=5`` string is produced by a summary +provider and the list of children is produced by a synthetic child provider. +More information about these providers is available later in this document. + + There are several features related to data visualization: formats, summaries, filters, synthetic children. @@ -871,18 +932,26 @@ this call should return a new LLDB SBValue object representing the child at the index given as argument 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] + Also, this method is invoked before any other method in the interface. 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] -[1] This method is optional. Also, it may optionally choose to return a value -(starting with SVN rev153061/LLDB-134). If it returns a value, and that value -is True, LLDB will be allowed to cache the children and the children count it -previously obtained, and will not return to the provider class to ask. If -nothing, None, or anything other than True is returned, LLDB will discard the -cached information and ask. Regardless, whenever necessary LLDB will call -update. +As a warning, exceptions that are thrown by python formatters are caught +silently by LLDB and should be handled appropriately by the formatter itself. +Being more specific, in case of exceptions, LLDB might assume that the given +object has no children or it might skip printing some children, as they are +printed one by one. + +[1] This method is optional. Also, a boolean value must be returned +(starting with SVN rev153061/LLDB-134). If ``False`` is returned, then +whenever the process reaches a new stop, this method will be invoked again to +generate an updated list of the children for a given variable. Otherwise, if +``True`` is returned, then the value is cached and this method won't be called +again, effectively freezing the state of the value in subsequent stops. Beware +that returning ``True`` incorrectly could show misleading information to the +user. [2] This method is optional (starting with SVN rev166495/LLDB-175). While implementing it in terms of num_children is acceptable, implementors are @@ -972,6 +1041,24 @@ (int) [3] = 1234 } +It's important to mention that LLDB invokes the synthetic child provider before +invoking the summary string provider, which allows the latter to have access to +the actual displayable children. This applies to both inlined summary strings +and python-based summary providers. + + +As a warning, when programmatically accessing the children or children count of +a variable that has a synthetic child provider, notice that LLDB hides the +actual raw children. For example, suppose we have a ``std::vector``, which has +an actual in-memory property ``__begin`` marking the beginning of its data. +After the synthetic child provider is executed, the ``std::vector`` variable +won't show ``__begin`` as child anymore, even through the SB API. It will have +instead the children calculated by the provider. In case the actual raw +children are needed, a call to ``value.GetNonSyntheticValue()`` is enough to +get a raw version of the value. It is import to remember this when implementing +summary string providers, as they run after the synthetic child provider. + + In some cases, if LLDB is unable to use the real object to get a child specified in an expression path, it will automatically refer to the synthetic children. While in summaries it is best to always use ${svar to make your