[Lldb-commits] [lldb] 69c8e64 - [formatters] Improve documentation

Walter Erquinigo via lldb-commits lldb-commits at lists.llvm.org
Fri Jan 7 16:27:19 PST 2022


Author: Walter Erquinigo
Date: 2022-01-07T16:27:03-08:00
New Revision: 69c8e64ba6be090d25657ca0fc2bc53797907837

URL: https://github.com/llvm/llvm-project/commit/69c8e64ba6be090d25657ca0fc2bc53797907837
DIFF: https://github.com/llvm/llvm-project/commit/69c8e64ba6be090d25657ca0fc2bc53797907837.diff

LOG: [formatters] Improve documentation

This adds some important remarks to the data formatter documentation.

Differential Revision: https://reviews.llvm.org/D115974

Added: 
    

Modified: 
    lldb/docs/use/variable.rst

Removed: 
    


################################################################################
diff  --git a/lldb/docs/use/variable.rst b/lldb/docs/use/variable.rst
index 0250de5600ffe..e1adb96d2ad88 100644
--- a/lldb/docs/use/variable.rst
+++ b/lldb/docs/use/variable.rst
@@ -7,7 +7,7 @@ Variable Formatting
 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 @@ the following example:
    (uint8_t) x = 'a'
    (intptr_t) y = 124752287
 
-However, in certain cases, you may want to associate a 
diff erent 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 
diff erent 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 @@ Using it you can change your visualization to look like this:
    (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<int>`` with the elements ``{2, 3, 4, 5, 6}`` would
+result in something like:
+
+::
+
+   (lldb) frame variable a_deque
+   (std::deque<Foo, std::allocator<int> >) $0 = {
+      std::_Deque_base<Foo, std::allocator<int> > = {
+         _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 <var>`` prints out the variable ``<var>`` 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<Foo, std::allocator<int> >) $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 <var>`` instead of ``frame variable <var>``.
+
+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 @@ be implemented by the Python class):
          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 @@ instead of the real ones. For instance,
       (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


        


More information about the lldb-commits mailing list