[Lldb-commits] [lldb] [LLDB] Add DIL code for handling plain variable names. (PR #120971)

2025-01-20 Thread via lldb-commits

https://github.com/cmtice edited 
https://github.com/llvm/llvm-project/pull/120971
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Implement basic support for reverse-continue (PR #112079)

2025-01-20 Thread Pavel Labath via lldb-commits

labath wrote:

Cool, thanks. I take it you need me to merge this (?)

https://github.com/llvm/llvm-project/pull/112079
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Implement basic support for reverse-continue (PR #112079)

2025-01-20 Thread Robert O'Callahan via lldb-commits

rocallahan wrote:

Yes, I need someone to merge it. Thanks!

https://github.com/llvm/llvm-project/pull/112079
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [llvm] [lldb] Enable "frame diagnose" on linux (PR #123217)

2025-01-20 Thread Pavel Labath via lldb-commits

https://github.com/labath updated 
https://github.com/llvm/llvm-project/pull/123217

>From 3b2c06550d398b281b6dd75928507590dd5ed4c4 Mon Sep 17 00:00:00 2001
From: Pavel Labath 
Date: Thu, 16 Jan 2025 16:49:56 +0100
Subject: [PATCH 1/3] [lldb] Enable "frame diagnose" on linux

.. by changing the signal stop reason format :facepalm:

The reason this did not work is because the code in
StopInfo::GetCrashingDereference was looking for the string "address="
to extract the address of the crash. Macos stop reason strings have the
form
  EXC_BAD_ACCESS (code=1, address=0xdead)
while on linux they look like:
  signal SIGSEGV: address not mapped to object (fault address: 0xdead)

Extracting the address from a string sounds like a bad idea, but I
suppose there's some value in using a consistent format across
platforms, so this patch changes the signal format to use the equals
sign as well. All of the diagnose tests pass except one, which appears
to fail due to something similar #115453 (disassembler reports
unrelocated call targets).

I've left the tests disabled on windows, as the stop reason reporting
code works very differently there, and I suspect it won't work out of
the box. If I'm wrong -- the XFAIL will let us know.
---
 lldb/source/Target/UnixSignals.cpp |  8 
 .../API/commands/frame/diagnose/array/TestArray.py |  2 +-
 .../frame/diagnose/bad-reference/TestBadReference.py   |  2 +-
 .../TestComplicatedExpression.py   |  2 +-
 .../TestDiagnoseDereferenceArgument.py |  2 +-
 .../TestDiagnoseDereferenceFunctionReturn.py   |  2 +-
 .../dereference-this/TestDiagnoseDereferenceThis.py|  2 +-
 .../diagnose/inheritance/TestDiagnoseInheritance.py|  2 +-
 .../frame/diagnose/local-variable/TestLocalVariable.py |  2 +-
 .../TestDiagnoseDereferenceVirtualMethodCall.py|  2 +-
 .../TestAArch64LinuxMTEMemoryTagCoreFile.py|  2 +-
 .../TestAArch64LinuxNonAddressBitMemoryAccess.py   |  2 +-
 .../Shell/Register/Core/x86-32-linux-multithread.test  |  2 +-
 .../Shell/Register/Core/x86-64-linux-multithread.test  |  2 +-
 lldb/unittests/Signals/UnixSignalsTest.cpp | 10 +-
 15 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/lldb/source/Target/UnixSignals.cpp 
b/lldb/source/Target/UnixSignals.cpp
index bee3a63818259e..da661003925c79 100644
--- a/lldb/source/Target/UnixSignals.cpp
+++ b/lldb/source/Target/UnixSignals.cpp
@@ -163,7 +163,7 @@ UnixSignals::GetSignalDescription(int32_t signo, 
std::optional code,
   break;
 case SignalCodePrintOption::Address:
   if (addr)
-strm << " (fault address: 0x" << std::hex << *addr << ")";
+strm << " (fault address=0x" << std::hex << *addr << ")";
   break;
 case SignalCodePrintOption::Bounds:
   if (lower && upper && addr) {
@@ -172,9 +172,9 @@ UnixSignals::GetSignalDescription(int32_t signo, 
std::optional code,
 else
   strm << "upper bound violation ";
 
-strm << "(fault address: 0x" << std::hex << *addr;
-strm << ", lower bound: 0x" << std::hex << *lower;
-strm << ", upper bound: 0x" << std::hex << *upper;
+strm << "(fault address=0x" << std::hex << *addr;
+strm << ", lower bound=0x" << std::hex << *lower;
+strm << ", upper bound=0x" << std::hex << *upper;
 strm << ")";
   } else
 strm << sc.m_description.str();
diff --git a/lldb/test/API/commands/frame/diagnose/array/TestArray.py 
b/lldb/test/API/commands/frame/diagnose/array/TestArray.py
index 5de6f7b0aaa1c4..307e2cbca30228 100644
--- a/lldb/test/API/commands/frame/diagnose/array/TestArray.py
+++ b/lldb/test/API/commands/frame/diagnose/array/TestArray.py
@@ -10,7 +10,7 @@
 
 
 class TestArray(TestBase):
-@skipUnlessDarwin
+@expectedFailureAll(oslist=["windows"])
 @skipIf(
 archs=no_match(["x86_64"])
 )  #  frame diagnose doesn't work for armv7 or 
arm64
diff --git 
a/lldb/test/API/commands/frame/diagnose/bad-reference/TestBadReference.py 
b/lldb/test/API/commands/frame/diagnose/bad-reference/TestBadReference.py
index 7a9498cab13766..8ded5e2ff55c21 100644
--- a/lldb/test/API/commands/frame/diagnose/bad-reference/TestBadReference.py
+++ b/lldb/test/API/commands/frame/diagnose/bad-reference/TestBadReference.py
@@ -10,7 +10,7 @@
 
 
 class TestBadReference(TestBase):
-@skipUnlessDarwin
+@expectedFailureAll(oslist=["windows"])
 @skipIf(
 archs=no_match(["x86_64"])
 )  #  frame diagnose doesn't work for armv7 or 
arm64
diff --git 
a/lldb/test/API/commands/frame/diagnose/complicated-expression/TestComplicatedExpression.py
 
b/lldb/test/API/commands/frame/diagnose/complicated-expression/TestComplicatedExpression.py
index eb1b556f0c408d..8ee254a28cb545 100644
--- 
a/lldb/test/API/commands/frame/diagnose/complicated-expression/TestComplicatedExpression.py
+++ 
b/ll

[Lldb-commits] [lldb] [llvm] [lldb] Enable "frame diagnose" on linux (PR #123217)

2025-01-20 Thread David Spickett via lldb-commits

https://github.com/DavidSpickett approved this pull request.

LGTM

https://github.com/llvm/llvm-project/pull/123217
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Implement basic support for reverse-continue (PR #112079)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,32 @@
+import lldb
+import unittest
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test import lldbutil
+
+
+class TestReverseContinueNotSupported(TestBase):
+NO_DEBUG_INFO_TESTCASE = True
+
+def test_reverse_continue_not_supported(self):
+self.build()
+exe = self.getBuildArtifact("a.out")
+target = self.dbg.CreateTarget(exe)
+self.assertTrue(target, VALID_TARGET)
+
+main_bkpt = target.BreakpointCreateByName("main", None)
+self.assertTrue(main_bkpt, VALID_BREAKPOINT)
+
+process = target.LaunchSimple(None, None, 
self.get_process_working_directory())
+self.assertTrue(process, PROCESS_IS_VALID)
+
+# This will fail gracefully.
+status = process.ContinueInDirection(lldb.eRunReverse)
+self.assertFailure(
+status, "error: gdb-remote does not support reverse execution of 
processes"
+)
+
+status = process.ContinueInDirection(lldb.eRunForward)
+self.assertSuccess(status)

labath wrote:

I'd put these on the same line. Besides being one line shorter, they're also 
slightly more useful, as in the case of a test failure, the python backtrace 
will contain the text of the line which failed.

```suggestion
self.assertSuccess(process.ContinueInDirection(lldb.eRunForward))
```

https://github.com/llvm/llvm-project/pull/112079
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Implement basic support for reverse-continue (PR #112079)

2025-01-20 Thread Pavel Labath via lldb-commits

https://github.com/labath approved this pull request.

LGTM

https://github.com/llvm/llvm-project/pull/112079
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Implement basic support for reverse-continue (PR #112079)

2025-01-20 Thread Pavel Labath via lldb-commits

https://github.com/labath edited 
https://github.com/llvm/llvm-project/pull/112079
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Implement basic support for reverse-continue (PR #112079)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,149 @@
+import lldb
+import time
+import unittest
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test.gdbclientutils import *
+from lldbsuite.test.lldbreverse import ReverseTestBase
+from lldbsuite.test import lldbutil
+
+
+class TestReverseContinueBreakpoints(ReverseTestBase):
+def test_reverse_continue(self):
+self.reverse_continue_internal(async_mode=False)
+
+def test_reverse_continue_async(self):
+self.reverse_continue_internal(async_mode=True)
+
+def reverse_continue_internal(self, async_mode):
+target, process, initial_threads = self.setup_recording(async_mode)
+
+# Reverse-continue. We'll stop at the point where we started recording.
+status = process.ContinueInDirection(lldb.eRunReverse)
+self.assertSuccess(status)
+self.expect_async_state_changes(
+async_mode, process, [lldb.eStateRunning, lldb.eStateStopped]
+)
+self.expect(
+"thread list",
+STOPPED_DUE_TO_HISTORY_BOUNDARY,
+substrs=["stopped", "stop reason = history boundary"],
+)

labath wrote:

Is there something more to assert here? The PC value, current line number or 
something like that?

https://github.com/llvm/llvm-project/pull/112079
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Add SymbolContext::GetAddress (PR #123340)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -370,6 +370,31 @@ bool SymbolContext::GetAddressRange(uint32_t scope, 
uint32_t range_idx,
   return false;
 }
 
+Address SymbolContext::GetAddress(uint32_t scope,
+  bool use_inline_block_range) const {
+  if ((scope & eSymbolContextLineEntry) && line_entry.IsValid())
+return line_entry.range.GetBaseAddress();
+
+  if (scope & eSymbolContextBlock) {
+Block *block_to_use = (block && use_inline_block_range)
+  ? block->GetContainingInlinedBlock()
+  : block;
+if (block_to_use) {
+  Address addr;
+  block_to_use->GetStartAddress(addr);
+  return addr;
+}
+  }

labath wrote:

The part that bothers me is that the "address of a block" isn't a very well 
defined concept. For functions/symbols, I think it's clear -- is the address 
you jump to when you want to "call" the functions. Line entries are contiguous 
so it sort of makes sense to say that its address is the beginning of that 
range, though I don't think that guarantees that address will ever be executed 
(*). For blocks, it's even messier, because even "regular" compiler 
optimizations (no propellers or bolts) can make the block discontiguous. 
Block::GetStartAddress returns the lowest address in the block, so the result 
maybe be not just be not executed, it may be in a completely different part of 
the function. It's not wrong, if that's what you expect. I think it's just.. 
confusing. But not supporting the flag would be confusing as well, so... :shrug:

(*) I don't know if you can get a compiler to emit something like this, but I 
don't think it would be wrong to describe `insn1` and `insn2` in the following 
snippet with the same line entry:
```
jcc 2f
insn1
2: insn2
```

(insn1 is executed only if some condition is met and the two happen to be on 
the same line. Let's assume we're not using column numbers here)

https://github.com/llvm/llvm-project/pull/123340
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [LLDB] Add Lexer (with tests) for DIL (Data Inspection Language). (PR #123521)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,156 @@
+//===-- DILLexer.h --*- C++ 
-*-===//

labath wrote:

Also, this file uses a combination of `cammelCase` (llvm style) and 
`UpperCamel` (lldb style) for method names. I'd be fine with either, but please 
be consistent.

https://github.com/llvm/llvm-project/pull/123521
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [llvm] [lldb] Enable "frame diagnose" on linux (PR #123217)

2025-01-20 Thread Pavel Labath via lldb-commits

labath wrote:

> It's not to the same level, but doesn't everyone else have this issue, 
> potentially?

Potentially yes, but I know for a fact debugserver comes with the iPhones and 
whatnot, which means it needs to keep working as long as the devices are 
supported. For example Android takes a different approach and always copies the 
"current" version of lldb-server for debugging (it wasn't the only factor, but 
not having to worry about compatibility definitely contributed to that 
decision). I expect most linux-y users will not have long support windows even 
if they're not always using matching binaries (the fact that you don't need to 
codesign lldb-server definitely helps with that)

> So - shall we release note this and include that detail?

SGTM

https://github.com/llvm/llvm-project/pull/123217
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [llvm] [lldb] Enable "frame diagnose" on linux (PR #123217)

2025-01-20 Thread Pavel Labath via lldb-commits

https://github.com/labath updated 
https://github.com/llvm/llvm-project/pull/123217

>From 3b2c06550d398b281b6dd75928507590dd5ed4c4 Mon Sep 17 00:00:00 2001
From: Pavel Labath 
Date: Thu, 16 Jan 2025 16:49:56 +0100
Subject: [PATCH 1/4] [lldb] Enable "frame diagnose" on linux

.. by changing the signal stop reason format :facepalm:

The reason this did not work is because the code in
StopInfo::GetCrashingDereference was looking for the string "address="
to extract the address of the crash. Macos stop reason strings have the
form
  EXC_BAD_ACCESS (code=1, address=0xdead)
while on linux they look like:
  signal SIGSEGV: address not mapped to object (fault address: 0xdead)

Extracting the address from a string sounds like a bad idea, but I
suppose there's some value in using a consistent format across
platforms, so this patch changes the signal format to use the equals
sign as well. All of the diagnose tests pass except one, which appears
to fail due to something similar #115453 (disassembler reports
unrelocated call targets).

I've left the tests disabled on windows, as the stop reason reporting
code works very differently there, and I suspect it won't work out of
the box. If I'm wrong -- the XFAIL will let us know.
---
 lldb/source/Target/UnixSignals.cpp |  8 
 .../API/commands/frame/diagnose/array/TestArray.py |  2 +-
 .../frame/diagnose/bad-reference/TestBadReference.py   |  2 +-
 .../TestComplicatedExpression.py   |  2 +-
 .../TestDiagnoseDereferenceArgument.py |  2 +-
 .../TestDiagnoseDereferenceFunctionReturn.py   |  2 +-
 .../dereference-this/TestDiagnoseDereferenceThis.py|  2 +-
 .../diagnose/inheritance/TestDiagnoseInheritance.py|  2 +-
 .../frame/diagnose/local-variable/TestLocalVariable.py |  2 +-
 .../TestDiagnoseDereferenceVirtualMethodCall.py|  2 +-
 .../TestAArch64LinuxMTEMemoryTagCoreFile.py|  2 +-
 .../TestAArch64LinuxNonAddressBitMemoryAccess.py   |  2 +-
 .../Shell/Register/Core/x86-32-linux-multithread.test  |  2 +-
 .../Shell/Register/Core/x86-64-linux-multithread.test  |  2 +-
 lldb/unittests/Signals/UnixSignalsTest.cpp | 10 +-
 15 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/lldb/source/Target/UnixSignals.cpp 
b/lldb/source/Target/UnixSignals.cpp
index bee3a63818259e..da661003925c79 100644
--- a/lldb/source/Target/UnixSignals.cpp
+++ b/lldb/source/Target/UnixSignals.cpp
@@ -163,7 +163,7 @@ UnixSignals::GetSignalDescription(int32_t signo, 
std::optional code,
   break;
 case SignalCodePrintOption::Address:
   if (addr)
-strm << " (fault address: 0x" << std::hex << *addr << ")";
+strm << " (fault address=0x" << std::hex << *addr << ")";
   break;
 case SignalCodePrintOption::Bounds:
   if (lower && upper && addr) {
@@ -172,9 +172,9 @@ UnixSignals::GetSignalDescription(int32_t signo, 
std::optional code,
 else
   strm << "upper bound violation ";
 
-strm << "(fault address: 0x" << std::hex << *addr;
-strm << ", lower bound: 0x" << std::hex << *lower;
-strm << ", upper bound: 0x" << std::hex << *upper;
+strm << "(fault address=0x" << std::hex << *addr;
+strm << ", lower bound=0x" << std::hex << *lower;
+strm << ", upper bound=0x" << std::hex << *upper;
 strm << ")";
   } else
 strm << sc.m_description.str();
diff --git a/lldb/test/API/commands/frame/diagnose/array/TestArray.py 
b/lldb/test/API/commands/frame/diagnose/array/TestArray.py
index 5de6f7b0aaa1c4..307e2cbca30228 100644
--- a/lldb/test/API/commands/frame/diagnose/array/TestArray.py
+++ b/lldb/test/API/commands/frame/diagnose/array/TestArray.py
@@ -10,7 +10,7 @@
 
 
 class TestArray(TestBase):
-@skipUnlessDarwin
+@expectedFailureAll(oslist=["windows"])
 @skipIf(
 archs=no_match(["x86_64"])
 )  #  frame diagnose doesn't work for armv7 or 
arm64
diff --git 
a/lldb/test/API/commands/frame/diagnose/bad-reference/TestBadReference.py 
b/lldb/test/API/commands/frame/diagnose/bad-reference/TestBadReference.py
index 7a9498cab13766..8ded5e2ff55c21 100644
--- a/lldb/test/API/commands/frame/diagnose/bad-reference/TestBadReference.py
+++ b/lldb/test/API/commands/frame/diagnose/bad-reference/TestBadReference.py
@@ -10,7 +10,7 @@
 
 
 class TestBadReference(TestBase):
-@skipUnlessDarwin
+@expectedFailureAll(oslist=["windows"])
 @skipIf(
 archs=no_match(["x86_64"])
 )  #  frame diagnose doesn't work for armv7 or 
arm64
diff --git 
a/lldb/test/API/commands/frame/diagnose/complicated-expression/TestComplicatedExpression.py
 
b/lldb/test/API/commands/frame/diagnose/complicated-expression/TestComplicatedExpression.py
index eb1b556f0c408d..8ee254a28cb545 100644
--- 
a/lldb/test/API/commands/frame/diagnose/complicated-expression/TestComplicatedExpression.py
+++ 
b/ll

[Lldb-commits] [lldb] [lldb][AIX] Taking Linux Host Info header's base for AIX (PR #106910)

2025-01-20 Thread Dhruv Srivastava via lldb-commits


@@ -55,6 +55,9 @@
 #elif defined(__APPLE__)
 #include "lldb/Host/macosx/HostInfoMacOSX.h"
 #define HOST_INFO_TYPE HostInfoMacOSX
+#elif defined(__AIX__)

DhruvSrivastavaX wrote:

Already merged

https://github.com/llvm/llvm-project/pull/106910
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][AIX] Taking Linux Host Info header's base for AIX (PR #106910)

2025-01-20 Thread Dhruv Srivastava via lldb-commits


@@ -0,0 +1,60 @@
+//===-- Ptrace.h *- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+// This file defines ptrace functions & structures
+
+#ifndef liblldb_Host_linux_Ptrace_h_
+#define liblldb_Host_linux_Ptrace_h_
+
+#include 
+

DhruvSrivastavaX wrote:

Planning on removing

https://github.com/llvm/llvm-project/pull/106910
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][AIX] Taking Linux Host Info header's base for AIX (PR #106910)

2025-01-20 Thread Dhruv Srivastava via lldb-commits


@@ -11,11 +11,11 @@
 
 #include "lldb/lldb-defines.h"
 
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) || defined(__AIX__)
 #define REPLACE_GETOPT
 #define REPLACE_GETOPT_LONG
 #endif
-#if defined(_MSC_VER) || defined(__NetBSD__)
+#if defined(_MSC_VER) || defined(__NetBSD__) || defined(__AIX__)

DhruvSrivastavaX wrote:

Merged

https://github.com/llvm/llvm-project/pull/106910
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][AIX] Taking Linux Host Info header's base for AIX (PR #106910)

2025-01-20 Thread Dhruv Srivastava via lldb-commits


@@ -0,0 +1,43 @@
+//===-- HostInfoLinux.h -*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.

DhruvSrivastavaX wrote:

Already modified and merged

https://github.com/llvm/llvm-project/pull/106910
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Add SymbolContext::GetAddress (PR #123340)

2025-01-20 Thread Pavel Labath via lldb-commits

https://github.com/labath updated 
https://github.com/llvm/llvm-project/pull/123340

>From 2d6210ad9527df5147987f856e941e61d9851a97 Mon Sep 17 00:00:00 2001
From: Pavel Labath 
Date: Fri, 17 Jan 2025 12:36:36 +0100
Subject: [PATCH 1/3] [lldb] Add SymbolContext::GetAddress

Many (most?) uses of SC::GetAddressRange were not interested in the
range, but in the address of the function/symbol contained inside the
symbol context. They were getting that by calling the GetBaseAddress on
the returned range, which worked well enough so far, but isn't
compatible with discontinuous functions, whose address (entry point) may
not be the lowest address in the range.

To resolve this problem, this PR creates a new function whose purpose is
return the address of the object inside the symbol context ("address of
a block" is a somewhat fuzzy concept, but I've made it so that mirrors
what the GetAddressRange function does). It also changes all of the
callers of GetAddressRange which do not actually care about the range to
call this function instead.

I've also changed all of the callers which are interested in the entry
point of a function/symbol to pass eSymbolContextFunction |
eSymbolContextSymbol instead of eSymbolContextEverything, as a block or
a line will not have a callable address.
---
 lldb/include/lldb/Symbol/SymbolContext.h  | 27 
 lldb/source/Commands/CommandObjectTarget.cpp  | 17 +++---
 .../Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp |  6 ++--
 .../MacOSX-DYLD/DynamicLoaderDarwin.cpp   | 20 +---
 .../POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp |  6 ++--
 .../CPlusPlus/CPPLanguageRuntime.cpp  |  6 ++--
 .../Process/Utility/InferiorCallPOSIX.cpp | 32 ---
 .../MacOSX/SystemRuntimeMacOSX.cpp| 24 +-
 lldb/source/Symbol/SymbolContext.cpp  | 25 +++
 9 files changed, 95 insertions(+), 68 deletions(-)

diff --git a/lldb/include/lldb/Symbol/SymbolContext.h 
b/lldb/include/lldb/Symbol/SymbolContext.h
index 07769cd8dffae7..fde11f275dc60a 100644
--- a/lldb/include/lldb/Symbol/SymbolContext.h
+++ b/lldb/include/lldb/Symbol/SymbolContext.h
@@ -192,6 +192,33 @@ class SymbolContext {
   bool GetAddressRange(uint32_t scope, uint32_t range_idx,
bool use_inline_block_range, AddressRange &range) const;
 
+  /// Get the address represented by this symbol context.
+  ///
+  /// The exact meaning of the address depends on object being queried and the
+  /// flags. Priority is as follows:
+  /// - The beginning (lowest address) of the line_entry if line_entry is
+  /// valid and eSymbolContextLineEntry is set in \a scope
+  /// - The beginning of the block if block is not nullptr and
+  /// eSymbolContextBlock is set in \a scope
+  /// - function address (entry point) if function is not nullptr and
+  /// eSymbolContextFunction is set in \a scope
+  /// - symbol address if symbol is not nullptr and eSymbolContextSymbol is
+  /// set in \a scope
+  ///
+  /// \param[in] scope
+  /// A mask of symbol context bits telling this function which
+  /// address ranges it can use when trying to extract one from
+  /// the valid (non-nullptr) symbol context classes.
+  ///
+  /// \param[in] use_inline_block_range
+  /// If \a scope has the eSymbolContextBlock bit set, and there
+  /// is a valid block in the symbol context, return the block
+  /// address range for the containing inline function block, not
+  /// the deepest most block. This allows us to extract information
+  /// for the address range of the inlined function block, not
+  /// the deepest lexical block.
+  Address GetAddress(uint32_t scope, bool use_inline_block_range) const;
+
   llvm::Error GetAddressRangeFromHereToEndLine(uint32_t end_line,
AddressRange &range);
 
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp 
b/lldb/source/Commands/CommandObjectTarget.cpp
index d8265e41a7384e..705c69167badd3 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -1621,12 +1621,8 @@ static void DumpSymbolContextList(
 if (!first_module)
   strm.EOL();
 
-AddressRange range;
-
-sc.GetAddressRange(eSymbolContextEverything, 0, true, range);
-
-DumpAddress(exe_scope, range.GetBaseAddress(), verbose, all_ranges, strm,
-settings);
+Address addr = sc.GetAddress(eSymbolContextEverything, true);
+DumpAddress(exe_scope, addr, verbose, all_ranges, strm, settings);
 first_module = false;
   }
   strm.IndentLess();
@@ -3570,16 +3566,13 @@ class CommandObjectTargetModulesShowUnwind : public 
CommandObjectParsed {
 continue;
   if (!sc.module_sp || sc.module_sp->GetObjectFile() == nullptr)
 continue;
-  AddressRange range;
-  if (!sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
-  

[Lldb-commits] [lldb] [lldb] Add SymbolContext::GetAddress (PR #123340)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -192,6 +192,33 @@ class SymbolContext {
   bool GetAddressRange(uint32_t scope, uint32_t range_idx,
bool use_inline_block_range, AddressRange &range) const;
 
+  /// Get the address represented by this symbol context.
+  ///
+  /// The exact meaning of the address depends on object being queried and the
+  /// flags. Priority is as follows:
+  /// - The beginning (lowest address) of the line_entry if line_entry is
+  /// valid and eSymbolContextLineEntry is set in \a scope
+  /// - The beginning of the block if block is not nullptr and
+  /// eSymbolContextBlock is set in \a scope
+  /// - function address (entry point) if function is not nullptr and
+  /// eSymbolContextFunction is set in \a scope
+  /// - symbol address if symbol is not nullptr and eSymbolContextSymbol is
+  /// set in \a scope
+  ///
+  /// \param[in] scope
+  /// A mask of symbol context bits telling this function which

labath wrote:

I'm not sure what you mean. The individual bits and their meaning is listed in 
the paragraph above this. I don't think it makes sense to repeat them here. I 
could move the whole paragraph here, but I'm just following the pattern of 
`GetAddressRange`

https://github.com/llvm/llvm-project/pull/123340
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [LLDB] Add Lexer (with tests) for DIL (Data Inspection Language). (PR #123521)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,156 @@
+//===-- DILLexer.h --*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+#ifndef LLDB_VALUEOBJECT_DILLEXER_H_
+#define LLDB_VALUEOBJECT_DILLEXER_H_
+
+#include "llvm/ADT/StringRef.h"
+#include 
+#include 
+#include 
+#include 
+#include 
+
+namespace lldb_private {
+
+namespace dil {
+
+enum class TokenKind {
+  coloncolon,
+  eof,
+  identifier,
+  invalid,
+  kw_namespace,
+  l_paren,
+  none,
+  r_paren,
+  unknown,
+};
+
+/// Class defining the tokens generated by the DIL lexer and used by the
+/// DIL parser.
+class DILToken {
+public:
+  DILToken(dil::TokenKind kind, std::string spelling, uint32_t start)
+  : m_kind(kind), m_spelling(spelling), m_start_pos(start) {}
+
+  DILToken() : m_kind(dil::TokenKind::none), m_spelling(""), m_start_pos(0) {}
+
+  void setKind(dil::TokenKind kind) { m_kind = kind; }
+  dil::TokenKind getKind() const { return m_kind; }
+
+  std::string getSpelling() const { return m_spelling; }
+
+  uint32_t getLength() const { return m_spelling.size(); }
+
+  bool is(dil::TokenKind kind) const { return m_kind == kind; }
+
+  bool isNot(dil::TokenKind kind) const { return m_kind != kind; }
+
+  bool isOneOf(dil::TokenKind kind1, dil::TokenKind kind2) const {
+return is(kind1) || is(kind2);
+  }
+
+  template  bool isOneOf(dil::TokenKind kind, Ts... Ks) const {
+return is(kind) || isOneOf(Ks...);
+  }
+
+  uint32_t getLocation() const { return m_start_pos; }
+
+  void setValues(dil::TokenKind kind, std::string spelling, uint32_t start) {
+m_kind = kind;
+m_spelling = spelling;
+m_start_pos = start;
+  }
+
+  static const std::string getTokenName(dil::TokenKind kind);
+
+private:
+  dil::TokenKind m_kind;
+  std::string m_spelling;
+  uint32_t m_start_pos; // within entire expression string
+};
+
+/// Class for doing the simple lexing required by DIL.
+class DILLexer {
+public:
+  DILLexer(llvm::StringRef dil_expr) : m_expr(dil_expr.str()) {
+m_cur_pos = m_expr.begin();
+// Use UINT_MAX to indicate invalid/uninitialized value.
+m_tokens_idx = UINT_MAX;
+  }
+
+  bool Lex(DILToken &result, bool look_ahead = false);
+
+  bool Is_Word(std::string::iterator start, uint32_t &length);
+
+  uint32_t GetLocation() { return m_cur_pos - m_expr.begin(); }
+
+  /// Update 'result' with the other paremeter values, create a
+  /// duplicate token, and push the duplicate token onto the vector of
+  /// lexed tokens.
+  void UpdateLexedTokens(DILToken &result, dil::TokenKind tok_kind,

labath wrote:

Should all of these APIs really be public?

https://github.com/llvm/llvm-project/pull/123521
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [LLDB] Add Lexer (with tests) for DIL (Data Inspection Language). (PR #123521)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,205 @@
+//===-- DILLexer.cpp 
--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// This implements the recursive descent parser for the Data Inspection
+// Language (DIL), and its helper functions, which will eventually underlie the
+// 'frame variable' command. The language that this parser recognizes is
+// described in lldb/docs/dil-expr-lang.ebnf
+//
+//===--===//
+
+#include "lldb/ValueObject/DILLexer.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace lldb_private {
+
+namespace dil {
+
+// For fast keyword lookup. More keywords will be added later.
+const llvm::StringMap Keywords = {
+{"namespace", dil::TokenKind::kw_namespace},
+};

labath wrote:

This violatees 
https://llvm.org/docs/CodingStandards.html#do-not-use-static-constructors

You could make it a function-local static variable (so that it's initialized on 
first use), but unless we're going to have many, many keywords, I probably 
wouldn't bother with that and use llvm::StringSwitch instead.

https://github.com/llvm/llvm-project/pull/123521
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [LLDB] Add Lexer (with tests) for DIL (Data Inspection Language). (PR #123521)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,205 @@
+//===-- DILLexer.cpp 
--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// This implements the recursive descent parser for the Data Inspection
+// Language (DIL), and its helper functions, which will eventually underlie the
+// 'frame variable' command. The language that this parser recognizes is
+// described in lldb/docs/dil-expr-lang.ebnf
+//
+//===--===//
+
+#include "lldb/ValueObject/DILLexer.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace lldb_private {
+
+namespace dil {
+
+// For fast keyword lookup. More keywords will be added later.
+const llvm::StringMap Keywords = {
+{"namespace", dil::TokenKind::kw_namespace},
+};
+
+const std::string DILToken::getTokenName(dil::TokenKind kind) {
+  switch (kind) {
+  case dil::TokenKind::coloncolon:
+return "coloncolon";
+  case dil::TokenKind::eof:
+return "eof";
+  case dil::TokenKind::identifier:
+return "identifier";
+  case dil::TokenKind::kw_namespace:
+return "namespace";
+  case dil::TokenKind::l_paren:
+return "l_paren";
+  case dil::TokenKind::r_paren:
+return "r_paren";
+  case dil::TokenKind::unknown:
+return "unknown";
+  default:
+return "token_name";
+  }
+}
+
+static bool Is_Letter(char c) {
+  if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
+return true;
+  return false;
+}
+
+static bool Is_Digit(char c) { return ('0' <= c && c <= '9'); }
+
+// A word starts with a letter, underscore, or dollar sign, followed by
+// letters ('a'..'z','A'..'Z'), digits ('0'..'9'), and/or  underscores.
+bool DILLexer::Is_Word(std::string::iterator start, uint32_t &length) {
+  bool done = false;
+  bool dollar_start = false;
+
+  // Must not start with a digit.
+  if (m_cur_pos == m_expr.end() || Is_Digit(*m_cur_pos))
+return false;
+
+  // First character *may* be a '$', for a register name or convenience
+  // variable.
+  if (*m_cur_pos == '$') {
+dollar_start = true;
+++m_cur_pos;
+length++;
+  }
+
+  // Contains only letters, digits or underscores
+  for (; m_cur_pos != m_expr.end() && !done; ++m_cur_pos) {
+char c = *m_cur_pos;
+if (!Is_Letter(c) && !Is_Digit(c) && c != '_') {
+  done = true;
+  break;
+} else
+  length++;
+  }
+
+  if (dollar_start && length > 1) // Must have something besides just '$'
+return true;
+
+  if (!dollar_start && length > 0)
+return true;
+
+  // Not a valid word, so re-set the lexing position.
+  m_cur_pos = start;

labath wrote:

AFAICT, this is the only use of the start argument, which makes for a very 
weird API. Perhaps the function could make a note of the starting position 
internally, and then return the range it found to the caller (I'd suggest a 
return type of `iterator_range, with the empty range meaning 
"no word found")

https://github.com/llvm/llvm-project/pull/123521
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [LLDB] Add Lexer (with tests) for DIL (Data Inspection Language). (PR #123521)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,156 @@
+//===-- DILLexer.h --*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+#ifndef LLDB_VALUEOBJECT_DILLEXER_H_
+#define LLDB_VALUEOBJECT_DILLEXER_H_
+
+#include "llvm/ADT/StringRef.h"
+#include 
+#include 
+#include 
+#include 
+#include 
+
+namespace lldb_private {
+
+namespace dil {
+
+enum class TokenKind {
+  coloncolon,
+  eof,
+  identifier,
+  invalid,
+  kw_namespace,
+  l_paren,
+  none,
+  r_paren,
+  unknown,
+};
+
+/// Class defining the tokens generated by the DIL lexer and used by the
+/// DIL parser.
+class DILToken {
+public:
+  DILToken(dil::TokenKind kind, std::string spelling, uint32_t start)
+  : m_kind(kind), m_spelling(spelling), m_start_pos(start) {}
+
+  DILToken() : m_kind(dil::TokenKind::none), m_spelling(""), m_start_pos(0) {}
+
+  void setKind(dil::TokenKind kind) { m_kind = kind; }
+  dil::TokenKind getKind() const { return m_kind; }
+
+  std::string getSpelling() const { return m_spelling; }
+
+  uint32_t getLength() const { return m_spelling.size(); }
+
+  bool is(dil::TokenKind kind) const { return m_kind == kind; }
+
+  bool isNot(dil::TokenKind kind) const { return m_kind != kind; }
+
+  bool isOneOf(dil::TokenKind kind1, dil::TokenKind kind2) const {
+return is(kind1) || is(kind2);
+  }
+
+  template  bool isOneOf(dil::TokenKind kind, Ts... Ks) const {
+return is(kind) || isOneOf(Ks...);
+  }
+
+  uint32_t getLocation() const { return m_start_pos; }
+
+  void setValues(dil::TokenKind kind, std::string spelling, uint32_t start) {
+m_kind = kind;
+m_spelling = spelling;
+m_start_pos = start;
+  }

labath wrote:

could we use the assignment operator instead (`token = Token(kind, spelling, 
start)`) ?

https://github.com/llvm/llvm-project/pull/123521
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [LLDB] Add Lexer (with tests) for DIL (Data Inspection Language). (PR #123521)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,205 @@
+//===-- DILLexer.cpp 
--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// This implements the recursive descent parser for the Data Inspection
+// Language (DIL), and its helper functions, which will eventually underlie the
+// 'frame variable' command. The language that this parser recognizes is
+// described in lldb/docs/dil-expr-lang.ebnf
+//
+//===--===//
+
+#include "lldb/ValueObject/DILLexer.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace lldb_private {
+
+namespace dil {
+
+// For fast keyword lookup. More keywords will be added later.
+const llvm::StringMap Keywords = {
+{"namespace", dil::TokenKind::kw_namespace},
+};
+
+const std::string DILToken::getTokenName(dil::TokenKind kind) {
+  switch (kind) {
+  case dil::TokenKind::coloncolon:
+return "coloncolon";
+  case dil::TokenKind::eof:
+return "eof";
+  case dil::TokenKind::identifier:
+return "identifier";
+  case dil::TokenKind::kw_namespace:
+return "namespace";
+  case dil::TokenKind::l_paren:
+return "l_paren";
+  case dil::TokenKind::r_paren:
+return "r_paren";
+  case dil::TokenKind::unknown:
+return "unknown";
+  default:
+return "token_name";
+  }
+}
+
+static bool Is_Letter(char c) {
+  if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
+return true;
+  return false;
+}
+
+static bool Is_Digit(char c) { return ('0' <= c && c <= '9'); }

labath wrote:

```suggestion
static bool IsLetter(char c) {
  return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
}

static bool IsDigit(char c) { return '0' <= c && c <= '9'; }
```

https://github.com/llvm/llvm-project/pull/123521
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [LLDB] Add Lexer (with tests) for DIL (Data Inspection Language). (PR #123521)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,205 @@
+//===-- DILLexer.cpp 
--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// This implements the recursive descent parser for the Data Inspection
+// Language (DIL), and its helper functions, which will eventually underlie the
+// 'frame variable' command. The language that this parser recognizes is
+// described in lldb/docs/dil-expr-lang.ebnf
+//
+//===--===//
+
+#include "lldb/ValueObject/DILLexer.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace lldb_private {
+
+namespace dil {
+
+// For fast keyword lookup. More keywords will be added later.
+const llvm::StringMap Keywords = {
+{"namespace", dil::TokenKind::kw_namespace},
+};
+
+const std::string DILToken::getTokenName(dil::TokenKind kind) {
+  switch (kind) {
+  case dil::TokenKind::coloncolon:
+return "coloncolon";
+  case dil::TokenKind::eof:
+return "eof";
+  case dil::TokenKind::identifier:
+return "identifier";
+  case dil::TokenKind::kw_namespace:
+return "namespace";
+  case dil::TokenKind::l_paren:
+return "l_paren";
+  case dil::TokenKind::r_paren:
+return "r_paren";
+  case dil::TokenKind::unknown:
+return "unknown";
+  default:
+return "token_name";
+  }
+}
+
+static bool Is_Letter(char c) {
+  if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
+return true;
+  return false;
+}
+
+static bool Is_Digit(char c) { return ('0' <= c && c <= '9'); }
+
+// A word starts with a letter, underscore, or dollar sign, followed by
+// letters ('a'..'z','A'..'Z'), digits ('0'..'9'), and/or  underscores.
+bool DILLexer::Is_Word(std::string::iterator start, uint32_t &length) {
+  bool done = false;

labath wrote:

it doesn't look like this is used for anything

https://github.com/llvm/llvm-project/pull/123521
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [LLDB] Add Lexer (with tests) for DIL (Data Inspection Language). (PR #123521)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,193 @@
+//===-- DILLexerTests.cpp ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+#include "lldb/ValueObject/DILLexer.h"
+#include "llvm/ADT/StringRef.h"
+#include "gtest/gtest.h"
+#include 
+
+using llvm::StringRef;
+
+TEST(DILLexerTests, SimpleTest) {
+  StringRef dil_input_expr("simple_var");
+  uint32_t tok_len = 10;
+  lldb_private::dil::DILLexer dil_lexer(dil_input_expr);
+  lldb_private::dil::DILToken dil_token;
+  dil_token.setKind(lldb_private::dil::TokenKind::unknown);
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::unknown);
+  dil_lexer.Lex(dil_token);
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::identifier);
+  EXPECT_EQ(dil_token.getSpelling(), "simple_var");
+  EXPECT_EQ(dil_token.getLength(), tok_len);
+  dil_lexer.Lex(dil_token);
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::eof);
+}
+
+TEST(DILLexerTests, TokenKindTest) {
+  StringRef dil_input_expr("namespace");
+  lldb_private::dil::DILLexer dil_lexer(dil_input_expr);
+  lldb_private::dil::DILToken dil_token;
+  dil_token.setKind(lldb_private::dil::TokenKind::unknown);
+
+  dil_lexer.Lex(dil_token);
+  EXPECT_EQ(dil_lexer.GetCurrentTokenIdx(), UINT_MAX);
+  dil_lexer.ResetTokenIdx(0);
+
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::kw_namespace);
+  EXPECT_TRUE(dil_token.isNot(lldb_private::dil::TokenKind::identifier));
+  EXPECT_FALSE(dil_token.is(lldb_private::dil::TokenKind::l_paren));
+  EXPECT_TRUE(dil_token.isOneOf(lldb_private::dil::TokenKind::eof,
+lldb_private::dil::TokenKind::kw_namespace));
+  EXPECT_FALSE(dil_token.isOneOf(lldb_private::dil::TokenKind::l_paren,
+ lldb_private::dil::TokenKind::r_paren,
+ lldb_private::dil::TokenKind::coloncolon,
+ lldb_private::dil::TokenKind::eof));
+
+  dil_token.setKind(lldb_private::dil::TokenKind::identifier);
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::identifier);
+}
+
+TEST(DILLexerTests, LookAheadTest) {
+  StringRef dil_input_expr("(anonymous namespace)::some_var");
+  lldb_private::dil::DILLexer dil_lexer(dil_input_expr);
+  lldb_private::dil::DILToken dil_token;
+  dil_token.setKind(lldb_private::dil::TokenKind::unknown);
+  uint32_t expect_loc = 23;
+
+  dil_lexer.Lex(dil_token);
+  EXPECT_EQ(dil_lexer.GetCurrentTokenIdx(), UINT_MAX);
+  dil_lexer.ResetTokenIdx(0);
+
+  // Current token is '('; check the next 4 tokens, to make
+  // sure they are the identifier 'anonymous', the namespace keyword,
+  // ')' and '::', in that order.
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::l_paren);
+  EXPECT_EQ(dil_lexer.LookAhead(0).getKind(),
+lldb_private::dil::TokenKind::identifier);
+  EXPECT_EQ(dil_lexer.LookAhead(0).getSpelling(), "anonymous");
+  EXPECT_EQ(dil_lexer.LookAhead(1).getKind(),
+lldb_private::dil::TokenKind::kw_namespace);
+  EXPECT_EQ(dil_lexer.LookAhead(2).getKind(),
+lldb_private::dil::TokenKind::r_paren);
+  EXPECT_EQ(dil_lexer.LookAhead(3).getKind(),
+lldb_private::dil::TokenKind::coloncolon);
+  // Verify we've advanced our position counter (lexing location) in the
+  // input 23 characters (the length of '(anonymous namespace)::'.
+  EXPECT_EQ(dil_lexer.GetLocation(), expect_loc);
+
+  // Our current index should still be 0, as we only looked ahead; we are still
+  // officially on the '('.
+  EXPECT_EQ(dil_lexer.GetCurrentTokenIdx(), 0);
+
+  // Accept the 'lookahead', so our current token is '::', which has the index
+  // 4 in our vector of tokens (which starts at zero).
+  dil_token = dil_lexer.AcceptLookAhead(3);
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::coloncolon);
+  EXPECT_EQ(dil_lexer.GetCurrentTokenIdx(), 4);
+
+  // Lex the final variable name in the input string
+  dil_lexer.Lex(dil_token);
+  dil_lexer.IncrementTokenIdx();
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::identifier);
+  EXPECT_EQ(dil_token.getSpelling(), "some_var");
+  EXPECT_EQ(dil_lexer.GetCurrentTokenIdx(), 5);
+
+  dil_lexer.Lex(dil_token);
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::eof);
+}
+
+TEST(DILLexerTests, MultiTokenLexTest) {
+  StringRef dil_input_expr("This string has several identifiers");
+  lldb_private::dil::DILLexer dil_lexer(dil_input_expr);
+  lldb_private::dil::DILToken dil_token;
+  dil_token.setKind(lldb_private::dil::TokenKind::unknown);
+
+  dil_lexer.Lex(dil_token);
+  EXPECT_EQ(dil_lexer.GetCurrentTokenIdx(), UINT_MAX);
+  dil_lexer.ResetTokenIdx(0);
+
+  EXPECT_EQ(dil_token.getSpelling(), "This")

[Lldb-commits] [lldb] [LLDB] Add Lexer (with tests) for DIL (Data Inspection Language). (PR #123521)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,156 @@
+//===-- DILLexer.h --*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+#ifndef LLDB_VALUEOBJECT_DILLEXER_H_
+#define LLDB_VALUEOBJECT_DILLEXER_H_
+
+#include "llvm/ADT/StringRef.h"
+#include 
+#include 
+#include 
+#include 
+#include 
+
+namespace lldb_private {
+
+namespace dil {
+
+enum class TokenKind {
+  coloncolon,
+  eof,
+  identifier,
+  invalid,
+  kw_namespace,
+  l_paren,
+  none,
+  r_paren,
+  unknown,
+};
+
+/// Class defining the tokens generated by the DIL lexer and used by the
+/// DIL parser.
+class DILToken {
+public:
+  DILToken(dil::TokenKind kind, std::string spelling, uint32_t start)
+  : m_kind(kind), m_spelling(spelling), m_start_pos(start) {}
+
+  DILToken() : m_kind(dil::TokenKind::none), m_spelling(""), m_start_pos(0) {}
+
+  void setKind(dil::TokenKind kind) { m_kind = kind; }
+  dil::TokenKind getKind() const { return m_kind; }
+
+  std::string getSpelling() const { return m_spelling; }
+
+  uint32_t getLength() const { return m_spelling.size(); }
+
+  bool is(dil::TokenKind kind) const { return m_kind == kind; }
+
+  bool isNot(dil::TokenKind kind) const { return m_kind != kind; }
+
+  bool isOneOf(dil::TokenKind kind1, dil::TokenKind kind2) const {
+return is(kind1) || is(kind2);
+  }
+
+  template  bool isOneOf(dil::TokenKind kind, Ts... Ks) const {
+return is(kind) || isOneOf(Ks...);
+  }
+
+  uint32_t getLocation() const { return m_start_pos; }
+
+  void setValues(dil::TokenKind kind, std::string spelling, uint32_t start) {
+m_kind = kind;
+m_spelling = spelling;
+m_start_pos = start;
+  }
+
+  static const std::string getTokenName(dil::TokenKind kind);
+
+private:
+  dil::TokenKind m_kind;
+  std::string m_spelling;
+  uint32_t m_start_pos; // within entire expression string
+};
+
+/// Class for doing the simple lexing required by DIL.
+class DILLexer {
+public:
+  DILLexer(llvm::StringRef dil_expr) : m_expr(dil_expr.str()) {
+m_cur_pos = m_expr.begin();
+// Use UINT_MAX to indicate invalid/uninitialized value.
+m_tokens_idx = UINT_MAX;
+  }
+
+  bool Lex(DILToken &result, bool look_ahead = false);

labath wrote:

```suggestion
  std::optional Lex(bool look_ahead = false);
```

https://github.com/llvm/llvm-project/pull/123521
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [LLDB] Add Lexer (with tests) for DIL (Data Inspection Language). (PR #123521)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,205 @@
+//===-- DILLexer.cpp 
--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// This implements the recursive descent parser for the Data Inspection
+// Language (DIL), and its helper functions, which will eventually underlie the
+// 'frame variable' command. The language that this parser recognizes is
+// described in lldb/docs/dil-expr-lang.ebnf
+//
+//===--===//
+
+#include "lldb/ValueObject/DILLexer.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace lldb_private {
+
+namespace dil {
+
+// For fast keyword lookup. More keywords will be added later.
+const llvm::StringMap Keywords = {
+{"namespace", dil::TokenKind::kw_namespace},
+};
+
+const std::string DILToken::getTokenName(dil::TokenKind kind) {
+  switch (kind) {
+  case dil::TokenKind::coloncolon:
+return "coloncolon";
+  case dil::TokenKind::eof:
+return "eof";
+  case dil::TokenKind::identifier:
+return "identifier";
+  case dil::TokenKind::kw_namespace:
+return "namespace";
+  case dil::TokenKind::l_paren:
+return "l_paren";
+  case dil::TokenKind::r_paren:
+return "r_paren";
+  case dil::TokenKind::unknown:
+return "unknown";
+  default:
+return "token_name";

labath wrote:

Can we drop the default clause? All it does is make it easy to forget to modify 
this function when adding a new token type.

https://github.com/llvm/llvm-project/pull/123521
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [LLDB] Add Lexer (with tests) for DIL (Data Inspection Language). (PR #123521)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,205 @@
+//===-- DILLexer.cpp 
--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// This implements the recursive descent parser for the Data Inspection
+// Language (DIL), and its helper functions, which will eventually underlie the
+// 'frame variable' command. The language that this parser recognizes is
+// described in lldb/docs/dil-expr-lang.ebnf
+//
+//===--===//
+
+#include "lldb/ValueObject/DILLexer.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace lldb_private {
+
+namespace dil {
+
+// For fast keyword lookup. More keywords will be added later.
+const llvm::StringMap Keywords = {
+{"namespace", dil::TokenKind::kw_namespace},
+};
+
+const std::string DILToken::getTokenName(dil::TokenKind kind) {
+  switch (kind) {
+  case dil::TokenKind::coloncolon:
+return "coloncolon";
+  case dil::TokenKind::eof:
+return "eof";
+  case dil::TokenKind::identifier:
+return "identifier";
+  case dil::TokenKind::kw_namespace:
+return "namespace";
+  case dil::TokenKind::l_paren:
+return "l_paren";
+  case dil::TokenKind::r_paren:
+return "r_paren";
+  case dil::TokenKind::unknown:
+return "unknown";
+  default:
+return "token_name";
+  }
+}
+
+static bool Is_Letter(char c) {
+  if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
+return true;
+  return false;
+}
+
+static bool Is_Digit(char c) { return ('0' <= c && c <= '9'); }
+
+// A word starts with a letter, underscore, or dollar sign, followed by
+// letters ('a'..'z','A'..'Z'), digits ('0'..'9'), and/or  underscores.
+bool DILLexer::Is_Word(std::string::iterator start, uint32_t &length) {
+  bool done = false;
+  bool dollar_start = false;
+
+  // Must not start with a digit.
+  if (m_cur_pos == m_expr.end() || Is_Digit(*m_cur_pos))
+return false;
+
+  // First character *may* be a '$', for a register name or convenience

labath wrote:

I don't think this needs to change, but I'll note that `frame variable` 
currently does *not* support referencing registers or convenience variables. It 
is one of the first improvements I'd make to it though...

https://github.com/llvm/llvm-project/pull/123521
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [LLDB] Add Lexer (with tests) for DIL (Data Inspection Language). (PR #123521)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,205 @@
+//===-- DILLexer.cpp 
--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// This implements the recursive descent parser for the Data Inspection
+// Language (DIL), and its helper functions, which will eventually underlie the
+// 'frame variable' command. The language that this parser recognizes is
+// described in lldb/docs/dil-expr-lang.ebnf
+//
+//===--===//
+
+#include "lldb/ValueObject/DILLexer.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace lldb_private {
+
+namespace dil {
+
+// For fast keyword lookup. More keywords will be added later.
+const llvm::StringMap Keywords = {
+{"namespace", dil::TokenKind::kw_namespace},
+};
+
+const std::string DILToken::getTokenName(dil::TokenKind kind) {
+  switch (kind) {
+  case dil::TokenKind::coloncolon:
+return "coloncolon";
+  case dil::TokenKind::eof:
+return "eof";
+  case dil::TokenKind::identifier:
+return "identifier";
+  case dil::TokenKind::kw_namespace:
+return "namespace";
+  case dil::TokenKind::l_paren:
+return "l_paren";
+  case dil::TokenKind::r_paren:
+return "r_paren";
+  case dil::TokenKind::unknown:
+return "unknown";
+  default:
+return "token_name";
+  }
+}
+
+static bool Is_Letter(char c) {
+  if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
+return true;
+  return false;
+}
+
+static bool Is_Digit(char c) { return ('0' <= c && c <= '9'); }
+
+// A word starts with a letter, underscore, or dollar sign, followed by
+// letters ('a'..'z','A'..'Z'), digits ('0'..'9'), and/or  underscores.
+bool DILLexer::Is_Word(std::string::iterator start, uint32_t &length) {
+  bool done = false;
+  bool dollar_start = false;
+
+  // Must not start with a digit.
+  if (m_cur_pos == m_expr.end() || Is_Digit(*m_cur_pos))
+return false;
+
+  // First character *may* be a '$', for a register name or convenience
+  // variable.
+  if (*m_cur_pos == '$') {
+dollar_start = true;
+++m_cur_pos;
+length++;
+  }
+
+  // Contains only letters, digits or underscores
+  for (; m_cur_pos != m_expr.end() && !done; ++m_cur_pos) {
+char c = *m_cur_pos;
+if (!Is_Letter(c) && !Is_Digit(c) && c != '_') {
+  done = true;
+  break;
+} else
+  length++;
+  }
+
+  if (dollar_start && length > 1) // Must have something besides just '$'
+return true;
+
+  if (!dollar_start && length > 0)
+return true;
+
+  // Not a valid word, so re-set the lexing position.
+  m_cur_pos = start;
+  return false;
+}
+
+void DILLexer::UpdateLexedTokens(DILToken &result, dil::TokenKind tok_kind,
+ std::string tok_str, uint32_t tok_pos) {
+  DILToken new_token;
+  result.setValues(tok_kind, tok_str, tok_pos);
+  new_token = result;
+  m_lexed_tokens.push_back(std::move(new_token));
+}
+
+bool DILLexer::Lex(DILToken &result, bool look_ahead) {
+  bool retval = true;
+
+  if (!look_ahead) {
+// We're being asked for the 'next' token, and not a part of a LookAhead.
+// Check to see if we've already lexed it and pushed it onto our tokens
+// vector; if so, return the next token from the vector, rather than doing
+// more lexing.
+if ((m_tokens_idx != UINT_MAX) &&
+(m_tokens_idx < m_lexed_tokens.size() - 1)) {
+  result = m_lexed_tokens[m_tokens_idx + 1];
+  return retval;
+}
+  }
+
+  // Skip over whitespace (spaces).
+  while (m_cur_pos != m_expr.end() && *m_cur_pos == ' ')
+m_cur_pos++;
+
+  // Check to see if we've reached the end of our input string.
+  if (m_cur_pos == m_expr.end()) {
+UpdateLexedTokens(result, dil::TokenKind::eof, "", m_expr.length());
+return retval;
+  }
+
+  uint32_t position = m_cur_pos - m_expr.begin();
+  ;
+  std::string::iterator start = m_cur_pos;
+  uint32_t length = 0;
+  if (Is_Word(start, length)) {
+dil::TokenKind kind;
+std::string word = m_expr.substr(position, length);
+auto iter = Keywords.find(word);
+if (iter != Keywords.end())
+  kind = iter->second;
+else
+  kind = dil::TokenKind::identifier;
+
+UpdateLexedTokens(result, kind, word, position);
+return true;
+  }
+
+  switch (*m_cur_pos) {

labath wrote:

An iterator is sort of a natural representation of a position in a string, but 
it also makes it hard to use many of the nice (safe) string APIs. For example, 
if we had a `StringRef m_rest` to represent the unparsed portion of the string, 
then this block could be written as:
```
constexpr std::pair operators = {
  {TokenKind::l_paren, "("},
  {TokenKind::r_paren, ")"},
  {TokenKind::coloncolon, "::"},
  {TokenKind::colon, ":"},
};
size_t position = m_rest.data() - m_input.data();
for (auto [kind, str]: operators) {

[Lldb-commits] [lldb] [LLDB] Add Lexer (with tests) for DIL (Data Inspection Language). (PR #123521)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,156 @@
+//===-- DILLexer.h --*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+#ifndef LLDB_VALUEOBJECT_DILLEXER_H_
+#define LLDB_VALUEOBJECT_DILLEXER_H_
+
+#include "llvm/ADT/StringRef.h"
+#include 
+#include 
+#include 
+#include 
+#include 
+
+namespace lldb_private {
+
+namespace dil {
+
+enum class TokenKind {
+  coloncolon,
+  eof,
+  identifier,
+  invalid,
+  kw_namespace,
+  l_paren,
+  none,
+  r_paren,
+  unknown,
+};
+
+/// Class defining the tokens generated by the DIL lexer and used by the
+/// DIL parser.
+class DILToken {
+public:
+  DILToken(dil::TokenKind kind, std::string spelling, uint32_t start)
+  : m_kind(kind), m_spelling(spelling), m_start_pos(start) {}
+
+  DILToken() : m_kind(dil::TokenKind::none), m_spelling(""), m_start_pos(0) {}
+
+  void setKind(dil::TokenKind kind) { m_kind = kind; }
+  dil::TokenKind getKind() const { return m_kind; }
+
+  std::string getSpelling() const { return m_spelling; }
+
+  uint32_t getLength() const { return m_spelling.size(); }
+
+  bool is(dil::TokenKind kind) const { return m_kind == kind; }
+
+  bool isNot(dil::TokenKind kind) const { return m_kind != kind; }
+
+  bool isOneOf(dil::TokenKind kind1, dil::TokenKind kind2) const {
+return is(kind1) || is(kind2);
+  }
+
+  template  bool isOneOf(dil::TokenKind kind, Ts... Ks) const {
+return is(kind) || isOneOf(Ks...);
+  }
+
+  uint32_t getLocation() const { return m_start_pos; }
+
+  void setValues(dil::TokenKind kind, std::string spelling, uint32_t start) {
+m_kind = kind;
+m_spelling = spelling;
+m_start_pos = start;
+  }
+
+  static const std::string getTokenName(dil::TokenKind kind);
+
+private:
+  dil::TokenKind m_kind;
+  std::string m_spelling;
+  uint32_t m_start_pos; // within entire expression string
+};
+
+/// Class for doing the simple lexing required by DIL.
+class DILLexer {
+public:
+  DILLexer(llvm::StringRef dil_expr) : m_expr(dil_expr.str()) {
+m_cur_pos = m_expr.begin();
+// Use UINT_MAX to indicate invalid/uninitialized value.
+m_tokens_idx = UINT_MAX;
+  }
+
+  bool Lex(DILToken &result, bool look_ahead = false);
+
+  bool Is_Word(std::string::iterator start, uint32_t &length);
+
+  uint32_t GetLocation() { return m_cur_pos - m_expr.begin(); }
+
+  /// Update 'result' with the other paremeter values, create a
+  /// duplicate token, and push the duplicate token onto the vector of
+  /// lexed tokens.
+  void UpdateLexedTokens(DILToken &result, dil::TokenKind tok_kind,
+ std::string tok_str, uint32_t tok_pos);
+
+  /// Return the lexed token N+1 positions ahead of the 'current' token
+  /// being handled by the DIL parser.
+  const DILToken &LookAhead(uint32_t N);
+
+  const DILToken &AcceptLookAhead(uint32_t N);

labath wrote:

That would definitely be nice, and if its true, I'd consider taking this even 
further: given that we're going to be processing about a line of text at most, 
we might be able to just eagerly lex the whole string and avoid the whole 
on-demand parsing business. If so, maybe we don't even need the lexer *class* 
and the lexing could consist of a single function like `std::vector 
Lex(string)` ?

https://github.com/llvm/llvm-project/pull/123521
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [LLDB] Add Lexer (with tests) for DIL (Data Inspection Language). (PR #123521)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,156 @@
+//===-- DILLexer.h --*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+#ifndef LLDB_VALUEOBJECT_DILLEXER_H_
+#define LLDB_VALUEOBJECT_DILLEXER_H_
+
+#include "llvm/ADT/StringRef.h"
+#include 
+#include 
+#include 
+#include 
+#include 
+
+namespace lldb_private {
+
+namespace dil {
+
+enum class TokenKind {
+  coloncolon,
+  eof,
+  identifier,
+  invalid,
+  kw_namespace,
+  l_paren,
+  none,
+  r_paren,
+  unknown,
+};
+
+/// Class defining the tokens generated by the DIL lexer and used by the
+/// DIL parser.
+class DILToken {
+public:
+  DILToken(dil::TokenKind kind, std::string spelling, uint32_t start)
+  : m_kind(kind), m_spelling(spelling), m_start_pos(start) {}
+
+  DILToken() : m_kind(dil::TokenKind::none), m_spelling(""), m_start_pos(0) {}
+
+  void setKind(dil::TokenKind kind) { m_kind = kind; }
+  dil::TokenKind getKind() const { return m_kind; }
+
+  std::string getSpelling() const { return m_spelling; }
+
+  uint32_t getLength() const { return m_spelling.size(); }
+
+  bool is(dil::TokenKind kind) const { return m_kind == kind; }
+
+  bool isNot(dil::TokenKind kind) const { return m_kind != kind; }
+
+  bool isOneOf(dil::TokenKind kind1, dil::TokenKind kind2) const {
+return is(kind1) || is(kind2);
+  }
+
+  template  bool isOneOf(dil::TokenKind kind, Ts... Ks) const {
+return is(kind) || isOneOf(Ks...);
+  }
+
+  uint32_t getLocation() const { return m_start_pos; }
+
+  void setValues(dil::TokenKind kind, std::string spelling, uint32_t start) {
+m_kind = kind;
+m_spelling = spelling;
+m_start_pos = start;
+  }
+
+  static const std::string getTokenName(dil::TokenKind kind);
+
+private:
+  dil::TokenKind m_kind;
+  std::string m_spelling;
+  uint32_t m_start_pos; // within entire expression string
+};
+
+/// Class for doing the simple lexing required by DIL.
+class DILLexer {
+public:
+  DILLexer(llvm::StringRef dil_expr) : m_expr(dil_expr.str()) {
+m_cur_pos = m_expr.begin();
+// Use UINT_MAX to indicate invalid/uninitialized value.
+m_tokens_idx = UINT_MAX;
+  }
+
+  bool Lex(DILToken &result, bool look_ahead = false);
+
+  bool Is_Word(std::string::iterator start, uint32_t &length);

labath wrote:

```suggestion
  bool IsWord(std::string::iterator start, uint32_t &length);
```

https://github.com/llvm/llvm-project/pull/123521
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [LLDB] Add Lexer (with tests) for DIL (Data Inspection Language). (PR #123521)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,193 @@
+//===-- DILLexerTests.cpp ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+#include "lldb/ValueObject/DILLexer.h"
+#include "llvm/ADT/StringRef.h"
+#include "gtest/gtest.h"
+#include 
+
+using llvm::StringRef;
+
+TEST(DILLexerTests, SimpleTest) {
+  StringRef dil_input_expr("simple_var");
+  uint32_t tok_len = 10;
+  lldb_private::dil::DILLexer dil_lexer(dil_input_expr);
+  lldb_private::dil::DILToken dil_token;
+  dil_token.setKind(lldb_private::dil::TokenKind::unknown);
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::unknown);
+  dil_lexer.Lex(dil_token);
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::identifier);
+  EXPECT_EQ(dil_token.getSpelling(), "simple_var");
+  EXPECT_EQ(dil_token.getLength(), tok_len);
+  dil_lexer.Lex(dil_token);
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::eof);
+}
+
+TEST(DILLexerTests, TokenKindTest) {
+  StringRef dil_input_expr("namespace");
+  lldb_private::dil::DILLexer dil_lexer(dil_input_expr);
+  lldb_private::dil::DILToken dil_token;
+  dil_token.setKind(lldb_private::dil::TokenKind::unknown);
+
+  dil_lexer.Lex(dil_token);
+  EXPECT_EQ(dil_lexer.GetCurrentTokenIdx(), UINT_MAX);
+  dil_lexer.ResetTokenIdx(0);
+
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::kw_namespace);
+  EXPECT_TRUE(dil_token.isNot(lldb_private::dil::TokenKind::identifier));
+  EXPECT_FALSE(dil_token.is(lldb_private::dil::TokenKind::l_paren));
+  EXPECT_TRUE(dil_token.isOneOf(lldb_private::dil::TokenKind::eof,
+lldb_private::dil::TokenKind::kw_namespace));
+  EXPECT_FALSE(dil_token.isOneOf(lldb_private::dil::TokenKind::l_paren,
+ lldb_private::dil::TokenKind::r_paren,
+ lldb_private::dil::TokenKind::coloncolon,
+ lldb_private::dil::TokenKind::eof));
+
+  dil_token.setKind(lldb_private::dil::TokenKind::identifier);
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::identifier);
+}
+
+TEST(DILLexerTests, LookAheadTest) {
+  StringRef dil_input_expr("(anonymous namespace)::some_var");
+  lldb_private::dil::DILLexer dil_lexer(dil_input_expr);
+  lldb_private::dil::DILToken dil_token;
+  dil_token.setKind(lldb_private::dil::TokenKind::unknown);
+  uint32_t expect_loc = 23;
+
+  dil_lexer.Lex(dil_token);
+  EXPECT_EQ(dil_lexer.GetCurrentTokenIdx(), UINT_MAX);
+  dil_lexer.ResetTokenIdx(0);
+
+  // Current token is '('; check the next 4 tokens, to make
+  // sure they are the identifier 'anonymous', the namespace keyword,
+  // ')' and '::', in that order.
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::l_paren);
+  EXPECT_EQ(dil_lexer.LookAhead(0).getKind(),
+lldb_private::dil::TokenKind::identifier);
+  EXPECT_EQ(dil_lexer.LookAhead(0).getSpelling(), "anonymous");
+  EXPECT_EQ(dil_lexer.LookAhead(1).getKind(),
+lldb_private::dil::TokenKind::kw_namespace);
+  EXPECT_EQ(dil_lexer.LookAhead(2).getKind(),
+lldb_private::dil::TokenKind::r_paren);
+  EXPECT_EQ(dil_lexer.LookAhead(3).getKind(),
+lldb_private::dil::TokenKind::coloncolon);
+  // Verify we've advanced our position counter (lexing location) in the
+  // input 23 characters (the length of '(anonymous namespace)::'.
+  EXPECT_EQ(dil_lexer.GetLocation(), expect_loc);
+
+  // Our current index should still be 0, as we only looked ahead; we are still
+  // officially on the '('.
+  EXPECT_EQ(dil_lexer.GetCurrentTokenIdx(), 0);
+
+  // Accept the 'lookahead', so our current token is '::', which has the index
+  // 4 in our vector of tokens (which starts at zero).
+  dil_token = dil_lexer.AcceptLookAhead(3);
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::coloncolon);
+  EXPECT_EQ(dil_lexer.GetCurrentTokenIdx(), 4);
+
+  // Lex the final variable name in the input string
+  dil_lexer.Lex(dil_token);
+  dil_lexer.IncrementTokenIdx();
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::identifier);
+  EXPECT_EQ(dil_token.getSpelling(), "some_var");
+  EXPECT_EQ(dil_lexer.GetCurrentTokenIdx(), 5);
+
+  dil_lexer.Lex(dil_token);
+  EXPECT_EQ(dil_token.getKind(), lldb_private::dil::TokenKind::eof);
+}
+
+TEST(DILLexerTests, MultiTokenLexTest) {
+  StringRef dil_input_expr("This string has several identifiers");
+  lldb_private::dil::DILLexer dil_lexer(dil_input_expr);
+  lldb_private::dil::DILToken dil_token;
+  dil_token.setKind(lldb_private::dil::TokenKind::unknown);
+
+  dil_lexer.Lex(dil_token);
+  EXPECT_EQ(dil_lexer.GetCurrentTokenIdx(), UINT_MAX);
+  dil_lexer.ResetTokenIdx(0);
+
+  EXPECT_EQ(dil_token.getSpelling(), "This")

[Lldb-commits] [lldb] [LLDB] Add Lexer (with tests) for DIL (Data Inspection Language). (PR #123521)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,205 @@
+//===-- DILLexer.cpp 
--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// This implements the recursive descent parser for the Data Inspection
+// Language (DIL), and its helper functions, which will eventually underlie the
+// 'frame variable' command. The language that this parser recognizes is
+// described in lldb/docs/dil-expr-lang.ebnf
+//
+//===--===//
+
+#include "lldb/ValueObject/DILLexer.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace lldb_private {
+
+namespace dil {
+
+// For fast keyword lookup. More keywords will be added later.
+const llvm::StringMap Keywords = {
+{"namespace", dil::TokenKind::kw_namespace},
+};
+
+const std::string DILToken::getTokenName(dil::TokenKind kind) {

labath wrote:

`const` on a return type is useless, and if you don't plan on this function 
returning anything other than a constant string, then the it can return a 
StringRef

https://github.com/llvm/llvm-project/pull/123521
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [LLDB] Add Lexer (with tests) for DIL (Data Inspection Language). (PR #123521)

2025-01-20 Thread Pavel Labath via lldb-commits


@@ -0,0 +1,156 @@
+//===-- DILLexer.h --*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+#ifndef LLDB_VALUEOBJECT_DILLEXER_H_
+#define LLDB_VALUEOBJECT_DILLEXER_H_
+
+#include "llvm/ADT/StringRef.h"
+#include 
+#include 
+#include 
+#include 
+#include 
+
+namespace lldb_private {
+
+namespace dil {
+
+enum class TokenKind {

labath wrote:

Optional idea: Make this a non-class enum inside the (DIL)Token class so that 
it can be referred to as `Token::coloncolon`

https://github.com/llvm/llvm-project/pull/123521
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Implement basic support for reverse-continue (PR #112079)

2025-01-20 Thread David Spickett via lldb-commits

DavidSpickett wrote:

> Technically that is already true --- with stock LLDB and latest rr you can 
> debug an rr replay, which is useful. You just don't get the reverse-execution 
> superpower.

Ok so nothing has actually changed on that front, best wait until we can do the 
reverse execution from lldb before release noting anything.

https://github.com/llvm/llvm-project/pull/112079
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Implement ${target.file} format variable (PR #123431)

2025-01-20 Thread David Spickett via lldb-commits


@@ -113,11 +113,11 @@ A complete list of currently supported format string 
variables is listed below:
 
+---+-+
 | ``module.file.basename``  | The basename of the 
current module (shared library or executable)   


|
 
+---+-+
-| ``module.file.fullpath``  | The basename of the 
current module (shared library or executable)   


|
+| ``module.file.fullpath``  | The path of the current 
module (shared library or executable)   


|

DavidSpickett wrote:

I presume this is just correcting the docs, module.file.fullpath has always 
been the path, as the name suggests.

https://github.com/llvm/llvm-project/pull/123431
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Fix "in function" detection in "thread until" (PR #123622)

2025-01-20 Thread Pavel Labath via lldb-commits

https://github.com/labath updated 
https://github.com/llvm/llvm-project/pull/123622

>From 0a80b7a54b49de65758ab48acdb6d92f9b674d71 Mon Sep 17 00:00:00 2001
From: Pavel Labath 
Date: Mon, 20 Jan 2025 15:03:14 +0100
Subject: [PATCH 1/2] [lldb] Fix "in function" detection in "thread until"

The implementation has an optimization which detects the range of line
table entries covered by the function and then only searches for a
matching line between them.

This optimization was interfering with the logic for detecting whether a
line belongs to the function because the first call to FindLineEntry was
made with exact=false, which meant that if the function did not contain
any exact matches, we would just pick the closest line number in that
range, even if it was very far away.

This patch fixes that by first attempting an inexact search across the
entire line table, and then use the (potentially inexact) result of that
for searching within the function. This makes the optimization a less
effective, but I don't think we can differentiate between a line that
belongs to the function (but doesn't have any code) and a line outside
the function without that.

The patch also avoids the use of (deprecated) Function::GetAddressRange
by iterating over the GetAddressRanges result to find the full range of
line entries for the function.
---
 lldb/source/Commands/CommandObjectThread.cpp  | 57 ++-
 .../thread/step_until/TestStepUntil.py| 38 -
 2 files changed, 65 insertions(+), 30 deletions(-)

diff --git a/lldb/source/Commands/CommandObjectThread.cpp 
b/lldb/source/Commands/CommandObjectThread.cpp
index 4e2c4c1126bc3f..829abb8c5839bb 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -959,7 +959,6 @@ class CommandObjectThreadUntil : public CommandObjectParsed 
{
 }
 
 LineEntry function_start;
-uint32_t index_ptr = 0, end_ptr = UINT32_MAX;
 std::vector address_list;
 
 // Find the beginning & end index of the function, but first make
@@ -970,19 +969,22 @@ class CommandObjectThreadUntil : public 
CommandObjectParsed {
   return;
 }
 
-AddressRange fun_addr_range = sc.function->GetAddressRange();
-Address fun_start_addr = fun_addr_range.GetBaseAddress();
-line_table->FindLineEntryByAddress(fun_start_addr, function_start,
-   &index_ptr);
 
-Address fun_end_addr(fun_start_addr.GetSection(),
- fun_start_addr.GetOffset() +
- fun_addr_range.GetByteSize());
+uint32_t lowest_func_idx = UINT32_MAX;
+uint32_t highest_func_idx = 0;
+for (AddressRange range : sc.function->GetAddressRanges()) {
+  uint32_t idx;
+  LineEntry unused;
+  Address addr = range.GetBaseAddress();
+  if (line_table->FindLineEntryByAddress(addr, unused, &idx))
+lowest_func_idx = std::min(lowest_func_idx, idx);
 
-bool all_in_function = true;
+  addr.Slide(range.GetByteSize());
+  if (line_table->FindLineEntryByAddress(addr, unused, &idx))
+highest_func_idx = std::max(highest_func_idx, idx);
+}
 
-line_table->FindLineEntryByAddress(fun_end_addr, function_start,
-   &end_ptr);
+bool found_something = false;
 
 // Since not all source lines will contribute code, check if we are
 // setting the breakpoint on the exact line number or the nearest
@@ -991,14 +993,15 @@ class CommandObjectThreadUntil : public 
CommandObjectParsed {
 for (uint32_t line_number : line_numbers) {
   LineEntry line_entry;
   bool exact = false;
-  uint32_t start_idx_ptr = index_ptr;
-  start_idx_ptr = sc.comp_unit->FindLineEntry(
-  index_ptr, line_number, nullptr, exact, &line_entry);
-  if (start_idx_ptr != UINT32_MAX)
-line_number = line_entry.line;
+  if (sc.comp_unit->FindLineEntry(0, line_number, nullptr, exact,
+  &line_entry) == UINT32_MAX)
+continue;
+
+  found_something = true;
+  line_number = line_entry.line;
   exact = true;
-  start_idx_ptr = index_ptr;
-  while (start_idx_ptr <= end_ptr) {
+  uint32_t start_idx_ptr = lowest_func_idx;
+  while (start_idx_ptr <= highest_func_idx) {
 start_idx_ptr = sc.comp_unit->FindLineEntry(
 start_idx_ptr, line_number, nullptr, exact, &line_entry);
 if (start_idx_ptr == UINT32_MAX)
@@ -1007,29 +1010,29 @@ class CommandObjectThreadUntil : public 
CommandObjectParsed {
 addr_t address =
 line_entry.range.GetBaseAddress().GetLoadAddress(target);
 if (address != LLDB_INVALID_ADDRESS) {
-  if (fun_addr_range.Cont

[Lldb-commits] [lldb] [LLDB] Add DIL code for handling plain variable names. (PR #120971)

2025-01-20 Thread via lldb-commits


@@ -0,0 +1,106 @@
+//===-- DILEval.h ---*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+#ifndef LLDB_VALUEOBJECT_DILEVAL_H_
+#define LLDB_VALUEOBJECT_DILEVAL_H_
+
+#include "lldb/ValueObject/DILAST.h"
+#include "lldb/ValueObject/DILParser.h"
+#include 
+#include 
+
+namespace lldb_private {
+
+namespace dil {
+
+/// Class used to store & manipulate information about identifiers.
+class IdentifierInfo {
+public:
+  enum class Kind {
+eValue,
+eContextArg,
+  };
+
+  static std::unique_ptr FromValue(ValueObject &valobj) {
+CompilerType type;
+type = valobj.GetCompilerType();
+return std::unique_ptr(
+new IdentifierInfo(Kind::eValue, type, valobj.GetSP(), {}));
+  }
+
+  static std::unique_ptr FromContextArg(CompilerType type) {
+lldb::ValueObjectSP empty_value;
+return std::unique_ptr(
+new IdentifierInfo(Kind::eContextArg, type, empty_value, {}));
+  }
+
+  Kind GetKind() const { return m_kind; }
+  lldb::ValueObjectSP GetValue() const { return m_value; }
+
+  CompilerType GetType() { return m_type; }
+  bool IsValid() const { return m_type.IsValid(); }
+
+  IdentifierInfo(Kind kind, CompilerType type, lldb::ValueObjectSP value,
+ std::vector path)
+  : m_kind(kind), m_type(type), m_value(std::move(value)) {}
+
+private:
+  Kind m_kind;
+  CompilerType m_type;
+  lldb::ValueObjectSP m_value;
+};
+
+/// Given the name of an identifier (variable name, member name, type name,
+/// etc.), find the ValueObject for that name (if it exists) and create and
+/// return an IdentifierInfo object containing all the relevant information
+/// about that object (for DIL parsing and evaluating).
+std::unique_ptr LookupIdentifier(
+const std::string &name, std::shared_ptr ctx_scope,
+lldb::DynamicValueType use_dynamic, CompilerType *scope_ptr = nullptr);
+
+class DILInterpreter : Visitor {
+public:
+  DILInterpreter(lldb::TargetSP target, llvm::StringRef expr,
+ lldb::DynamicValueType use_dynamic,
+ std::shared_ptr exe_ctx_scope);
+
+  llvm::Expected DILEval(const DILASTNode *tree,
+  lldb::TargetSP target_sp);
+
+private:
+  lldb::ValueObjectSP DILEvalNode(const DILASTNode *node);
+
+  bool Success() { return m_error.Success(); }
+
+  void SetError(ErrorCode error_code, std::string error, uint32_t loc);
+
+  void Visit(const ErrorNode *node) override;
+  void Visit(const IdentifierNode *node) override;
+
+private:
+  // Used by the interpreter to create objects, perform casts, etc.
+  lldb::TargetSP m_target;
+
+  llvm::StringRef m_expr;
+
+  lldb::ValueObjectSP m_result;
+
+  lldb::ValueObjectSP m_scope;
+
+  lldb::DynamicValueType m_default_dynamic;
+
+  Status m_error;

cmtice wrote:

It turns out that I can get by without using a Status member object in the 
DILIntepreter. I have updated the DILInterpreter code to use llvm::Expected 
instead.

The use of the Status member in the DILParser will be much harder to remove and 
replace with llvm::Expected. But the good news is that the m_error status 
member in DILParser is only ever updated by the BailOut methods, which also 
immediately terminate parsing by setting the current token to EOF, and the top 
level call (Run) checks the error before returning, so I am hoping that in this 
case I will be allowed to keep the Status member variable?  

Among the reasons for not trying to convert all calls to BailOut to returning 
an llvm::Expected...: It's called from many functions with many different 
return types, including void. So at a minimum I would have to add return types 
to functions that currently don't return anything (as well as. changing the 
return types of nearly every function in the parser); I would have to do error 
type conversions in functions where they call something that fails with 
llvm::expected but the calling function returns llvm::expected. 
I would also have to add code to many of these sites to also update the current 
token to EOF, to terminate the parsing, not to mention the additional code at 
all the parse function call sites to see what value was returned & get the 
'real' (non error) value out of the expected return.  It will actually make the 
code much messier and more complicated than it is now.

I would be happy to add comments both at the declaration of the 'Status 
m_error;' variable in DILParser.h and in the BailOut functions, to the effect 
that this variable must ONLY be set in the BailOut functions (as it currently 
is).

https://github.com/llvm/llvm-project/pull/120971
___
lldb-commits mailing list
lldb-co

[Lldb-commits] [lldb] [LLDB] Add DIL code for handling plain variable names. (PR #120971)

2025-01-20 Thread via lldb-commits


@@ -0,0 +1,102 @@
+//===-- DILParser.h -*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+#ifndef LLDB_VALUEOBJECT_DILPARSER_H_
+#define LLDB_VALUEOBJECT_DILPARSER_H_
+
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/ValueObject/DILAST.h"
+#include "lldb/ValueObject/DILLexer.h"
+#include 
+#include 
+#include 
+#include 
+#include 
+
+namespace lldb_private {
+
+namespace dil {
+
+enum class ErrorCode : unsigned char {
+  kOk = 0,
+  kInvalidExpressionSyntax,
+  kUndeclaredIdentifier,
+  kUnknown,
+};
+
+std::string FormatDiagnostics(llvm::StringRef input_expr,
+  const std::string &message, uint32_t loc);
+
+/// Pure recursive descent parser for C++ like expressions.
+/// EBNF grammar for the parser is described in lldb/docs/dil-expr-lang.ebnf
+class DILParser {
+public:
+  explicit DILParser(llvm::StringRef dil_input_expr,
+ std::shared_ptr exe_ctx_scope,
+ lldb::DynamicValueType use_dynamic, bool use_synthetic,
+ bool fragile_ivar, bool check_ptr_vs_member);
+
+  llvm::Expected Run();
+
+  ~DILParser() { m_ctx_scope.reset(); }
+
+  bool UseSynthetic() { return m_use_synthetic; }
+
+  lldb::DynamicValueType UseDynamic() { return m_use_dynamic; }
+
+  using PtrOperator = std::tuple;
+
+private:
+  DILASTNodeUP ParseExpression();
+  DILASTNodeUP ParsePrimaryExpression();
+
+  std::string ParseNestedNameSpecifier();
+
+  std::string ParseIdExpression();
+  std::string ParseUnqualifiedId();
+
+  void ConsumeToken();
+
+  void BailOut(ErrorCode error_code, const std::string &error, uint32_t loc);
+
+  void BailOut(Status error);
+
+  void Expect(dil::TokenKind kind);
+
+  std::string TokenDescription(const DILToken &token);
+
+  void TentativeParsingRollback(uint32_t saved_idx) {
+m_error.Clear();
+m_dil_lexer.ResetTokenIdx(saved_idx);
+m_dil_token = m_dil_lexer.GetCurrentToken();
+  }
+
+  // Parser doesn't own the evaluation context. The produced AST may depend on
+  // it (for example, for source locations), so it's expected that expression
+  // context will outlive the parser.
+  std::shared_ptr m_ctx_scope;
+
+  llvm::StringRef m_input_expr;
+  // The token lexer is stopped at (aka "current token").
+  DILToken m_dil_token;
+  // Holds an error if it occures during parsing.
+  Status m_error;

cmtice wrote:

I'm already putting formatted diagnostics in my Status/Error. What would be the 
additional benefit of using the DIagnosticManager?

https://github.com/llvm/llvm-project/pull/120971
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Fix "in function" detection in "thread until" (PR #123622)

2025-01-20 Thread Pavel Labath via lldb-commits

https://github.com/labath updated 
https://github.com/llvm/llvm-project/pull/123622

>From 0a80b7a54b49de65758ab48acdb6d92f9b674d71 Mon Sep 17 00:00:00 2001
From: Pavel Labath 
Date: Mon, 20 Jan 2025 15:03:14 +0100
Subject: [PATCH 1/3] [lldb] Fix "in function" detection in "thread until"

The implementation has an optimization which detects the range of line
table entries covered by the function and then only searches for a
matching line between them.

This optimization was interfering with the logic for detecting whether a
line belongs to the function because the first call to FindLineEntry was
made with exact=false, which meant that if the function did not contain
any exact matches, we would just pick the closest line number in that
range, even if it was very far away.

This patch fixes that by first attempting an inexact search across the
entire line table, and then use the (potentially inexact) result of that
for searching within the function. This makes the optimization a less
effective, but I don't think we can differentiate between a line that
belongs to the function (but doesn't have any code) and a line outside
the function without that.

The patch also avoids the use of (deprecated) Function::GetAddressRange
by iterating over the GetAddressRanges result to find the full range of
line entries for the function.
---
 lldb/source/Commands/CommandObjectThread.cpp  | 57 ++-
 .../thread/step_until/TestStepUntil.py| 38 -
 2 files changed, 65 insertions(+), 30 deletions(-)

diff --git a/lldb/source/Commands/CommandObjectThread.cpp 
b/lldb/source/Commands/CommandObjectThread.cpp
index 4e2c4c1126bc3fe..829abb8c5839bbc 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -959,7 +959,6 @@ class CommandObjectThreadUntil : public CommandObjectParsed 
{
 }
 
 LineEntry function_start;
-uint32_t index_ptr = 0, end_ptr = UINT32_MAX;
 std::vector address_list;
 
 // Find the beginning & end index of the function, but first make
@@ -970,19 +969,22 @@ class CommandObjectThreadUntil : public 
CommandObjectParsed {
   return;
 }
 
-AddressRange fun_addr_range = sc.function->GetAddressRange();
-Address fun_start_addr = fun_addr_range.GetBaseAddress();
-line_table->FindLineEntryByAddress(fun_start_addr, function_start,
-   &index_ptr);
 
-Address fun_end_addr(fun_start_addr.GetSection(),
- fun_start_addr.GetOffset() +
- fun_addr_range.GetByteSize());
+uint32_t lowest_func_idx = UINT32_MAX;
+uint32_t highest_func_idx = 0;
+for (AddressRange range : sc.function->GetAddressRanges()) {
+  uint32_t idx;
+  LineEntry unused;
+  Address addr = range.GetBaseAddress();
+  if (line_table->FindLineEntryByAddress(addr, unused, &idx))
+lowest_func_idx = std::min(lowest_func_idx, idx);
 
-bool all_in_function = true;
+  addr.Slide(range.GetByteSize());
+  if (line_table->FindLineEntryByAddress(addr, unused, &idx))
+highest_func_idx = std::max(highest_func_idx, idx);
+}
 
-line_table->FindLineEntryByAddress(fun_end_addr, function_start,
-   &end_ptr);
+bool found_something = false;
 
 // Since not all source lines will contribute code, check if we are
 // setting the breakpoint on the exact line number or the nearest
@@ -991,14 +993,15 @@ class CommandObjectThreadUntil : public 
CommandObjectParsed {
 for (uint32_t line_number : line_numbers) {
   LineEntry line_entry;
   bool exact = false;
-  uint32_t start_idx_ptr = index_ptr;
-  start_idx_ptr = sc.comp_unit->FindLineEntry(
-  index_ptr, line_number, nullptr, exact, &line_entry);
-  if (start_idx_ptr != UINT32_MAX)
-line_number = line_entry.line;
+  if (sc.comp_unit->FindLineEntry(0, line_number, nullptr, exact,
+  &line_entry) == UINT32_MAX)
+continue;
+
+  found_something = true;
+  line_number = line_entry.line;
   exact = true;
-  start_idx_ptr = index_ptr;
-  while (start_idx_ptr <= end_ptr) {
+  uint32_t start_idx_ptr = lowest_func_idx;
+  while (start_idx_ptr <= highest_func_idx) {
 start_idx_ptr = sc.comp_unit->FindLineEntry(
 start_idx_ptr, line_number, nullptr, exact, &line_entry);
 if (start_idx_ptr == UINT32_MAX)
@@ -1007,29 +1010,29 @@ class CommandObjectThreadUntil : public 
CommandObjectParsed {
 addr_t address =
 line_entry.range.GetBaseAddress().GetLoadAddress(target);
 if (address != LLDB_INVALID_ADDRESS) {
-  if (fun_addr_range.Co

[Lldb-commits] [lldb] [lldb] Implement ${target.file} format variable (PR #123431)

2025-01-20 Thread Jonas Devlieghere via lldb-commits

https://github.com/JDevlieghere updated 
https://github.com/llvm/llvm-project/pull/123431

>From c5474b3a1f0f2ed78f799e8b907ef2f2aa5d97e1 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere 
Date: Fri, 17 Jan 2025 17:18:13 -0800
Subject: [PATCH 1/3] [lldb] Implement ${taret.file} format variable

Implements a format variable to print the basename and full path to the
current target.
---
 lldb/docs/use/formatting.rst |  8 ++--
 lldb/include/lldb/Core/FormatEntity.h|  1 +
 lldb/source/Core/FormatEntity.cpp| 18 +-
 lldb/unittests/Core/FormatEntityTest.cpp |  3 +++
 4 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/lldb/docs/use/formatting.rst b/lldb/docs/use/formatting.rst
index 970bacfd8807a7..3b7819d29d0a27 100644
--- a/lldb/docs/use/formatting.rst
+++ b/lldb/docs/use/formatting.rst
@@ -113,11 +113,11 @@ A complete list of currently supported format string 
variables is listed below:
 
+---+-+
 | ``module.file.basename``  | The basename of the 
current module (shared library or executable)   


|
 
+---+-+
-| ``module.file.fullpath``  | The basename of the 
current module (shared library or executable)   


|
+| ``module.file.fullpath``  | The path of the current 
module (shared library or executable)   


|
 
+---+-+
 | ``process.file.basename`` | The basename of the file 
for the process 


   |
 
+---+-+
-| ``process.file.fullpath`` | The fullname of the file 
for the process 


   |
+| ``process.file.fullpath`` | The path of the file for 
the process 


   |
 
+---+-+
 | ``process.id``| The process ID native to 
the system on which the inferior runs.  


[Lldb-commits] [lldb] [lldb] Implement ${target.file} format variable (PR #123431)

2025-01-20 Thread Jonas Devlieghere via lldb-commits

https://github.com/JDevlieghere updated 
https://github.com/llvm/llvm-project/pull/123431

>From c5474b3a1f0f2ed78f799e8b907ef2f2aa5d97e1 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere 
Date: Fri, 17 Jan 2025 17:18:13 -0800
Subject: [PATCH 1/2] [lldb] Implement ${taret.file} format variable

Implements a format variable to print the basename and full path to the
current target.
---
 lldb/docs/use/formatting.rst |  8 ++--
 lldb/include/lldb/Core/FormatEntity.h|  1 +
 lldb/source/Core/FormatEntity.cpp| 18 +-
 lldb/unittests/Core/FormatEntityTest.cpp |  3 +++
 4 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/lldb/docs/use/formatting.rst b/lldb/docs/use/formatting.rst
index 970bacfd8807a7..3b7819d29d0a27 100644
--- a/lldb/docs/use/formatting.rst
+++ b/lldb/docs/use/formatting.rst
@@ -113,11 +113,11 @@ A complete list of currently supported format string 
variables is listed below:
 
+---+-+
 | ``module.file.basename``  | The basename of the 
current module (shared library or executable)   


|
 
+---+-+
-| ``module.file.fullpath``  | The basename of the 
current module (shared library or executable)   


|
+| ``module.file.fullpath``  | The path of the current 
module (shared library or executable)   


|
 
+---+-+
 | ``process.file.basename`` | The basename of the file 
for the process 


   |
 
+---+-+
-| ``process.file.fullpath`` | The fullname of the file 
for the process 


   |
+| ``process.file.fullpath`` | The path of the file for 
the process 


   |
 
+---+-+
 | ``process.id``| The process ID native to 
the system on which the inferior runs.  


[Lldb-commits] [lldb] [LLDB] Add DIL code for handling plain variable names. (PR #120971)

2025-01-20 Thread via lldb-commits


@@ -0,0 +1,296 @@
+//===-- DILEval.cpp 
---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+#include "lldb/ValueObject/DILEval.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/ValueObject/DILAST.h"
+#include "lldb/ValueObject/ValueObject.h"
+#include "lldb/ValueObject/ValueObjectRegister.h"
+#include "lldb/ValueObject/ValueObjectVariable.h"
+#include "llvm/Support/FormatAdapters.h"
+#include 
+
+namespace lldb_private {
+
+namespace dil {
+
+static lldb::ValueObjectSP
+LookupStaticIdentifier(lldb::TargetSP target_sp,
+   const llvm::StringRef &name_ref,
+   ConstString unqualified_name) {
+  // List global variable with the same "basename". There can be many matches
+  // from other scopes (namespaces, classes), so we do additional filtering
+  // later.
+  VariableList variable_list;
+  ConstString name(name_ref);
+  target_sp->GetImages().FindGlobalVariables(name, 1, variable_list);
+  if (!variable_list.Empty()) {

cmtice wrote:

Ok, I have tried to do this now. :-)

https://github.com/llvm/llvm-project/pull/120971
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Support format string in the prompt (PR #123430)

2025-01-20 Thread Jonas Devlieghere via lldb-commits


@@ -171,7 +171,45 @@ inline std::string FormatAnsiTerminalCodes(llvm::StringRef 
format,
   }
   return fmt;
 }
+
+inline std::string StripAnsiTerminalCodes(llvm::StringRef str) {
+  std::string stripped;
+  while (!str.empty()) {
+llvm::StringRef left, right;
+
+std::tie(left, right) = str.split(ANSI_ESC_START);
+stripped += left;
+
+// ANSI_ESC_START not found.
+if (left == str && right.empty())
+  break;
+
+auto end = llvm::StringRef::npos;
+for (size_t i = 0; i < right.size(); i++) {
+  char c = right[i];
+  if (c == 'm' || c == 'G') {
+end = i;
+break;
+  }
+  if (isdigit(c) || c == ';')
+continue;
+
+  break;
+}
+
+// ANSI_ESC_END not found.
+if (end != llvm::StringRef::npos) {
+  str = right.substr(end + 1);
+  continue;
+}
+
+stripped += ANSI_ESC_START;
+str = right;

JDevlieghere wrote:

My code being called "lumberjacky" is probably the most beautiful insult I've 
ever received 😂

https://github.com/llvm/llvm-project/pull/123430
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Support format string in the prompt (PR #123430)

2025-01-20 Thread Jonas Devlieghere via lldb-commits

https://github.com/JDevlieghere updated 
https://github.com/llvm/llvm-project/pull/123430

>From 10e89226a485d73acfb07ad6d72f3004d270a2f5 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere 
Date: Fri, 17 Jan 2025 16:51:21 -0800
Subject: [PATCH 1/2] [lldb] Support format string in the prompt

Implement ansi::StripAnsiTerminalCodes and fix a long standing bug where
using format strings in lldb's prompt resulted in an incorrect prompt
column width.
---
 lldb/include/lldb/Utility/AnsiTerminal.h| 38 +
 lldb/source/Host/common/Editline.cpp|  4 ++-
 lldb/test/API/terminal/TestEditline.py  | 16 +
 lldb/unittests/Utility/AnsiTerminalTest.cpp | 15 
 4 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/lldb/include/lldb/Utility/AnsiTerminal.h 
b/lldb/include/lldb/Utility/AnsiTerminal.h
index 67795971d2ca89..22601e873dfe9e 100644
--- a/lldb/include/lldb/Utility/AnsiTerminal.h
+++ b/lldb/include/lldb/Utility/AnsiTerminal.h
@@ -171,7 +171,45 @@ inline std::string FormatAnsiTerminalCodes(llvm::StringRef 
format,
   }
   return fmt;
 }
+
+inline std::string StripAnsiTerminalCodes(llvm::StringRef str) {
+  std::string stripped;
+  while (!str.empty()) {
+llvm::StringRef left, right;
+
+std::tie(left, right) = str.split(ANSI_ESC_START);
+stripped += left;
+
+// ANSI_ESC_START not found.
+if (left == str && right.empty())
+  break;
+
+auto end = llvm::StringRef::npos;
+for (size_t i = 0; i < right.size(); i++) {
+  char c = right[i];
+  if (c == 'm' || c == 'G') {
+end = i;
+break;
+  }
+  if (isdigit(c) || c == ';')
+continue;
+
+  break;
+}
+
+// ANSI_ESC_END not found.
+if (end != llvm::StringRef::npos) {
+  str = right.substr(end + 1);
+  continue;
+}
+
+stripped += ANSI_ESC_START;
+str = right;
+  }
+  return stripped;
 }
+
+} // namespace ansi
 } // namespace lldb_private
 
 #endif
diff --git a/lldb/source/Host/common/Editline.cpp 
b/lldb/source/Host/common/Editline.cpp
index 6e35b15d69651d..d31fe3af946b37 100644
--- a/lldb/source/Host/common/Editline.cpp
+++ b/lldb/source/Host/common/Editline.cpp
@@ -14,6 +14,7 @@
 #include "lldb/Host/Editline.h"
 #include "lldb/Host/FileSystem.h"
 #include "lldb/Host/Host.h"
+#include "lldb/Utility/AnsiTerminal.h"
 #include "lldb/Utility/CompletionRequest.h"
 #include "lldb/Utility/FileSpec.h"
 #include "lldb/Utility/LLDBAssert.h"
@@ -85,7 +86,8 @@ bool IsOnlySpaces(const EditLineStringType &content) {
 }
 
 static size_t ColumnWidth(llvm::StringRef str) {
-  return llvm::sys::locale::columnWidth(str);
+  std::string stripped = ansi::StripAnsiTerminalCodes(str);
+  return llvm::sys::locale::columnWidth(stripped);
 }
 
 static int GetOperation(HistoryOperation op) {
diff --git a/lldb/test/API/terminal/TestEditline.py 
b/lldb/test/API/terminal/TestEditline.py
index aa7d827e599441..40f8a50e06bf6d 100644
--- a/lldb/test/API/terminal/TestEditline.py
+++ b/lldb/test/API/terminal/TestEditline.py
@@ -69,6 +69,22 @@ def test_prompt_color(self):
 # Column: 16.8
 self.child.expect(re.escape("\x1b[31m(lldb) \x1b[0m\x1b[8G"))
 
+@skipIfAsan
+@skipIfEditlineSupportMissing
+def test_prompt_format_color(self):
+"""Test that we can change the prompt color with a format string."""
+self.launch(use_colors=True)
+# Clear the prefix and suffix setting to simplify the output.
+self.child.send('settings set prompt-ansi-prefix ""\n')
+self.child.send('settings set prompt-ansi-suffix ""\n')
+self.child.send('settings set prompt 
"${ansi.fg.red}(lldb)${ansi.normal} "\n')
+self.child.send("foo")
+# Make sure this change is reflected immediately. Check that the color
+# is set (31) and the cursor position (8) is correct.
+# Prompt: (lldb) _
+# Column: 16.8
+self.child.expect(re.escape("\x1b[31m(lldb)\x1b[0m foo"))
+
 @skipIfAsan
 @skipIfEditlineSupportMissing
 def test_prompt_no_color(self):
diff --git a/lldb/unittests/Utility/AnsiTerminalTest.cpp 
b/lldb/unittests/Utility/AnsiTerminalTest.cpp
index a6dbfd61061420..1ba9565c3f6af3 100644
--- a/lldb/unittests/Utility/AnsiTerminalTest.cpp
+++ b/lldb/unittests/Utility/AnsiTerminalTest.cpp
@@ -16,16 +16,21 @@ TEST(AnsiTerminal, Empty) { EXPECT_EQ("", 
ansi::FormatAnsiTerminalCodes("")); }
 
 TEST(AnsiTerminal, WhiteSpace) {
   EXPECT_EQ(" ", ansi::FormatAnsiTerminalCodes(" "));
+  EXPECT_EQ(" ", ansi::StripAnsiTerminalCodes(" "));
 }
 
 TEST(AnsiTerminal, AtEnd) {
   EXPECT_EQ("abc\x1B[30m",
 ansi::FormatAnsiTerminalCodes("abc${ansi.fg.black}"));
+
+  EXPECT_EQ("abc", ansi::StripAnsiTerminalCodes("abc\x1B[30m"));
 }
 
 TEST(AnsiTerminal, AtStart) {
   EXPECT_EQ("\x1B[30mabc",
 ansi::FormatAnsiTerminalCodes("${ansi.fg.black}abc"));
+
+  EXPECT_EQ("abc", ansi::StripAnsiTerminalCodes("\x1B[30mabc"));
 }
 
 TEST(AnsiTerminal, KnownPrefix) 

[Lldb-commits] [lldb] [lldb] Implement basic support for reverse-continue (PR #112079)

2025-01-20 Thread Robert O'Callahan via lldb-commits

https://github.com/rocallahan updated 
https://github.com/llvm/llvm-project/pull/112079

>From 4b0279adaa055182d93f6d27d04af23fc03492c9 Mon Sep 17 00:00:00 2001
From: Robert O'Callahan 
Date: Fri, 19 Jul 2024 22:46:42 +1200
Subject: [PATCH 1/3] [lldb] Implement basic support for reverse-continue

This commit only adds support for the
`SBProcess::ContinueInDirection()` API. A user-accessible command
for this will follow in a later commit.

This feature depends on a gdbserver implementation (e.g. `rr`)
providing support for the `bc` and `bs` packets. `lldb-server`
does not support those packets, and there is no plan to change that.
with a Python implementation of *very limited* record-and-replay
functionality.
---
 lldb/include/lldb/API/SBProcess.h |   1 +
 lldb/include/lldb/Target/Process.h|  21 +-
 lldb/include/lldb/Target/StopInfo.h   |   7 +
 lldb/include/lldb/Target/Thread.h |   9 +-
 lldb/include/lldb/Target/ThreadList.h |   6 +-
 lldb/include/lldb/Target/ThreadPlan.h |  13 +
 lldb/include/lldb/Target/ThreadPlanBase.h |   2 +
 lldb/include/lldb/lldb-enumerations.h |   6 +
 .../Python/lldbsuite/test/gdbclientutils.py   |   5 +-
 .../Python/lldbsuite/test/lldbgdbproxy.py | 175 +++
 .../Python/lldbsuite/test/lldbreverse.py  | 492 ++
 .../Python/lldbsuite/test/lldbtest.py |   2 +
 .../tools/lldb-server/lldbgdbserverutils.py   |  14 +-
 lldb/source/API/SBProcess.cpp |   6 +
 lldb/source/API/SBThread.cpp  |   2 +
 .../source/Interpreter/CommandInterpreter.cpp |   3 +-
 .../Process/Linux/NativeThreadLinux.cpp   |   3 +
 .../Process/MacOSX-Kernel/ProcessKDP.cpp  |   8 +-
 .../Process/MacOSX-Kernel/ProcessKDP.h|   2 +-
 .../Process/Windows/Common/ProcessWindows.cpp |   9 +-
 .../Process/Windows/Common/ProcessWindows.h   |   2 +-
 .../GDBRemoteCommunicationClient.cpp  |  20 +
 .../gdb-remote/GDBRemoteCommunicationClient.h |   6 +
 .../GDBRemoteCommunicationServerLLGS.cpp  |   1 +
 .../Process/gdb-remote/ProcessGDBRemote.cpp   |  93 +++-
 .../Process/gdb-remote/ProcessGDBRemote.h |   2 +-
 .../Process/scripted/ScriptedProcess.cpp  |   9 +-
 .../Process/scripted/ScriptedProcess.h|   2 +-
 lldb/source/Target/Process.cpp|  24 +-
 lldb/source/Target/StopInfo.cpp   |  28 +
 lldb/source/Target/Thread.cpp |   9 +-
 lldb/source/Target/ThreadList.cpp |  32 +-
 lldb/source/Target/ThreadPlanBase.cpp |   4 +
 .../reverse-execution/Makefile|   3 +
 .../TestReverseContinueBreakpoints.py | 149 ++
 .../TestReverseContinueNotSupported.py|  30 ++
 .../functionalities/reverse-execution/main.c  |  14 +
 lldb/tools/lldb-dap/JSONUtils.cpp |   3 +
 lldb/tools/lldb-dap/LLDBUtils.cpp |   1 +
 39 files changed, 1171 insertions(+), 47 deletions(-)
 create mode 100644 lldb/packages/Python/lldbsuite/test/lldbgdbproxy.py
 create mode 100644 lldb/packages/Python/lldbsuite/test/lldbreverse.py
 create mode 100644 lldb/test/API/functionalities/reverse-execution/Makefile
 create mode 100644 
lldb/test/API/functionalities/reverse-execution/TestReverseContinueBreakpoints.py
 create mode 100644 
lldb/test/API/functionalities/reverse-execution/TestReverseContinueNotSupported.py
 create mode 100644 lldb/test/API/functionalities/reverse-execution/main.c

diff --git a/lldb/include/lldb/API/SBProcess.h 
b/lldb/include/lldb/API/SBProcess.h
index 1624e02070b1b2..882b8bd837131d 100644
--- a/lldb/include/lldb/API/SBProcess.h
+++ b/lldb/include/lldb/API/SBProcess.h
@@ -159,6 +159,7 @@ class LLDB_API SBProcess {
   lldb::SBError Destroy();
 
   lldb::SBError Continue();
+  lldb::SBError ContinueInDirection(lldb::RunDirection direction);
 
   lldb::SBError Stop();
 
diff --git a/lldb/include/lldb/Target/Process.h 
b/lldb/include/lldb/Target/Process.h
index a184e6dd891aff..3d76413da0fce2 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -1104,9 +1104,13 @@ class Process : public 
std::enable_shared_from_this,
   /// \see Thread:Resume()
   /// \see Thread:Step()
   /// \see Thread:Suspend()
-  virtual Status DoResume() {
+  virtual Status DoResume(lldb::RunDirection direction) {
+if (direction == lldb::RunDirection::eRunForward)
+  return Status::FromErrorStringWithFormatv(
+  "error: {0} does not support resuming processes", GetPluginName());
 return Status::FromErrorStringWithFormatv(
-"error: {0} does not support resuming processes", GetPluginName());
+"error: {0} does not support reverse execution of processes",
+GetPluginName());
   }
 
   /// Called after resuming a process.
@@ -2676,6 +2680,18 @@ void PruneThreadPlans();
 const AddressRange &range, size_t alignment,
 Status &error);
 
+  /// Get the base run direc

[Lldb-commits] [lldb] [lldb] Implement basic support for reverse-continue (PR #112079)

2025-01-20 Thread Robert O'Callahan via lldb-commits


@@ -0,0 +1,32 @@
+import lldb
+import unittest
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test import lldbutil
+
+
+class TestReverseContinueNotSupported(TestBase):
+NO_DEBUG_INFO_TESTCASE = True
+
+def test_reverse_continue_not_supported(self):
+self.build()
+exe = self.getBuildArtifact("a.out")
+target = self.dbg.CreateTarget(exe)
+self.assertTrue(target, VALID_TARGET)
+
+main_bkpt = target.BreakpointCreateByName("main", None)
+self.assertTrue(main_bkpt, VALID_BREAKPOINT)
+
+process = target.LaunchSimple(None, None, 
self.get_process_working_directory())
+self.assertTrue(process, PROCESS_IS_VALID)
+
+# This will fail gracefully.
+status = process.ContinueInDirection(lldb.eRunReverse)
+self.assertFailure(
+status, "error: gdb-remote does not support reverse execution of 
processes"
+)
+
+status = process.ContinueInDirection(lldb.eRunForward)
+self.assertSuccess(status)

rocallahan wrote:

Done.

https://github.com/llvm/llvm-project/pull/112079
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] 06c54bc - [lldb] Implement ${target.file} format variable (#123431)

2025-01-20 Thread via lldb-commits

Author: Jonas Devlieghere
Date: 2025-01-20T15:38:04-08:00
New Revision: 06c54bc1a200fd87bbf4b81db70f52159c79f5bf

URL: 
https://github.com/llvm/llvm-project/commit/06c54bc1a200fd87bbf4b81db70f52159c79f5bf
DIFF: 
https://github.com/llvm/llvm-project/commit/06c54bc1a200fd87bbf4b81db70f52159c79f5bf.diff

LOG: [lldb] Implement ${target.file} format variable (#123431)

Implements a format variable to print the basename and full path to the
current target.

Added: 


Modified: 
lldb/docs/use/formatting.rst
lldb/include/lldb/Core/FormatEntity.h
lldb/source/Core/FormatEntity.cpp
lldb/unittests/Core/FormatEntityTest.cpp

Removed: 




diff  --git a/lldb/docs/use/formatting.rst b/lldb/docs/use/formatting.rst
index 970bacfd8807a7..7b3f01eebc8917 100644
--- a/lldb/docs/use/formatting.rst
+++ b/lldb/docs/use/formatting.rst
@@ -113,11 +113,11 @@ A complete list of currently supported format string 
variables is listed below:
 
+---+-+
 | ``module.file.basename``  | The basename of the 
current module (shared library or executable)   


|
 
+---+-+
-| ``module.file.fullpath``  | The basename of the 
current module (shared library or executable)   


|
+| ``module.file.fullpath``  | The path of the current 
module (shared library or executable)   


|
 
+---+-+
 | ``process.file.basename`` | The basename of the file 
for the process 


   |
 
+---+-+
-| ``process.file.fullpath`` | The fullname of the file 
for the process 


   |
+| ``process.file.fullpath`` | The path of the file for 
the process 


   |
 
+---+-+
 | ``process.id``| The process ID native to 
the system on which the inferior runs.  
   

[Lldb-commits] [lldb] [lldb] Implement ${target.file} format variable (PR #123431)

2025-01-20 Thread Jonas Devlieghere via lldb-commits

https://github.com/JDevlieghere closed 
https://github.com/llvm/llvm-project/pull/123431
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Implement basic support for reverse-continue (PR #112079)

2025-01-20 Thread Robert O'Callahan via lldb-commits


@@ -0,0 +1,149 @@
+import lldb
+import time
+import unittest
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test.gdbclientutils import *
+from lldbsuite.test.lldbreverse import ReverseTestBase
+from lldbsuite.test import lldbutil
+
+
+class TestReverseContinueBreakpoints(ReverseTestBase):
+def test_reverse_continue(self):
+self.reverse_continue_internal(async_mode=False)
+
+def test_reverse_continue_async(self):
+self.reverse_continue_internal(async_mode=True)
+
+def reverse_continue_internal(self, async_mode):
+target, process, initial_threads = self.setup_recording(async_mode)
+
+# Reverse-continue. We'll stop at the point where we started recording.
+status = process.ContinueInDirection(lldb.eRunReverse)
+self.assertSuccess(status)
+self.expect_async_state_changes(
+async_mode, process, [lldb.eStateRunning, lldb.eStateStopped]
+)
+self.expect(
+"thread list",
+STOPPED_DUE_TO_HISTORY_BOUNDARY,
+substrs=["stopped", "stop reason = history boundary"],
+)

rocallahan wrote:

Yes, good point. The PC should point to the instruction that modifies the 
watched variable. We can't test that directly since it's hard to figure out 
where that instruction is, but we can singlestep one instruction forward and 
verify that the variable value changes. So I've added that.

https://github.com/llvm/llvm-project/pull/112079
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][Linux] Add Control Protection Fault signal (PR #122917)

2025-01-20 Thread Omair Javaid via lldb-commits

https://github.com/omjavaid approved this pull request.


https://github.com/llvm/llvm-project/pull/122917
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Fix "in function" detection in "thread until" (PR #123622)

2025-01-20 Thread via lldb-commits

llvmbot wrote:




@llvm/pr-subscribers-lldb

Author: Pavel Labath (labath)


Changes

The implementation has an optimization which detects the range of line table 
entries covered by the function and then only searches for a matching line 
between them.

This optimization was interfering with the logic for detecting whether a line 
belongs to the function because the first call to FindLineEntry was made with 
exact=false, which meant that if the function did not contain any exact 
matches, we would just pick the closest line number in that range, even if it 
was very far away.

This patch fixes that by first attempting an inexact search across the entire 
line table, and then use the (potentially inexact) result of that for searching 
within the function. This makes the optimization a less effective, but I don't 
think we can differentiate between a line that belongs to the function (but 
doesn't have any code) and a line outside the function without that.

The patch also avoids the use of (deprecated) Function::GetAddressRange by 
iterating over the GetAddressRanges result to find the full range of line 
entries for the function.

---
Full diff: https://github.com/llvm/llvm-project/pull/123622.diff


2 Files Affected:

- (modified) lldb/source/Commands/CommandObjectThread.cpp (+30-27) 
- (modified) lldb/test/API/functionalities/thread/step_until/TestStepUntil.py 
(+35-3) 


``diff
diff --git a/lldb/source/Commands/CommandObjectThread.cpp 
b/lldb/source/Commands/CommandObjectThread.cpp
index 4e2c4c1126bc3f..829abb8c5839bb 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -959,7 +959,6 @@ class CommandObjectThreadUntil : public CommandObjectParsed 
{
 }
 
 LineEntry function_start;
-uint32_t index_ptr = 0, end_ptr = UINT32_MAX;
 std::vector address_list;
 
 // Find the beginning & end index of the function, but first make
@@ -970,19 +969,22 @@ class CommandObjectThreadUntil : public 
CommandObjectParsed {
   return;
 }
 
-AddressRange fun_addr_range = sc.function->GetAddressRange();
-Address fun_start_addr = fun_addr_range.GetBaseAddress();
-line_table->FindLineEntryByAddress(fun_start_addr, function_start,
-   &index_ptr);
 
-Address fun_end_addr(fun_start_addr.GetSection(),
- fun_start_addr.GetOffset() +
- fun_addr_range.GetByteSize());
+uint32_t lowest_func_idx = UINT32_MAX;
+uint32_t highest_func_idx = 0;
+for (AddressRange range : sc.function->GetAddressRanges()) {
+  uint32_t idx;
+  LineEntry unused;
+  Address addr = range.GetBaseAddress();
+  if (line_table->FindLineEntryByAddress(addr, unused, &idx))
+lowest_func_idx = std::min(lowest_func_idx, idx);
 
-bool all_in_function = true;
+  addr.Slide(range.GetByteSize());
+  if (line_table->FindLineEntryByAddress(addr, unused, &idx))
+highest_func_idx = std::max(highest_func_idx, idx);
+}
 
-line_table->FindLineEntryByAddress(fun_end_addr, function_start,
-   &end_ptr);
+bool found_something = false;
 
 // Since not all source lines will contribute code, check if we are
 // setting the breakpoint on the exact line number or the nearest
@@ -991,14 +993,15 @@ class CommandObjectThreadUntil : public 
CommandObjectParsed {
 for (uint32_t line_number : line_numbers) {
   LineEntry line_entry;
   bool exact = false;
-  uint32_t start_idx_ptr = index_ptr;
-  start_idx_ptr = sc.comp_unit->FindLineEntry(
-  index_ptr, line_number, nullptr, exact, &line_entry);
-  if (start_idx_ptr != UINT32_MAX)
-line_number = line_entry.line;
+  if (sc.comp_unit->FindLineEntry(0, line_number, nullptr, exact,
+  &line_entry) == UINT32_MAX)
+continue;
+
+  found_something = true;
+  line_number = line_entry.line;
   exact = true;
-  start_idx_ptr = index_ptr;
-  while (start_idx_ptr <= end_ptr) {
+  uint32_t start_idx_ptr = lowest_func_idx;
+  while (start_idx_ptr <= highest_func_idx) {
 start_idx_ptr = sc.comp_unit->FindLineEntry(
 start_idx_ptr, line_number, nullptr, exact, &line_entry);
 if (start_idx_ptr == UINT32_MAX)
@@ -1007,29 +1010,29 @@ class CommandObjectThreadUntil : public 
CommandObjectParsed {
 addr_t address =
 line_entry.range.GetBaseAddress().GetLoadAddress(target);
 if (address != LLDB_INVALID_ADDRESS) {
-  if (fun_addr_range.ContainsLoadAddress(address, target))
+  AddressRange unused;
+  if (sc.function->GetRangeContainingLo

[Lldb-commits] [lldb] [lldb] Fix "in function" detection in "thread until" (PR #123622)

2025-01-20 Thread Pavel Labath via lldb-commits

https://github.com/labath created 
https://github.com/llvm/llvm-project/pull/123622

The implementation has an optimization which detects the range of line table 
entries covered by the function and then only searches for a matching line 
between them.

This optimization was interfering with the logic for detecting whether a line 
belongs to the function because the first call to FindLineEntry was made with 
exact=false, which meant that if the function did not contain any exact 
matches, we would just pick the closest line number in that range, even if it 
was very far away.

This patch fixes that by first attempting an inexact search across the entire 
line table, and then use the (potentially inexact) result of that for searching 
within the function. This makes the optimization a less effective, but I don't 
think we can differentiate between a line that belongs to the function (but 
doesn't have any code) and a line outside the function without that.

The patch also avoids the use of (deprecated) Function::GetAddressRange by 
iterating over the GetAddressRanges result to find the full range of line 
entries for the function.

>From 0a80b7a54b49de65758ab48acdb6d92f9b674d71 Mon Sep 17 00:00:00 2001
From: Pavel Labath 
Date: Mon, 20 Jan 2025 15:03:14 +0100
Subject: [PATCH] [lldb] Fix "in function" detection in "thread until"

The implementation has an optimization which detects the range of line
table entries covered by the function and then only searches for a
matching line between them.

This optimization was interfering with the logic for detecting whether a
line belongs to the function because the first call to FindLineEntry was
made with exact=false, which meant that if the function did not contain
any exact matches, we would just pick the closest line number in that
range, even if it was very far away.

This patch fixes that by first attempting an inexact search across the
entire line table, and then use the (potentially inexact) result of that
for searching within the function. This makes the optimization a less
effective, but I don't think we can differentiate between a line that
belongs to the function (but doesn't have any code) and a line outside
the function without that.

The patch also avoids the use of (deprecated) Function::GetAddressRange
by iterating over the GetAddressRanges result to find the full range of
line entries for the function.
---
 lldb/source/Commands/CommandObjectThread.cpp  | 57 ++-
 .../thread/step_until/TestStepUntil.py| 38 -
 2 files changed, 65 insertions(+), 30 deletions(-)

diff --git a/lldb/source/Commands/CommandObjectThread.cpp 
b/lldb/source/Commands/CommandObjectThread.cpp
index 4e2c4c1126bc3f..829abb8c5839bb 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -959,7 +959,6 @@ class CommandObjectThreadUntil : public CommandObjectParsed 
{
 }
 
 LineEntry function_start;
-uint32_t index_ptr = 0, end_ptr = UINT32_MAX;
 std::vector address_list;
 
 // Find the beginning & end index of the function, but first make
@@ -970,19 +969,22 @@ class CommandObjectThreadUntil : public 
CommandObjectParsed {
   return;
 }
 
-AddressRange fun_addr_range = sc.function->GetAddressRange();
-Address fun_start_addr = fun_addr_range.GetBaseAddress();
-line_table->FindLineEntryByAddress(fun_start_addr, function_start,
-   &index_ptr);
 
-Address fun_end_addr(fun_start_addr.GetSection(),
- fun_start_addr.GetOffset() +
- fun_addr_range.GetByteSize());
+uint32_t lowest_func_idx = UINT32_MAX;
+uint32_t highest_func_idx = 0;
+for (AddressRange range : sc.function->GetAddressRanges()) {
+  uint32_t idx;
+  LineEntry unused;
+  Address addr = range.GetBaseAddress();
+  if (line_table->FindLineEntryByAddress(addr, unused, &idx))
+lowest_func_idx = std::min(lowest_func_idx, idx);
 
-bool all_in_function = true;
+  addr.Slide(range.GetByteSize());
+  if (line_table->FindLineEntryByAddress(addr, unused, &idx))
+highest_func_idx = std::max(highest_func_idx, idx);
+}
 
-line_table->FindLineEntryByAddress(fun_end_addr, function_start,
-   &end_ptr);
+bool found_something = false;
 
 // Since not all source lines will contribute code, check if we are
 // setting the breakpoint on the exact line number or the nearest
@@ -991,14 +993,15 @@ class CommandObjectThreadUntil : public 
CommandObjectParsed {
 for (uint32_t line_number : line_numbers) {
   LineEntry line_entry;
   bool exact = false;
-  uint32_t start_idx_ptr = index_ptr;
-  start_idx_ptr = sc.comp_unit->FindLineEntry(
-  index_pt

[Lldb-commits] [lldb] [lldb] Fix "in function" detection in "thread until" (PR #123622)

2025-01-20 Thread via lldb-commits

github-actions[bot] wrote:




:warning: Python code formatter, darker found issues in your code. :warning:



You can test this locally with the following command:


``bash
darker --check --diff -r 
71d6287f5b1e65466de5fe5c093852fa7903cdbe...0a80b7a54b49de65758ab48acdb6d92f9b674d71
 lldb/test/API/functionalities/thread/step_until/TestStepUntil.py
``





View the diff from darker here.


``diff
--- TestStepUntil.py2025-01-20 14:03:14.00 +
+++ TestStepUntil.py2025-01-20 14:35:26.001442 +
@@ -101,13 +101,15 @@
 @no_debug_info_test
 def test_bad_line(self):
 """Test that we get an error if attempting to step outside the current
 function"""
 thread = self._common_setup(None, None)
-self.expect(f"thread until {self.in_foo}",
-substrs=["Until target outside of the current function"],
- error=True)
+self.expect(
+f"thread until {self.in_foo}",
+substrs=["Until target outside of the current function"],
+error=True,
+)
 
 @no_debug_info_test
 @skipIf(oslist=lldbplatformutil.getDarwinOSTriples() + ["windows"])
 @skipIf(archs=no_match(["x86_64", "aarch64"]))
 def test_bad_line_discontinuous(self):
@@ -115,8 +117,10 @@
 function -- and the function is discontinuous"""
 self.build(dictionary=self._build_dict_for_discontinuity())
 _, _, thread, _ = lldbutil.run_to_source_breakpoint(
 self, "At the start", lldb.SBFileSpec(self.main_source)
 )
-self.expect(f"thread until {self.in_foo}",
-substrs=["Until target outside of the current function"],
- error=True)
+self.expect(
+f"thread until {self.in_foo}",
+substrs=["Until target outside of the current function"],
+error=True,
+)

``




https://github.com/llvm/llvm-project/pull/123622
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Fix "in function" detection in "thread until" (PR #123622)

2025-01-20 Thread via lldb-commits

github-actions[bot] wrote:




:warning: C/C++ code formatter, clang-format found issues in your code. 
:warning:



You can test this locally with the following command:


``bash
git-clang-format --diff 71d6287f5b1e65466de5fe5c093852fa7903cdbe 
0a80b7a54b49de65758ab48acdb6d92f9b674d71 --extensions cpp -- 
lldb/source/Commands/CommandObjectThread.cpp
``





View the diff from clang-format here.


``diff
diff --git a/lldb/source/Commands/CommandObjectThread.cpp 
b/lldb/source/Commands/CommandObjectThread.cpp
index 829abb8c58..e472359a31 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -969,7 +969,6 @@ protected:
   return;
 }
 
-
 uint32_t lowest_func_idx = UINT32_MAX;
 uint32_t highest_func_idx = 0;
 for (AddressRange range : sc.function->GetAddressRanges()) {

``




https://github.com/llvm/llvm-project/pull/123622
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits