[Lldb-commits] [lldb] [lldb] Do not bump memory modificator ID when "internal" debugger memory is updated (PR #129092)

Mikhail Zakharov via lldb-commits lldb-commits at lists.llvm.org
Sat Mar 15 08:25:08 PDT 2025


real-mikhail wrote:

> If I make an instance of a collection class (most of which are comprehended by synthetic child providers) and then call:
> (lldb) expr $my_vector.append(1)
> (lldb) expr $my_vector

That will still work with my changes. Because function call (`.append()`) is JIT compiled and with current implementation LLDB modifies stack memory to call such function. Approximate callstack:
```
[liblldb.dll] lldb_private::Process::WriteMemory(unsigned long long, const void *, unsigned long long, lldb_private::Status &) Process.cpp:2240
[liblldb.dll] lldb_private::Process::WriteScalarToMemory(unsigned long long, const lldb_private::Scalar &, unsigned long long, lldb_private::Status &) Process.cpp:2319
[liblldb.dll] lldb_private::Process::WritePointerToMemory(unsigned long long, unsigned long long, lldb_private::Status &) Process.cpp:2208
/* Writing return address on the stack here */ [liblldb.dll] ABIWindows_x86_64::PrepareTrivialCall(lldb_private::Thread &,unsigned long long,unsigned long long,unsigned long long,ArrayRef<unsigned __int64>) ABIWindows_x86_64.cpp:1163
[liblldb.dll] lldb_private::ThreadPlanCallFunction::ThreadPlanCallFunction(lldb_private::Thread &,const lldb_private::Address &,const lldb_private::CompilerType &,ArrayRef<unsigned __int64>,const lldb_private::EvaluateExpressionOptions &) ThreadPlanCallFunction.cpp:143
[liblldb.dll] lldb_private::ThreadPlanCallUserExpression::ThreadPlanCallUserExpression(lldb_private::Thread &,lldb_private::Address &,ArrayRef<unsigned __int64>,const lldb_private::EvaluateExpressionOptions &,std::shared_ptr<lldb_private::UserExpression> &) ThreadPlanCallUserExpression.cpp:38
[liblldb.dll] lldb_private::LLVMUserExpression::DoExecute(lldb_private::DiagnosticManager &, lldb_private::ExecutionContext &, lldb_private::ValueObject *, const lldb_private::EvaluateExpressionOptions &, std::shared_ptr<…> &, std::shared_ptr<…> &) LLVMUserExpression.cpp:158
[liblldb.dll] lldb_private::UserExpression::Execute(lldb_private::DiagnosticManager &, lldb_private::ExecutionContext &, lldb_private::ValueObject *, const lldb_private::EvaluateExpressionOptions &, std::shared_ptr<…> &, std::shared_ptr<…> &) UserExpression.cpp:550
[liblldb.dll] lldb_private::ExpressionCache::Execute(lldb_private::ExecutionContext &, lldb_private::ValueObject *, shared_ptr<…>, const lldb_private::EvaluateExpressionOptions &, lldb_private::SharingPtr<…> &) ExpressionCache.cpp:320
[liblldb.dll] lldb_private::ExpressionCache::EvaluateWithCache(lldb_private::ExecutionContext &, const lldb_private::EvaluateExpressionOptions &, StringRef, lldb_private::SharingPtr<…> &, lldb_private::ValueObject *, const std::shared_ptr<…> &, lldb_private::ExpressionCache::ExpressionKey &&) ExpressionCache.cpp:412
[liblldb.dll] lldb_private::ExpressionCache::Evaluate(lldb_private::ExecutionContext &, const lldb_private::EvaluateExpressionOptions &, StringRef, lldb_private::SharingPtr<…> &, std::string *, lldb_private::ValueObject *, shared_ptr<…>) ExpressionCache.cpp:208
[liblldb.dll] lldb_private::Target::EvaluateExpression(StringRef, lldb_private::ExecutionContextScope *, lldb_private::SharingPtr<…> &, const lldb_private::EvaluateExpressionOptions &, std::string *, lldb_private::ValueObject *) Target.cpp:2471
```
(this is from older LLDB version so line numbers might be wrong)

The case where it won't work is something like variant class. For instance, if there is a struct with 2 fields and first field decodes how to display the second field, and there is a pretty printer which creates a synthetic child for second field, and in `expr` user directly assigns some value to one of the fields (and not calls a property to set it) - then LLDB won't show correct values.


> If this is only a problem for persistent variables, maybe we can somehow remember that we delayed an update of the memory generation and if we see that's true and we're updating a persistent variable, then clear the memory cache at that point?

In general case persistent variables can holds pointers to non-persistent ones and vice versa. I guess we can have two `MemoryId` variables (second one for memory cache) and if we can easily understand whether `ValueObject` is a persistent variable or not, then we can check whether variable needs updating by checking corresponding `MemoryId`. I think something like that might work.

https://github.com/llvm/llvm-project/pull/129092


More information about the lldb-commits mailing list