[Lldb-commits] [PATCH] D115104: [lldb] Fix guessing of windows path style

2021-12-04 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin created this revision.
jarin added a reviewer: labath.
jarin requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

Currently, only paths with length>3 are guessed as Windows paths. This prevents 
root paths (such as C:\) to be recognized as Windows paths. This patch makes 
sure we also recognize ":\" as Windows paths.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D115104

Files:
  lldb/source/Utility/FileSpec.cpp
  lldb/unittests/Utility/FileSpecTest.cpp


Index: lldb/unittests/Utility/FileSpecTest.cpp
===
--- lldb/unittests/Utility/FileSpecTest.cpp
+++ lldb/unittests/Utility/FileSpecTest.cpp
@@ -198,8 +198,10 @@
 FileSpec::GuessPathStyle(R"(C:\foo.txt)"));
   EXPECT_EQ(FileSpec::Style::windows,
 FileSpec::GuessPathStyle(R"(\\net\foo.txt)"));
+  EXPECT_EQ(FileSpec::Style::windows, FileSpec::GuessPathStyle(R"(Z:\)"));
   EXPECT_EQ(llvm::None, FileSpec::GuessPathStyle("foo.txt"));
   EXPECT_EQ(llvm::None, FileSpec::GuessPathStyle("foo/bar.txt"));
+  EXPECT_EQ(llvm::None, FileSpec::GuessPathStyle("Z:"));
 }
 
 TEST(FileSpecTest, GetPath) {
Index: lldb/source/Utility/FileSpec.cpp
===
--- lldb/source/Utility/FileSpec.cpp
+++ lldb/source/Utility/FileSpec.cpp
@@ -310,7 +310,7 @@
 return Style::posix;
   if (absolute_path.startswith(R"(\\)"))
 return Style::windows;
-  if (absolute_path.size() > 3 && llvm::isAlpha(absolute_path[0]) &&
+  if (absolute_path.size() >= 3 && llvm::isAlpha(absolute_path[0]) &&
   absolute_path.substr(1, 2) == R"(:\)")
 return Style::windows;
   return llvm::None;


Index: lldb/unittests/Utility/FileSpecTest.cpp
===
--- lldb/unittests/Utility/FileSpecTest.cpp
+++ lldb/unittests/Utility/FileSpecTest.cpp
@@ -198,8 +198,10 @@
 FileSpec::GuessPathStyle(R"(C:\foo.txt)"));
   EXPECT_EQ(FileSpec::Style::windows,
 FileSpec::GuessPathStyle(R"(\\net\foo.txt)"));
+  EXPECT_EQ(FileSpec::Style::windows, FileSpec::GuessPathStyle(R"(Z:\)"));
   EXPECT_EQ(llvm::None, FileSpec::GuessPathStyle("foo.txt"));
   EXPECT_EQ(llvm::None, FileSpec::GuessPathStyle("foo/bar.txt"));
+  EXPECT_EQ(llvm::None, FileSpec::GuessPathStyle("Z:"));
 }
 
 TEST(FileSpecTest, GetPath) {
Index: lldb/source/Utility/FileSpec.cpp
===
--- lldb/source/Utility/FileSpec.cpp
+++ lldb/source/Utility/FileSpec.cpp
@@ -310,7 +310,7 @@
 return Style::posix;
   if (absolute_path.startswith(R"(\\)"))
 return Style::windows;
-  if (absolute_path.size() > 3 && llvm::isAlpha(absolute_path[0]) &&
+  if (absolute_path.size() >= 3 && llvm::isAlpha(absolute_path[0]) &&
   absolute_path.substr(1, 2) == R"(:\)")
 return Style::windows;
   return llvm::None;
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D115104: [lldb] Fix guessing of windows path style

2021-12-07 Thread Jaroslav Sevcik via Phabricator via lldb-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGf72ae5cba1d6: [lldb] Fix windows path guessing for root 
paths (authored by jarin).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115104/new/

https://reviews.llvm.org/D115104

Files:
  lldb/source/Utility/FileSpec.cpp
  lldb/unittests/Utility/FileSpecTest.cpp


Index: lldb/unittests/Utility/FileSpecTest.cpp
===
--- lldb/unittests/Utility/FileSpecTest.cpp
+++ lldb/unittests/Utility/FileSpecTest.cpp
@@ -198,8 +198,10 @@
 FileSpec::GuessPathStyle(R"(C:\foo.txt)"));
   EXPECT_EQ(FileSpec::Style::windows,
 FileSpec::GuessPathStyle(R"(\\net\foo.txt)"));
+  EXPECT_EQ(FileSpec::Style::windows, FileSpec::GuessPathStyle(R"(Z:\)"));
   EXPECT_EQ(llvm::None, FileSpec::GuessPathStyle("foo.txt"));
   EXPECT_EQ(llvm::None, FileSpec::GuessPathStyle("foo/bar.txt"));
+  EXPECT_EQ(llvm::None, FileSpec::GuessPathStyle("Z:"));
 }
 
 TEST(FileSpecTest, GetPath) {
Index: lldb/source/Utility/FileSpec.cpp
===
--- lldb/source/Utility/FileSpec.cpp
+++ lldb/source/Utility/FileSpec.cpp
@@ -310,7 +310,7 @@
 return Style::posix;
   if (absolute_path.startswith(R"(\\)"))
 return Style::windows;
-  if (absolute_path.size() > 3 && llvm::isAlpha(absolute_path[0]) &&
+  if (absolute_path.size() >= 3 && llvm::isAlpha(absolute_path[0]) &&
   absolute_path.substr(1, 2) == R"(:\)")
 return Style::windows;
   return llvm::None;


Index: lldb/unittests/Utility/FileSpecTest.cpp
===
--- lldb/unittests/Utility/FileSpecTest.cpp
+++ lldb/unittests/Utility/FileSpecTest.cpp
@@ -198,8 +198,10 @@
 FileSpec::GuessPathStyle(R"(C:\foo.txt)"));
   EXPECT_EQ(FileSpec::Style::windows,
 FileSpec::GuessPathStyle(R"(\\net\foo.txt)"));
+  EXPECT_EQ(FileSpec::Style::windows, FileSpec::GuessPathStyle(R"(Z:\)"));
   EXPECT_EQ(llvm::None, FileSpec::GuessPathStyle("foo.txt"));
   EXPECT_EQ(llvm::None, FileSpec::GuessPathStyle("foo/bar.txt"));
+  EXPECT_EQ(llvm::None, FileSpec::GuessPathStyle("Z:"));
 }
 
 TEST(FileSpecTest, GetPath) {
Index: lldb/source/Utility/FileSpec.cpp
===
--- lldb/source/Utility/FileSpec.cpp
+++ lldb/source/Utility/FileSpec.cpp
@@ -310,7 +310,7 @@
 return Style::posix;
   if (absolute_path.startswith(R"(\\)"))
 return Style::windows;
-  if (absolute_path.size() > 3 && llvm::isAlpha(absolute_path[0]) &&
+  if (absolute_path.size() >= 3 && llvm::isAlpha(absolute_path[0]) &&
   absolute_path.substr(1, 2) == R"(:\)")
 return Style::windows;
   return llvm::None;
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D153043: [lldb] Fix handling of cfi_restore in the unwinder

2023-06-15 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin created this revision.
jarin added a reviewer: labath.
jarin added a project: LLDB.
Herald added a subscriber: JDevlieghere.
Herald added a project: All.
jarin requested review of this revision.
Herald added a subscriber: lldb-commits.

Currently, lldb's unwinder ignores cfi_restore opcodes for registers
that are not set in the first row of the unwinding info. This prevents
unwinding of failed assertion in Chrome/v8 (https://github.com/v8/v8).
The attached test is an x64 copy of v8's function that failed to unwind
correctly.

This patch changes handling of cfi_restore to reset the location if
the first unwind table row does not map the restored register.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D153043

Files:
  lldb/source/Symbol/DWARFCallFrameInfo.cpp
  lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s
  lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test


Index: lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test
===
--- /dev/null
+++ lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test
@@ -0,0 +1,21 @@
+# Test restoring of register values.
+
+# UNSUPPORTED: system-windows
+# REQUIRES: target-x86_64, native
+
+# RUN: %clang_host %p/Inputs/call-asm.c 
%p/Inputs/eh-frame-dwarf-unwind-abort.s -o %t
+# RUN: %lldb %t -s %s -o exit | FileCheck %s
+
+process launch
+# CHECK: stop reason = signal SIGTRAP
+
+thread backtrace
+# CHECK: frame #0: {{.*}}`asm_main + 23
+# CHECK: frame #1: {{.*}}`main + {{.*}}
+
+target modules show-unwind -n asm_main
+# CHECK: eh_frame UnwindPlan:
+# CHECK: row[0]:0: CFA=rsp +8 => rip=[CFA-8]
+# CHECK: row[1]:   14: CFA=rsp+16 => rbp=[CFA-16] rip=[CFA-8]
+# CHECK: row[2]:   17: CFA=rbp+16 => rbp=[CFA-16] rip=[CFA-8]
+# CHECK: row[3]:   22: CFA=rsp +8 => rip=[CFA-8]
Index: lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s
===
--- /dev/null
+++ lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s
@@ -0,0 +1,25 @@
+.text
+.globl  asm_main
+asm_main:
+.cfi_startproc
+cmpb $0x0, g_hard_abort(%rip)
+jne .L
+
+pushq   %rbp
+.cfi_def_cfa_offset 16
+.cfi_offset 6, -16
+movq%rsp, %rbp
+.cfi_def_cfa_register 6
+callq   abort
+.L:
+.cfi_def_cfa 7, 8
+.cfi_restore 6
+int3
+ud2
+.cfi_endproc
+
+   .data
+   .globl  g_hard_abort
+g_hard_abort:
+   .byte   1
+   .size   g_hard_abort, 1
\ No newline at end of file
Index: lldb/source/Symbol/DWARFCallFrameInfo.cpp
===
--- lldb/source/Symbol/DWARFCallFrameInfo.cpp
+++ lldb/source/Symbol/DWARFCallFrameInfo.cpp
@@ -674,6 +674,8 @@
   unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num,
 reg_location))
 row->SetRegisterInfo(reg_num, reg_location);
+  else
+row->RemoveRegisterInfo(reg_num);
   break;
 }
 }


Index: lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test
===
--- /dev/null
+++ lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test
@@ -0,0 +1,21 @@
+# Test restoring of register values.
+
+# UNSUPPORTED: system-windows
+# REQUIRES: target-x86_64, native
+
+# RUN: %clang_host %p/Inputs/call-asm.c %p/Inputs/eh-frame-dwarf-unwind-abort.s -o %t
+# RUN: %lldb %t -s %s -o exit | FileCheck %s
+
+process launch
+# CHECK: stop reason = signal SIGTRAP
+
+thread backtrace
+# CHECK: frame #0: {{.*}}`asm_main + 23
+# CHECK: frame #1: {{.*}}`main + {{.*}}
+
+target modules show-unwind -n asm_main
+# CHECK: eh_frame UnwindPlan:
+# CHECK: row[0]:0: CFA=rsp +8 => rip=[CFA-8]
+# CHECK: row[1]:   14: CFA=rsp+16 => rbp=[CFA-16] rip=[CFA-8]
+# CHECK: row[2]:   17: CFA=rbp+16 => rbp=[CFA-16] rip=[CFA-8]
+# CHECK: row[3]:   22: CFA=rsp +8 => rip=[CFA-8]
Index: lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s
===
--- /dev/null
+++ lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s
@@ -0,0 +1,25 @@
+.text
+.globl  asm_main
+asm_main:
+.cfi_startproc
+cmpb $0x0, g_hard_abort(%rip)
+jne .L
+
+pushq   %rbp
+.cfi_def_cfa_offset 16
+.cfi_offset 6, -16
+movq%rsp, %rbp
+.cfi_def_cfa_register 6
+callq   abort
+.L:
+.cfi_def_cfa 7, 8
+.cfi_restore 6
+int3
+ud2
+.cfi_endproc
+
+	.data
+	.globl  g_hard_abort
+g_hard_abort:
+	.byte   1
+	.size   g_hard_abort, 1
\ No newline at end of file
Index: lldb/source/Symbol/DWARFCallFrameInfo.cpp
===
--- lldb/source/Symbol/DWARFCallFrameInfo.cpp
+++ lldb/source/Sy

[Lldb-commits] [PATCH] D153043: [lldb] Fix handling of cfi_restore in the unwinder

2023-06-15 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 531987.
jarin added a comment.

Added a comment explaining that we are restoring the caller's value of the 
register.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153043/new/

https://reviews.llvm.org/D153043

Files:
  lldb/source/Symbol/DWARFCallFrameInfo.cpp
  lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s
  lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test


Index: lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test
===
--- /dev/null
+++ lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test
@@ -0,0 +1,21 @@
+# Test restoring of register values.
+
+# UNSUPPORTED: system-windows
+# REQUIRES: target-x86_64, native
+
+# RUN: %clang_host %p/Inputs/call-asm.c 
%p/Inputs/eh-frame-dwarf-unwind-abort.s -o %t
+# RUN: %lldb %t -s %s -o exit | FileCheck %s
+
+process launch
+# CHECK: stop reason = signal SIGTRAP
+
+thread backtrace
+# CHECK: frame #0: {{.*}}`asm_main + 23
+# CHECK: frame #1: {{.*}}`main + {{.*}}
+
+target modules show-unwind -n asm_main
+# CHECK: eh_frame UnwindPlan:
+# CHECK: row[0]:0: CFA=rsp +8 => rip=[CFA-8]
+# CHECK: row[1]:   14: CFA=rsp+16 => rbp=[CFA-16] rip=[CFA-8]
+# CHECK: row[2]:   17: CFA=rbp+16 => rbp=[CFA-16] rip=[CFA-8]
+# CHECK: row[3]:   22: CFA=rsp +8 => rip=[CFA-8]
Index: lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s
===
--- /dev/null
+++ lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s
@@ -0,0 +1,25 @@
+.text
+.globl  asm_main
+asm_main:
+.cfi_startproc
+cmpb $0x0, g_hard_abort(%rip)
+jne .L
+
+pushq   %rbp
+.cfi_def_cfa_offset 16
+.cfi_offset 6, -16
+movq%rsp, %rbp
+.cfi_def_cfa_register 6
+callq   abort
+.L:
+.cfi_def_cfa 7, 8
+.cfi_restore 6
+int3
+ud2
+.cfi_endproc
+
+   .data
+   .globl  g_hard_abort
+g_hard_abort:
+   .byte   1
+   .size   g_hard_abort, 1
\ No newline at end of file
Index: lldb/source/Symbol/DWARFCallFrameInfo.cpp
===
--- lldb/source/Symbol/DWARFCallFrameInfo.cpp
+++ lldb/source/Symbol/DWARFCallFrameInfo.cpp
@@ -674,6 +674,11 @@
   unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num,
 reg_location))
 row->SetRegisterInfo(reg_num, reg_location);
+  else {
+// If the register was not set in the first row, remove the
+// register info to keep the unmodified value from the caller.
+row->RemoveRegisterInfo(reg_num);
+  }
   break;
 }
 }


Index: lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test
===
--- /dev/null
+++ lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test
@@ -0,0 +1,21 @@
+# Test restoring of register values.
+
+# UNSUPPORTED: system-windows
+# REQUIRES: target-x86_64, native
+
+# RUN: %clang_host %p/Inputs/call-asm.c %p/Inputs/eh-frame-dwarf-unwind-abort.s -o %t
+# RUN: %lldb %t -s %s -o exit | FileCheck %s
+
+process launch
+# CHECK: stop reason = signal SIGTRAP
+
+thread backtrace
+# CHECK: frame #0: {{.*}}`asm_main + 23
+# CHECK: frame #1: {{.*}}`main + {{.*}}
+
+target modules show-unwind -n asm_main
+# CHECK: eh_frame UnwindPlan:
+# CHECK: row[0]:0: CFA=rsp +8 => rip=[CFA-8]
+# CHECK: row[1]:   14: CFA=rsp+16 => rbp=[CFA-16] rip=[CFA-8]
+# CHECK: row[2]:   17: CFA=rbp+16 => rbp=[CFA-16] rip=[CFA-8]
+# CHECK: row[3]:   22: CFA=rsp +8 => rip=[CFA-8]
Index: lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s
===
--- /dev/null
+++ lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s
@@ -0,0 +1,25 @@
+.text
+.globl  asm_main
+asm_main:
+.cfi_startproc
+cmpb $0x0, g_hard_abort(%rip)
+jne .L
+
+pushq   %rbp
+.cfi_def_cfa_offset 16
+.cfi_offset 6, -16
+movq%rsp, %rbp
+.cfi_def_cfa_register 6
+callq   abort
+.L:
+.cfi_def_cfa 7, 8
+.cfi_restore 6
+int3
+ud2
+.cfi_endproc
+
+	.data
+	.globl  g_hard_abort
+g_hard_abort:
+	.byte   1
+	.size   g_hard_abort, 1
\ No newline at end of file
Index: lldb/source/Symbol/DWARFCallFrameInfo.cpp
===
--- lldb/source/Symbol/DWARFCallFrameInfo.cpp
+++ lldb/source/Symbol/DWARFCallFrameInfo.cpp
@@ -674,6 +674,11 @@
   unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num,
 reg_location))
 row->SetRegisterInfo(reg_num, reg_location);
+  else {
+// If the register was not set in the 

[Lldb-commits] [PATCH] D153043: [lldb] Fix handling of cfi_restore in the unwinder

2023-06-15 Thread Jaroslav Sevcik via Phabricator via lldb-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG07b9e6ed0db2: [lldb] Fix handling of cfi_restore in the 
unwinder (authored by jarin).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153043/new/

https://reviews.llvm.org/D153043

Files:
  lldb/source/Symbol/DWARFCallFrameInfo.cpp
  lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s
  lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test


Index: lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test
===
--- /dev/null
+++ lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test
@@ -0,0 +1,21 @@
+# Test restoring of register values.
+
+# UNSUPPORTED: system-windows
+# REQUIRES: target-x86_64, native
+
+# RUN: %clang_host %p/Inputs/call-asm.c 
%p/Inputs/eh-frame-dwarf-unwind-abort.s -o %t
+# RUN: %lldb %t -s %s -o exit | FileCheck %s
+
+process launch
+# CHECK: stop reason = signal SIGTRAP
+
+thread backtrace
+# CHECK: frame #0: {{.*}}`asm_main + 23
+# CHECK: frame #1: {{.*}}`main + {{.*}}
+
+target modules show-unwind -n asm_main
+# CHECK: eh_frame UnwindPlan:
+# CHECK: row[0]:0: CFA=rsp +8 => rip=[CFA-8]
+# CHECK: row[1]:   14: CFA=rsp+16 => rbp=[CFA-16] rip=[CFA-8]
+# CHECK: row[2]:   17: CFA=rbp+16 => rbp=[CFA-16] rip=[CFA-8]
+# CHECK: row[3]:   22: CFA=rsp +8 => rip=[CFA-8]
Index: lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s
===
--- /dev/null
+++ lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s
@@ -0,0 +1,25 @@
+.text
+.globl  asm_main
+asm_main:
+.cfi_startproc
+cmpb $0x0, g_hard_abort(%rip)
+jne .L
+
+pushq   %rbp
+.cfi_def_cfa_offset 16
+.cfi_offset 6, -16
+movq%rsp, %rbp
+.cfi_def_cfa_register 6
+callq   abort
+.L:
+.cfi_def_cfa 7, 8
+.cfi_restore 6
+int3
+ud2
+.cfi_endproc
+
+   .data
+   .globl  g_hard_abort
+g_hard_abort:
+   .byte   1
+   .size   g_hard_abort, 1
\ No newline at end of file
Index: lldb/source/Symbol/DWARFCallFrameInfo.cpp
===
--- lldb/source/Symbol/DWARFCallFrameInfo.cpp
+++ lldb/source/Symbol/DWARFCallFrameInfo.cpp
@@ -674,6 +674,11 @@
   unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num,
 reg_location))
 row->SetRegisterInfo(reg_num, reg_location);
+  else {
+// If the register was not set in the first row, remove the
+// register info to keep the unmodified value from the caller.
+row->RemoveRegisterInfo(reg_num);
+  }
   break;
 }
 }


Index: lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test
===
--- /dev/null
+++ lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test
@@ -0,0 +1,21 @@
+# Test restoring of register values.
+
+# UNSUPPORTED: system-windows
+# REQUIRES: target-x86_64, native
+
+# RUN: %clang_host %p/Inputs/call-asm.c %p/Inputs/eh-frame-dwarf-unwind-abort.s -o %t
+# RUN: %lldb %t -s %s -o exit | FileCheck %s
+
+process launch
+# CHECK: stop reason = signal SIGTRAP
+
+thread backtrace
+# CHECK: frame #0: {{.*}}`asm_main + 23
+# CHECK: frame #1: {{.*}}`main + {{.*}}
+
+target modules show-unwind -n asm_main
+# CHECK: eh_frame UnwindPlan:
+# CHECK: row[0]:0: CFA=rsp +8 => rip=[CFA-8]
+# CHECK: row[1]:   14: CFA=rsp+16 => rbp=[CFA-16] rip=[CFA-8]
+# CHECK: row[2]:   17: CFA=rbp+16 => rbp=[CFA-16] rip=[CFA-8]
+# CHECK: row[3]:   22: CFA=rsp +8 => rip=[CFA-8]
Index: lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s
===
--- /dev/null
+++ lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s
@@ -0,0 +1,25 @@
+.text
+.globl  asm_main
+asm_main:
+.cfi_startproc
+cmpb $0x0, g_hard_abort(%rip)
+jne .L
+
+pushq   %rbp
+.cfi_def_cfa_offset 16
+.cfi_offset 6, -16
+movq%rsp, %rbp
+.cfi_def_cfa_register 6
+callq   abort
+.L:
+.cfi_def_cfa 7, 8
+.cfi_restore 6
+int3
+ud2
+.cfi_endproc
+
+	.data
+	.globl  g_hard_abort
+g_hard_abort:
+	.byte   1
+	.size   g_hard_abort, 1
\ No newline at end of file
Index: lldb/source/Symbol/DWARFCallFrameInfo.cpp
===
--- lldb/source/Symbol/DWARFCallFrameInfo.cpp
+++ lldb/source/Symbol/DWARFCallFrameInfo.cpp
@@ -674,6 +674,11 @@
   unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num,
 reg_location))
 row->SetRegisterInfo(reg_num, reg_location);
+

[Lldb-commits] [PATCH] D153043: [lldb] Fix handling of cfi_restore in the unwinder

2023-06-16 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

In D153043#4427660 , @Michael137 
wrote:

> Looks like this is failing on the Darwin x86_64 buildbots: 
> https://green.lab.llvm.org/green/view/LLDB/job/lldb-cmake/56510/execution/node/74/log/
>
>   Exit Code: 1
>   
>   Command Output (stderr):
>   --
>   clang: warning: argument unused during compilation: 
> '-fmodules-cache-path=/Users/buildslave/jenkins/workspace/lldb-cmake/lldb-build/lldb-test-build.noindex/module-cache-clang/lldb-shell'
>  [-Wunused-command-line-argument]
>   
> /Users/buildslave/jenkins/workspace/lldb-cmake/llvm-project/lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s:25:2:
>  error: unknown directive
>.size g_hard_abort, 1
>^
>   
>   
>   Failed Tests (1):
> lldb-shell :: Unwind/eh-frame-dwarf-unwind-abort.test

I removed the offending directive. Feel free to revert all this if there are 
still problems.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153043/new/

https://reviews.llvm.org/D153043

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D110570: [lldb] Refactor variable parsing in DWARF symbol file

2021-09-27 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin created this revision.
jarin added a reviewer: labath.
jarin added a project: LLDB.
Herald added a subscriber: JDevlieghere.
jarin requested review of this revision.
Herald added a reviewer: jdoerfert.
Herald added subscribers: lldb-commits, sstefan1.

This is in preparation for a fix of parsing omitted abstract
parameters of inlined functions (see the bug
https://bugs.llvm.org/show_bug.cgi?id=50076#c6 for more details). The
main idea is to move the recursive parsing of variables in a function
context into a separate method (ParseVariablesInFunctionContext).

We also move the setup of block variable list to the DIE node that
starts the block rather than setting up the list when processing
the first variable DIE in that block.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D110570

Files:
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h

Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
===
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -380,11 +380,14 @@
 const DWARFDIE &die,
 const lldb::addr_t func_low_pc);
 
-  size_t ParseVariables(const lldb_private::SymbolContext &sc,
-const DWARFDIE &orig_die,
-const lldb::addr_t func_low_pc, bool parse_siblings,
-bool parse_children,
-lldb_private::VariableList *cc_variable_list = nullptr);
+  void
+  ParseAndAppendGlobalVariable(const lldb_private::SymbolContext &sc,
+   const DWARFDIE &die,
+   lldb_private::VariableList &cc_variable_list);
+
+  size_t ParseVariablesInFunctionContext(const lldb_private::SymbolContext &sc,
+ const DWARFDIE &die,
+ const lldb::addr_t func_low_pc);
 
   bool ClassOrStructIsVirtual(const DWARFDIE &die);
 
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2135,7 +2135,7 @@
   }
 }
 
-ParseVariables(sc, die, LLDB_INVALID_ADDRESS, false, false, &variables);
+ParseAndAppendGlobalVariable(sc, die, variables);
 while (pruned_idx < variables.GetSize()) {
   VariableSP var_sp = variables.GetVariableAtIndex(pruned_idx);
   if (name_is_mangled ||
@@ -2188,7 +2188,7 @@
   return true;
 sc.comp_unit = GetCompUnitForDWARFCompUnit(*dwarf_cu);
 
-ParseVariables(sc, die, LLDB_INVALID_ADDRESS, false, false, &variables);
+ParseAndAppendGlobalVariable(sc, die, variables);
 
 return variables.GetSize() - original_size < max_matches;
   });
@@ -3049,8 +3049,8 @@
   /*check_hi_lo_pc=*/true))
 func_lo_pc = ranges.GetMinRangeBase(0);
   if (func_lo_pc != LLDB_INVALID_ADDRESS) {
-const size_t num_variables = ParseVariables(
-sc, function_die.GetFirstChild(), func_lo_pc, true, true);
+const size_t num_variables =
+ParseVariablesInFunctionContext(sc, function_die, func_lo_pc);
 
 // Let all blocks know they have parse all their variables
 sc.function->GetBlock(false).SetDidParseVariables(true, true);
@@ -3481,118 +3481,134 @@
   return DWARFDIE();
 }
 
-size_t SymbolFileDWARF::ParseVariables(const SymbolContext &sc,
-   const DWARFDIE &orig_die,
-   const lldb::addr_t func_low_pc,
-   bool parse_siblings, bool parse_children,
-   VariableList *cc_variable_list) {
-  if (!orig_die)
-return 0;
+void SymbolFileDWARF::ParseAndAppendGlobalVariable(
+const SymbolContext &sc, const DWARFDIE &die,
+VariableList &cc_variable_list) {
+  if (!die)
+return;
 
-  VariableListSP variable_list_sp;
+  dw_tag_t tag = die.Tag();
+  if (tag != DW_TAG_variable && tag != DW_TAG_constant)
+return;
 
-  size_t vars_added = 0;
-  DWARFDIE die = orig_die;
-  while (die) {
-dw_tag_t tag = die.Tag();
+  // Check to see if we have already parsed this variable or constant?
+  VariableSP var_sp = GetDIEToVariable()[die.GetDIE()];
+  if (var_sp) {
+cc_variable_list.AddVariableIfUnique(var_sp);
+return;
+  }
 
-// Check to see if we have already parsed this variable or constant?
-VariableSP var_sp = GetDIEToVariable()[die.GetDIE()];
-if (var_sp) {
-  if (cc_variable_list)
-cc_variable_list->AddVariableIfUnique(var_sp);
+  // We haven't already parsed it, lets do that now.
+  VariableListSP variable_list_sp;
+  DWARFDIE sc_parent_d

[Lldb-commits] [PATCH] D110570: [lldb] Refactor variable parsing in DWARF symbol file

2021-09-27 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Hi, could you possibly take a look at this change?

The main motivation for this patch is to move the setup of the variable list 
for parsing children to the DIE node that corresponds to the block containing 
the children. This will be particularly important for DW_TAG_inlined_subroutine 
because after a recent clang change (https://reviews.llvm.org/D95617), we can 
have inlined subroutines which contain no parameters (and thus no children) in 
the concrete DIE block, but still have some parameters in the abstract function 
(referenced by the inlined subroutine's DW_AT_abstract_origin attribute). If we 
started building the variable list when parsing the first variable in a 
function, we would never create the variable lists for the abstract parameters 
if they were all omitted.

Note that this change is just a refactoring for the actual change that will 
introduce parsing of the omitted abstract parameters. The actual change will be 
uploaded shortly.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110570/new/

https://reviews.llvm.org/D110570

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-09-27 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin created this revision.
jarin added a reviewer: labath.
jarin added a project: LLDB.
Herald added a subscriber: JDevlieghere.
jarin requested review of this revision.
Herald added a reviewer: jdoerfert.
Herald added subscribers: lldb-commits, sstefan1.

This change fixes a problem introduced by clang change
described by https://reviews.llvm.org/D95617 and described by
https://bugs.llvm.org/show_bug.cgi?id=50076#c6, where inlined
functions omit the unused parameters both in the stack trace
and in `frame var` command. With this change, the parameters
are listed correctly in the stack trace and in `frame var`
command (the included test tests `frame var`).

This change adds parsing of formal parameters from the abstract
version of inlined functions and use those formal parameters if
they are missing from the concrete version.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D110571

Files:
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
  lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
  lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test

Index: lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
@@ -0,0 +1,34 @@
+# UNSUPPORTED: system-darwin, system-windows
+
+# REQUIRES: lld
+
+# RUN: llvm-mc -filetype=obj %S/Inputs/unused-inlined-params.s \
+# RUN: -triple x86_64-pc-linux -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: %lldb %t -s %s -o exit | FileCheck %s
+
+breakpoint set -n f
+process launch
+
+# CHECK: Process {{.*}} stopped
+
+# Let us check that unused parameters (of an inlined function) are listed.
+frame variable
+# CHECK-LABEL: frame variable
+# CHECK: (void *) unused1 = <
+# CHECK: (int) used = 42
+# CHECK: (int) unused2 = <
+# CHECK: (int) partial = 1
+# CHECK: (int) unused3 = <
+
+# Step out of the live range of the 'partial' parameter.
+next
+next
+# Check the variable contents.
+frame variable
+# CHECK-LABEL: frame variable
+# CHECK: (void *) unused1 = <
+# CHECK: (int) used = 43
+# CHECK: (int) unused2 = <
+# CHECK: (int) partial = <
+# CHECK: (int) unused3 = <
Index: lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
@@ -0,0 +1,423 @@
+# Generated from the following program (with some pruning):
+#
+# 1   #include 
+# 2
+# 3   __attribute__((always_inline))
+# 4   void f(void* unused1, int used, int unused2, int partial, int unused3) {
+# 5 used += partial;
+# 6 printf("%i", partial);
+# 7 printf("%i", used);
+# 8   }
+# 9
+# 10  int main(int argc, char** argv) {
+# 11f(argv, 42, 1, argc, 2);
+# 12return 0;
+# 13  }
+	.text
+	.file	"unused-inlined-params.c"
+	.globl	main# -- Begin function main
+	.p2align	4, 0x90
+	.type	main,@function
+main:   # @main
+.Lfunc_begin1:
+	.file	1 "/example" "unused-inlined-params.c"
+	.loc	1 10 0  # unused-inlined-params.c:10:0
+	.cfi_startproc
+# %bb.0:
+	#DEBUG_VALUE: main:argc <- $edi
+	#DEBUG_VALUE: main:argv <- $rsi
+	#DEBUG_VALUE: f:partial <- $edi
+	pushq	%rbx
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbx, -16
+	movl	%edi, %esi
+.Lline5:
+	#DEBUG_VALUE: main:argv <- [DW_OP_LLVM_entry_value 1] $rsi
+	#DEBUG_VALUE: f:unused3 <- undef
+	#DEBUG_VALUE: f:unused2 <- undef
+	#DEBUG_VALUE: f:used <- 42
+	#DEBUG_VALUE: f:unused1 <- undef
+	#DEBUG_VALUE: f:partial <- $esi
+	#DEBUG_VALUE: main:argc <- $esi
+	.loc	1 5 8 prologue_end  # unused-inlined-params.c:5:8
+	leal	42(%rsi), %ebx
+.Lline6:
+	#DEBUG_VALUE: f:used <- $ebx
+	.loc	1 6 3   # unused-inlined-params.c:6:3
+	movl	$.L.str, %edi
+# kill: def $esi killed $esi killed $rsi
+	xorl	%eax, %eax
+	callq	printf
+.Lline7:
+	.loc	1 7 3   # unused-inlined-params.c:7:3
+	movl	$.L.str, %edi
+	movl	%ebx, %esi
+	xorl	%eax, %eax
+	callq	printf
+.Lline12:
+	.loc	1 12 3  # unused-inlined-params.c:12:3
+	xorl	%eax, %eax
+	popq	%rbx
+.Lreturn1:
+	.cfi_def_cfa_offset 8
+	retq
+.Lfunc_end1:
+	.size	main, .Lfunc_end1-main
+	.cfi_endproc
+# -- End function
+# Dummy printf implementation.
+printf:
+retq
+
+# Simple implementation of _start - set up argc, argv and tail-call main.
+	.globl	_start
+	.p2align	4, 0x90
+	.type	_start,@function
+_start:
+movl(%rsp), %edi
+leaq4(%rsp), %rsi
+jmp main
+
+	.type	.L.str,@object  # @.str
+	.section	.rodata.str1.1,"aMS",@progbits,1
+.L.str:
+	.asciz	"%i"
+	.size	.L.str, 3
+
+	.section	.debug_loc,"",@progbits
+.Ldebug

[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-09-27 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Hi, could you take a look at this change?

Some discussion points:

- In the ParseVariablesInFunctionContext method, we are using a lambda for the 
recursive parser. We could also use a function-local class or inner class of 
SymbolFileDWARF. Would any of these be preferable?
- The variables created by ParseVariableDIE on abstract formal parameters are 
fairly strange, especially if a function gets inlined into two different 
functions. If that happens, then the parsed variable will refer to a symbol 
context that does not contain the variable DIE and a block can contain a 
variable that is not in the DIE of tree of the block. Is that a big problem? 
(Quick testing of this situation did not reveal any strange stack traces or 
`frame var` anomalies.) Unfortunately, there is no good way to provide the 
correct block and the correct function because LLDB does not parse functions 
and blocks for the abstract functions (i.e., for the DW_TAG_subroutines that 
are referenced by DW_AT_abstract_origin of concrete functions).
- The provided test only tests the case of an inlined function where some 
parameters are unused/omitted. Would it make sense to also provide tests for 
other interesting cases or would that be too much bloat? The particularly 
interesting cases are:
  - Inlined function with all its parameters unused/omitted,
  - Inlined function that is called from different top-level functions.
  - Test correctness of the stack trace in the cases above.
- We could supply a test written in C, but it needs -O1 and is fairly sensitive 
to the meaning of -O1 (e.g., clang started inlining and omitting unsued inlined 
parameters only recently, so changes to -O1 could make a C test easily 
meaningless). Any concerns here?
- The provided test is a bit verbose, mostly because we wanted to mostly 
preserve the structure of the C compiler output. We could still cut the size of 
the test down by removing the main function in favour of _start and by removing 
all the file/line info. Would any of that make sense?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110571/new/

https://reviews.llvm.org/D110571

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D110570: [lldb] Refactor variable parsing in DWARF symbol file

2021-09-27 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Thank you for taking a look, shafik@. I hope you don't mind if I address your 
comments later, once a full review arrives from Pavel (or Johannes).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110570/new/

https://reviews.llvm.org/D110570

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D110570: [lldb] Refactor variable parsing in DWARF symbol file

2021-09-28 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 375535.
jarin added a comment.

Separated ParseVariablesInFunctionContext's lambda into a method.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110570/new/

https://reviews.llvm.org/D110570

Files:
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h

Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
===
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -380,11 +380,19 @@
 const DWARFDIE &die,
 const lldb::addr_t func_low_pc);
 
-  size_t ParseVariables(const lldb_private::SymbolContext &sc,
-const DWARFDIE &orig_die,
-const lldb::addr_t func_low_pc, bool parse_siblings,
-bool parse_children,
-lldb_private::VariableList *cc_variable_list = nullptr);
+  void
+  ParseAndAppendGlobalVariable(const lldb_private::SymbolContext &sc,
+   const DWARFDIE &die,
+   lldb_private::VariableList &cc_variable_list);
+
+  size_t ParseVariablesInFunctionContext(const lldb_private::SymbolContext &sc,
+ const DWARFDIE &die,
+ const lldb::addr_t func_low_pc);
+
+  size_t ParseVariablesInFunctionContextRecursive(
+  const lldb_private::SymbolContext &sc, const DWARFDIE &die,
+  const lldb::addr_t func_low_pc,
+  lldb_private::VariableList &variable_list);
 
   bool ClassOrStructIsVirtual(const DWARFDIE &die);
 
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2135,7 +2135,7 @@
   }
 }
 
-ParseVariables(sc, die, LLDB_INVALID_ADDRESS, false, false, &variables);
+ParseAndAppendGlobalVariable(sc, die, variables);
 while (pruned_idx < variables.GetSize()) {
   VariableSP var_sp = variables.GetVariableAtIndex(pruned_idx);
   if (name_is_mangled ||
@@ -2188,7 +2188,7 @@
   return true;
 sc.comp_unit = GetCompUnitForDWARFCompUnit(*dwarf_cu);
 
-ParseVariables(sc, die, LLDB_INVALID_ADDRESS, false, false, &variables);
+ParseAndAppendGlobalVariable(sc, die, variables);
 
 return variables.GetSize() - original_size < max_matches;
   });
@@ -3049,8 +3049,8 @@
   /*check_hi_lo_pc=*/true))
 func_lo_pc = ranges.GetMinRangeBase(0);
   if (func_lo_pc != LLDB_INVALID_ADDRESS) {
-const size_t num_variables = ParseVariables(
-sc, function_die.GetFirstChild(), func_lo_pc, true, true);
+const size_t num_variables =
+ParseVariablesInFunctionContext(sc, function_die, func_lo_pc);
 
 // Let all blocks know they have parse all their variables
 sc.function->GetBlock(false).SetDidParseVariables(true, true);
@@ -3481,117 +3481,135 @@
   return DWARFDIE();
 }
 
-size_t SymbolFileDWARF::ParseVariables(const SymbolContext &sc,
-   const DWARFDIE &orig_die,
-   const lldb::addr_t func_low_pc,
-   bool parse_siblings, bool parse_children,
-   VariableList *cc_variable_list) {
-  if (!orig_die)
-return 0;
+void SymbolFileDWARF::ParseAndAppendGlobalVariable(
+const SymbolContext &sc, const DWARFDIE &die,
+VariableList &cc_variable_list) {
+  if (!die)
+return;
 
+  dw_tag_t tag = die.Tag();
+  if (tag != DW_TAG_variable && tag != DW_TAG_constant)
+return;
+
+  // Check to see if we have already parsed this variable or constant?
+  VariableSP var_sp = GetDIEToVariable()[die.GetDIE()];
+  if (var_sp) {
+cc_variable_list.AddVariableIfUnique(var_sp);
+return;
+  }
+
+  // We haven't already parsed it, lets do that now.
   VariableListSP variable_list_sp;
+  DWARFDIE sc_parent_die = GetParentSymbolContextDIE(die);
+  dw_tag_t parent_tag = sc_parent_die.Tag();
+  switch (parent_tag) {
+  case DW_TAG_compile_unit:
+  case DW_TAG_partial_unit:
+if (sc.comp_unit != nullptr) {
+  variable_list_sp = sc.comp_unit->GetVariableList(false);
+} else {
+  GetObjectFile()->GetModule()->ReportError(
+  "parent 0x%8.8" PRIx64 " %s with no valid compile unit in "
+  "symbol context for 0x%8.8" PRIx64 " %s.\n",
+  sc_parent_die.GetID(), sc_parent_die.GetTagAsCString(), die.GetID(),
+  die.GetTagAsCString());
+  return;
+}
+break;
 
+  default:
+GetObjectFile()->GetModule()->ReportError(
+"didn't find appropriate par

[Lldb-commits] [PATCH] D110570: [lldb] Refactor variable parsing in DWARF symbol file

2021-09-28 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 375538.
jarin added a comment.

Added the `/*can_create=*/` comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110570/new/

https://reviews.llvm.org/D110570

Files:
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h

Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
===
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -380,11 +380,19 @@
 const DWARFDIE &die,
 const lldb::addr_t func_low_pc);
 
-  size_t ParseVariables(const lldb_private::SymbolContext &sc,
-const DWARFDIE &orig_die,
-const lldb::addr_t func_low_pc, bool parse_siblings,
-bool parse_children,
-lldb_private::VariableList *cc_variable_list = nullptr);
+  void
+  ParseAndAppendGlobalVariable(const lldb_private::SymbolContext &sc,
+   const DWARFDIE &die,
+   lldb_private::VariableList &cc_variable_list);
+
+  size_t ParseVariablesInFunctionContext(const lldb_private::SymbolContext &sc,
+ const DWARFDIE &die,
+ const lldb::addr_t func_low_pc);
+
+  size_t ParseVariablesInFunctionContextRecursive(
+  const lldb_private::SymbolContext &sc, const DWARFDIE &die,
+  const lldb::addr_t func_low_pc,
+  lldb_private::VariableList &variable_list);
 
   bool ClassOrStructIsVirtual(const DWARFDIE &die);
 
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2135,7 +2135,7 @@
   }
 }
 
-ParseVariables(sc, die, LLDB_INVALID_ADDRESS, false, false, &variables);
+ParseAndAppendGlobalVariable(sc, die, variables);
 while (pruned_idx < variables.GetSize()) {
   VariableSP var_sp = variables.GetVariableAtIndex(pruned_idx);
   if (name_is_mangled ||
@@ -2188,7 +2188,7 @@
   return true;
 sc.comp_unit = GetCompUnitForDWARFCompUnit(*dwarf_cu);
 
-ParseVariables(sc, die, LLDB_INVALID_ADDRESS, false, false, &variables);
+ParseAndAppendGlobalVariable(sc, die, variables);
 
 return variables.GetSize() - original_size < max_matches;
   });
@@ -3049,8 +3049,8 @@
   /*check_hi_lo_pc=*/true))
 func_lo_pc = ranges.GetMinRangeBase(0);
   if (func_lo_pc != LLDB_INVALID_ADDRESS) {
-const size_t num_variables = ParseVariables(
-sc, function_die.GetFirstChild(), func_lo_pc, true, true);
+const size_t num_variables =
+ParseVariablesInFunctionContext(sc, function_die, func_lo_pc);
 
 // Let all blocks know they have parse all their variables
 sc.function->GetBlock(false).SetDidParseVariables(true, true);
@@ -3481,117 +3481,137 @@
   return DWARFDIE();
 }
 
-size_t SymbolFileDWARF::ParseVariables(const SymbolContext &sc,
-   const DWARFDIE &orig_die,
-   const lldb::addr_t func_low_pc,
-   bool parse_siblings, bool parse_children,
-   VariableList *cc_variable_list) {
-  if (!orig_die)
-return 0;
+void SymbolFileDWARF::ParseAndAppendGlobalVariable(
+const SymbolContext &sc, const DWARFDIE &die,
+VariableList &cc_variable_list) {
+  if (!die)
+return;
 
+  dw_tag_t tag = die.Tag();
+  if (tag != DW_TAG_variable && tag != DW_TAG_constant)
+return;
+
+  // Check to see if we have already parsed this variable or constant?
+  VariableSP var_sp = GetDIEToVariable()[die.GetDIE()];
+  if (var_sp) {
+cc_variable_list.AddVariableIfUnique(var_sp);
+return;
+  }
+
+  // We haven't already parsed it, lets do that now.
   VariableListSP variable_list_sp;
+  DWARFDIE sc_parent_die = GetParentSymbolContextDIE(die);
+  dw_tag_t parent_tag = sc_parent_die.Tag();
+  switch (parent_tag) {
+  case DW_TAG_compile_unit:
+  case DW_TAG_partial_unit:
+if (sc.comp_unit != nullptr) {
+  variable_list_sp = sc.comp_unit->GetVariableList(false);
+} else {
+  GetObjectFile()->GetModule()->ReportError(
+  "parent 0x%8.8" PRIx64 " %s with no valid compile unit in "
+  "symbol context for 0x%8.8" PRIx64 " %s.\n",
+  sc_parent_die.GetID(), sc_parent_die.GetTagAsCString(), die.GetID(),
+  die.GetTagAsCString());
+  return;
+}
+break;
 
+  default:
+GetObjectFile()->GetModule()->ReportError(
+"didn't find appropriate parent DIE for variable list fo

[Lldb-commits] [PATCH] D110570: [lldb] Refactor variable parsing in DWARF symbol file

2021-09-28 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Thank you for the review! Does the separate method look more reasonable?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110570/new/

https://reviews.llvm.org/D110570

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-09-28 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Just a few replies below; I am hoping to put the relevant code changes together 
tomorrow.

In D110571#3027173 , @labath wrote:

> I haven't looked at the actual code yet, so I could be off, but here are some 
> thoughts.
>
> In D110571#3025527 , @jarin wrote:
>
>> Hi, could you take a look at this change?
>>
>> Some discussion points:
>>
>> - In the ParseVariablesInFunctionContext method, we are using a lambda for 
>> the recursive parser. We could also use a function-local class or inner 
>> class of SymbolFileDWARF. Would any of these be preferable?
>
> Yeah, what's the deal with that? Why wouldn't a regular function be 
> sufficient? You can just pass things in arguments instead of closures or 
> classes..

Right, I worked on a codebase where they used local classes for such things and 
in lldb I have seen lambdas. I actually do not have a strong preference, will 
rewrite this to use plain methods.

>> - The variables created by ParseVariableDIE on abstract formal parameters 
>> are fairly strange, especially if a function gets inlined into two different 
>> functions. If that happens, then the parsed variable will refer to a symbol 
>> context that does not contain the variable DIE and a block can contain a 
>> variable that is not in the DIE of tree of the block. Is that a big problem? 
>> (Quick testing of this situation did not reveal any strange stack traces or 
>> `frame var` anomalies.) Unfortunately, there is no good way to provide the 
>> correct block and the correct function because LLDB does not parse functions 
>> and blocks for the abstract functions (i.e., for the DW_TAG_subroutines that 
>> are referenced by DW_AT_abstract_origin of concrete functions).
>
> Judging by your description, I take it you parse these variables only once, 
> regardless of how many functions they are inlined in. Could we fix that my 
> creating a fresh variable object for each inlined instance? Then it could 
> maybe be correctly made to point to the actual block and function it is 
> inlined into(?)

Yes, they are parsed only once. This is because there is a DIE->Variable map 
(see SymbolFileDWARF::GetDIEToVariable) that makes sure no DIE gets parsed 
twice. Are you suggesting to index the map with a pair ? That would indeed create healthier structure (even though I 
could not spot any problems even with my current somewhat flawed approach).

>> - The provided test only tests the case of an inlined function where some 
>> parameters are unused/omitted. Would it make sense to also provide tests for 
>> other interesting cases or would that be too much bloat? The particularly 
>> interesting cases are:
>>   - Inlined function with all its parameters unused/omitted,
>>   - Inlined function that is called from different top-level functions.
>>   - Test correctness of the stack trace in the cases above.
>> - We could supply a test written in C, but it needs -O1 and is fairly 
>> sensitive to the meaning of -O1 (e.g., clang started inlining and omitting 
>> unsued inlined parameters only recently, so changes to -O1 could make a C 
>> test easily meaningless). Any concerns here?
>> - The provided test is a bit verbose, mostly because we wanted to mostly 
>> preserve the structure of the C compiler output. We could still cut the size 
>> of the test down by removing the main function in favour of _start and by 
>> removing all the file/line info. Would any of that make sense?
>
> I think you could get quite far by just testing the output of the "image 
> lookup" command. That should give you list variables that are in scope for 
> any particular address, and a bunch of details about each var, including the 
> expression used to compute its value (not the value itself, obviously). The 
> main advantage is that you wouldn't need a fully functional program, as you 
> wouldn't be running anything. That would remove a lot of bloat, and also 
> allow the test to run on non-x86-pc-linux hosts. Then, maybe it wouldn't be 
> too messy to add the additional test cases you mention.
>
> You can look at (e.g.) DW_AT_loclists_base.s for an example of a test case 
> with image lookup and local variables.

Makes sense, I really like that approach. Let me try to get that working.

> After that, we could think about adding a c++ test case. Although tests with 
> optimized code are tricky, it is often possible (with judicious use of 
> noinline, always_inline and optnone attributes) to constrain the optimizer in 
> a way that it has no choice but to do exactly what we want.

I have actually use the attributes when experimenting with the patch - if you 
think this is useful, I can certainly provide those tests.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110571/new/

https://reviews.llvm.org/D110571

___
lldb-commits mailing list
lldb-com

[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-09-29 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 375865.
jarin added a comment.

Rewrote the recursive parser to use a plain method.

Pruned and annotated the test.

Added other test cases:

- all parameters unused,
- inlining from two different functions,
- stack trace.

This still uses `frame variable` rather than `image lookup`, mostly because 
`frame variable` tests better the user experience and the cognitive overhead 
for making the code runnable does not seem to be too high.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110571/new/

https://reviews.llvm.org/D110571

Files:
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
  lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
  lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test

Index: lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
@@ -0,0 +1,69 @@
+# UNSUPPORTED: system-darwin, system-windows
+
+# REQUIRES: lld
+
+# RUN: llvm-mc -filetype=obj %S/Inputs/unused-inlined-params.s \
+# RUN: -triple x86_64-pc-linux -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: %lldb %t -s %s -o exit | FileCheck %s
+
+
+# In this test we verify that inlined functions still mention
+# all their parameters in `frame variable`, even when those
+# parameters were completely optimized away from the concrete
+# instance of the inlined function in the debug info.
+# The debugger should look up the parameters in the abstract
+# origin of the concrete instance.
+
+breakpoint set -n main
+process launch
+# CHECK: Process {{.*}} stopped
+
+# Let us check that unused parameters of an inlined function are listed
+# at the inlined function entry.
+breakpoint set -n break_at_inlined_f_in_main
+continue
+frame variable
+# CHECK-LABEL: frame variable
+# CHECK: (void *) unused1 = <
+# CHECK: (int) used = 42
+# CHECK: (int) unused2 = <
+# CHECK: (int) partial = 1
+# CHECK: (int) unused3 = <
+
+# Step out of the live range of the 'partial' parameter and verify that
+# all variables are still displayed.
+breakpoint set -n break_at_inlined_f_in_main_between_printfs
+continue
+frame variable
+# CHECK-LABEL: frame variable
+# CHECK: (void *) unused1 = <
+# CHECK: (int) used = 43
+# CHECK: (int) unused2 = <
+# CHECK: (int) partial = <
+# CHECK: (int) unused3 = <
+
+# Check that we show parameters even if all of them are compiled away.
+breakpoint set -n break_at_inlined_g_in_main
+continue
+frame variable
+# CHECK-LABEL: frame variable
+# CHECK: (int) unused = <
+
+# Check that even the other inlined instance of f displays correct
+# parameters.
+breakpoint set -n break_at_inlined_f_in_other
+continue
+frame variable
+# CHECK-LABEL: frame variable
+# CHECK: (void *) unused1 = <
+# CHECK: (int) used = 1
+# CHECK: (int) unused2 = <
+# CHECK: (int) partial = 2
+# CHECK: (int) unused3 = <
+
+# Check that the stack trace contains the inlined function with
+# all the arguments
+thread backtrace
+CHECK: other [inlined] f(unused1=, used=1, unused2=, \
+partial=2, unused3=)
\ No newline at end of file
Index: lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
@@ -0,0 +1,458 @@
+# The below program is roughly derived from the following C program.
+# To see the annotated debug info, look for the section 
+# '.section.debug_info' below.
+#
+# __attribute__((always_inline))
+# void f(void* unused1, int used, int unused2, int partial, int unused3) {
+#   used += partial;
+#   printf("f %i", partial);
+#   printf("f %i", used);   // |partial| is not live at this line.
+# }
+#
+# void g(int unused) {
+#   printf("Hello");
+# }
+#
+# __attribute__((noinline))
+# void other() {
+#   f(nullptr, 1, 0, 2, 0);
+# }
+#
+# int main(int argc, char** argv) {
+#   f(argv, 42, 1, argc, 2);
+#   g(1);
+#   other();
+#   return 0;
+# }
+
+.text
+.file"unused-inlined-params.c"
+
+.Lcu_begin:
+
+.globlother
+other:
+nop
+.Linlined_f_in_other:
+break_at_inlined_f_in_other:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_in_other_between_printfs:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_in_other_end:
+retq
+.Lother_end:
+.sizeother, .Lother_end-other
+
+.globlmain
+main:
+.file1 "/example" "unused-inlined-params.c"
+movl$1, %esi
+.Linlined_f:
+break_at_inlined_f_in_main:
+leal42(%rsi), %ebx
+.Linlined_f_before_printf:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_between_printfs:
+break_at_inlined_f_in_main_between_printfs:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_end:
+.Linlined_g:
+break_at_inlined_g_in_main:
+ 

[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-09-29 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 375886.
jarin added a comment.

Added a C test (I have also verified that the C test fails without the 
SymbolFileDWARF patch).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110571/new/

https://reviews.llvm.org/D110571

Files:
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
  lldb/test/API/functionalities/unused-inlined-parameters/Makefile
  
lldb/test/API/functionalities/unused-inlined-parameters/TestUnusedInlinedParameters.py
  lldb/test/API/functionalities/unused-inlined-parameters/main.c
  lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
  lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test

Index: lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
@@ -0,0 +1,69 @@
+# UNSUPPORTED: system-darwin, system-windows
+
+# REQUIRES: lld
+
+# RUN: llvm-mc -filetype=obj %S/Inputs/unused-inlined-params.s \
+# RUN: -triple x86_64-pc-linux -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: %lldb %t -s %s -o exit | FileCheck %s
+
+
+# In this test we verify that inlined functions still mention
+# all their parameters in `frame variable`, even when those
+# parameters were completely optimized away from the concrete
+# instance of the inlined function in the debug info.
+# The debugger should look up the parameters in the abstract
+# origin of the concrete instance.
+
+breakpoint set -n main
+process launch
+# CHECK: Process {{.*}} stopped
+
+# Let us check that unused parameters of an inlined function are listed
+# at the inlined function entry.
+breakpoint set -n break_at_inlined_f_in_main
+continue
+frame variable
+# CHECK-LABEL: frame variable
+# CHECK: (void *) unused1 = <
+# CHECK: (int) used = 42
+# CHECK: (int) unused2 = <
+# CHECK: (int) partial = 1
+# CHECK: (int) unused3 = <
+
+# Step out of the live range of the 'partial' parameter and verify that
+# all variables are still displayed.
+breakpoint set -n break_at_inlined_f_in_main_between_printfs
+continue
+frame variable
+# CHECK-LABEL: frame variable
+# CHECK: (void *) unused1 = <
+# CHECK: (int) used = 43
+# CHECK: (int) unused2 = <
+# CHECK: (int) partial = <
+# CHECK: (int) unused3 = <
+
+# Check that we show parameters even if all of them are compiled away.
+breakpoint set -n break_at_inlined_g_in_main
+continue
+frame variable
+# CHECK-LABEL: frame variable
+# CHECK: (int) unused = <
+
+# Check that even the other inlined instance of f displays correct
+# parameters.
+breakpoint set -n break_at_inlined_f_in_other
+continue
+frame variable
+# CHECK-LABEL: frame variable
+# CHECK: (void *) unused1 = <
+# CHECK: (int) used = 1
+# CHECK: (int) unused2 = <
+# CHECK: (int) partial = 2
+# CHECK: (int) unused3 = <
+
+# Check that the stack trace contains the inlined function with
+# all the arguments
+thread backtrace
+CHECK: other [inlined] f(unused1=, used=1, unused2=, \
+partial=2, unused3=)
\ No newline at end of file
Index: lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
@@ -0,0 +1,458 @@
+# The below program is roughly derived from the following C program.
+# To see the annotated debug info, look for the section 
+# '.section.debug_info' below.
+#
+# __attribute__((always_inline))
+# void f(void* unused1, int used, int unused2, int partial, int unused3) {
+#   used += partial;
+#   printf("f %i", partial);
+#   printf("f %i", used);   // |partial| is not live at this line.
+# }
+#
+# void g(int unused) {
+#   printf("Hello");
+# }
+#
+# __attribute__((noinline))
+# void other() {
+#   f(nullptr, 1, 0, 2, 0);
+# }
+#
+# int main(int argc, char** argv) {
+#   f(argv, 42, 1, argc, 2);
+#   g(1);
+#   other();
+#   return 0;
+# }
+
+.text
+.file"unused-inlined-params.c"
+
+.Lcu_begin:
+
+.globlother
+other:
+nop
+.Linlined_f_in_other:
+break_at_inlined_f_in_other:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_in_other_between_printfs:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_in_other_end:
+retq
+.Lother_end:
+.sizeother, .Lother_end-other
+
+.globlmain
+main:
+.file1 "/example" "unused-inlined-params.c"
+movl$1, %esi
+.Linlined_f:
+break_at_inlined_f_in_main:
+leal42(%rsi), %ebx
+.Linlined_f_before_printf:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_between_printfs:
+break_at_inlined_f_in_main_between_printfs:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_end:
+.Linlined_g:
+break_at_inlined_g_in_main:
+callqprintf# Omitted the setup of 

[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-09-29 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

In D110571#3030222 , @labath wrote:

> In D110571#3030192 , @jarin wrote:
>
>> This still uses `frame variable` rather than `image lookup`, mostly because 
>> `frame variable` tests better the user experience and the cognitive overhead 
>> for making the code runnable does not seem to be too high.
>
> This is not really about "cognitive overhead", but "who can run this test". 
> With a running process the answer is "a person with a linux x86 machine". 
> With image lookup it's "everyone". It's also easier to debug failures in the 
> test, as less code gets run before you get to the interesting part.

Good point. Would you prefer to recast the test in terms of image lookup and 
get rid of checking the stack trace?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110571/new/

https://reviews.llvm.org/D110571

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-09-29 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 375901.
jarin added a comment.

Changed the test to avoid running the process and use `image lookup` instead of 
`frame variable`.

I think I would still slightly prefer `frame variable`, mostly because there 
seem to be differences between what `image lookup` and `frame variable` show 
(`image lookup` omit variables that have DW_AT_location disjoint from the 
inspected address). As opposed to `image lookup`, `frame variable` tests more 
directly what the users would actually use.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110571/new/

https://reviews.llvm.org/D110571

Files:
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
  lldb/test/API/functionalities/unused-inlined-parameters/Makefile
  
lldb/test/API/functionalities/unused-inlined-parameters/TestUnusedInlinedParameters.py
  lldb/test/API/functionalities/unused-inlined-parameters/main.c
  lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
  lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test

Index: lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
@@ -0,0 +1,49 @@
+# UNSUPPORTED: system-darwin, system-windows
+
+# RUN: llvm-mc -filetype=obj %S/Inputs/unused-inlined-params.s \
+# RUN: -triple x86_64-pc-linux -o %t.o
+# RUN: %lldb %t.o -s %s -o exit | FileCheck %s
+
+
+# In this test we verify that inlined functions still mention
+# all their parameters in `frame variable`, even when those
+# parameters were completely optimized away from the concrete
+# instance of the inlined function in the debug info.
+# The debugger should look up the parameters in the abstract
+# origin of the concrete instance.
+
+# Let us check that unused parameters of an inlined function are listed
+# at the inlined function entry.
+image lookup -v -s break_at_inlined_f_in_main
+# CHECK-LABEL: image lookup -v -s break_at_inlined_f_in_main
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_consts +42
+# CHECK: name = "unused2", type = "int", location = 
+# CHECK: name = "partial", type = "int", location = DW_OP_reg4 RSI
+# CHECK: name = "unused3", type = "int", location = 
+
+# Show variables outsid of the live range of the 'partial' parameter
+# and verify that the output is as expected.
+image lookup -v -s break_at_inlined_f_in_main_between_printfs
+# CHECK-LABEL: image lookup -v -s break_at_inlined_f_in_main_between_printfs
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_reg3 RBX
+# CHECK: name = "unused2", type = "int", location = 
+# Note: image lookup does not show variables outside of their
+#   location, so |partial| is missing here.
+# CHECK: name = "unused3", type = "int", location = 
+
+# Check that we show parameters even if all of them are compiled away.
+image lookup -v -s  break_at_inlined_g_in_main
+# CHECK-LABEL: image lookup -v -s  break_at_inlined_g_in_main
+# CHECK: name = "unused", type = "int", location = 
+
+# Check that even the other inlined instance of f displays the correct
+# parameters.
+image lookup -v -s  break_at_inlined_f_in_other
+# CHECK-LABEL: image lookup -v -s  break_at_inlined_f_in_other
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_consts +1
+# CHECK: name = "unused2", type = "int", location = 
+# CHECK: name = "partial", type = "int", location =  DW_OP_consts +2
+# CHECK: name = "unused3", type = "int", location = 
\ No newline at end of file
Index: lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
@@ -0,0 +1,458 @@
+# The below program is roughly derived from the following C program.
+# To see the annotated debug info, look for the section 
+# '.section.debug_info' below.
+#
+# __attribute__((always_inline))
+# void f(void* unused1, int used, int unused2, int partial, int unused3) {
+#   used += partial;
+#   printf("f %i", partial);
+#   printf("f %i", used);   // |partial| is not live at this line.
+# }
+#
+# void g(int unused) {
+#   printf("Hello");
+# }
+#
+# __attribute__((noinline))
+# void other() {
+#   f(nullptr, 1, 0, 2, 0);
+# }
+#
+# int main(int argc, char** argv) {
+#   f(argv, 42, 1, argc, 2);
+#   g(1);
+#   other();
+#   return 0;
+# }
+
+.text
+.file"unused-inlined-params.c"
+
+.Lcu_begin:
+
+.globlother
+other:
+nop
+.Linlined_f_in_other:
+break_at_inlined_f_in_other:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_in_other_between_printfs:
+call

[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-09-29 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

First of all, thank you, Greg and Pavel, for all the great feedback and 
discussion. I have followed all your suggestions (use plain method, use `image 
lookup`, added the additional tests). I have also packaged the C test, but as 
Greg notes I am not convinced it will keep testing what it's supposed to.

Now, let me answer the question regarding the context:

In D110571#3030913 , @clayborg wrote:

> LLDB doesn't parse function definitions that have no low/high PC into 
> lldb_private::Function with lldb_private::Block objects, it only does this 
> for instances of functions with address ranges.
>
> I would expect that the SymbolContextScope (one pointer that can identify the 
> SymbolContext) for each variable parsed by ParseVariableDIE to point to the 
> DW_TAG_variable that is in the function with the address range. Are you 
> saying that the symbol context points to the definition?

With this change, the symbol context for unused parameters points to one of the 
concrete inlined function block (DW_TAG_inlined_subroutine). That concrete 
inlined function will not contain that formal parameter because after the clang 
change https://reviews.llvm.org/D95617, unused formal parameters are deleted 
from their concrete inlined functions (i.e., from their 
DW_TAG_inlined_subroutine).

The point here is that if a function is inlined into two places, i.e., there 
are two corresponding DW_TAG_inlined_subroutines for the inlined function, we 
still create just one instance of Variable and its symbol context will be one 
randomly chosen DW_TAG_inlined_subroutine.

As Pavel suggested, an alternative would be creating one Variable instance per 
DW_TAG_inlined_subroutine. That would require some changes to other data 
structures because the existing code assumes there is just one Variable for 
each DIE (see SymbolFileDWARF::GetDIEToVariable).

For illustration:

  0x100  DW_TAG_subprogram
   DW_AT_name "inlined_function"
   ... no DW_AT_low_pc here ...
  0x110DW_TAG_formal_parameter
 DW_AT_name "unused"
 ...
 ...
  0x200  DW_TAG_subprogram
   DW_AT_name("top_level_function_with_address"
   DW_AT_low_pc  (0x3000)
   DW_AT_high_pc  (0x3100)
   ...
  0x210DW_TAG_inlined_subroutine
 DW_AT_abstract_origin (0x100 "inlined_function")
 DW_AT_low_pc  (0x3010)
 DW_AT_high_pc  (0x3020)
 # Note the missing DW_TAG_formal_parameter here!
   NULL
 ...
  0x400  DW_TAG_subprogram
   DW_AT_name("another_top_level_function_with_address"
   DW_AT_low_pc  (0x5000)
   DW_AT_high_pc  (0x5100)
   ...
  0x410DW_TAG_inlined_subroutine
 DW_AT_abstract_origin (0x100 "inlined_function")
 DW_AT_low_pc  (0x5030)
 DW_AT_high_pc  (0x5040)
 # Note the missing DW_TAG_formal_parameter here!
   NULL
 ...

Here, we will create just one variable for the formal parameter "unused" (DIE 
offset 0x110). That variable's symbol context will be randomly one of the 
DW_TAG_inline subroutine blocks (either 0x210 or 0x410), and the variable will 
be inserted into two variable lists, one for the Block associated with the DIE 
at 0x210 and one for DIE associated with 0x410.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110571/new/

https://reviews.llvm.org/D110571

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-09-29 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

In D110571#3031846 , @clayborg wrote:

> In D110571#3031140 , @jarin wrote:
>
>> For illustration:
>>
>>   0x100  DW_TAG_subprogram
>>DW_AT_name "inlined_function"
>>... no DW_AT_low_pc here ...
>>   0x110DW_TAG_formal_parameter
>>  DW_AT_name "unused"
>>  ...
>>  ...
>>   0x200  DW_TAG_subprogram
>>DW_AT_name("top_level_function_with_address"
>>DW_AT_low_pc  (0x3000)
>>DW_AT_high_pc  (0x3100)
>>...
>>   0x210DW_TAG_inlined_subroutine
>>  DW_AT_abstract_origin (0x100 "inlined_function")
>>  DW_AT_low_pc  (0x3010)
>>  DW_AT_high_pc  (0x3020)
>>  # Note the missing DW_TAG_formal_parameter here!
>>NULL
>>  ...
>>   0x400  DW_TAG_subprogram
>>DW_AT_name("another_top_level_function_with_address"
>>DW_AT_low_pc  (0x5000)
>>DW_AT_high_pc  (0x5100)
>>...
>>   0x410DW_TAG_inlined_subroutine
>>  DW_AT_abstract_origin (0x100 "inlined_function")
>>  DW_AT_low_pc  (0x5030)
>>  DW_AT_high_pc  (0x5040)
>>  # Note the missing DW_TAG_formal_parameter here!
>>NULL
>>  ...
>>
>> Here, we will create just one variable for the formal parameter "unused" 
>> (DIE offset 0x110). That variable's symbol context will be randomly one of 
>> the DW_TAG_inline subroutine blocks (either 0x210 or 0x410), and the 
>> variable will be inserted into two variable lists, one for the Block 
>> associated with the DIE at 0x210 and one for DIE associated with 0x410.
>
> I hear what you are saying, but I am not sure this will be happening. Let me 
> explain: for each concrete DW_TAG_subprogram (0x200 and 0x400 in your example 
> above), we create a unique lldb_private::Function object whose UserID will be 
> 0x200 for "top_level_function_with_address" and 0x400 for 
> "another_top_level_function_with_address". Each of those functions might be 
> asked for their lldb_private::Block objects at some point and we should 
> create unique lldb_private::Block for each DW_TAG_lexical_block and 
> DW_TAG_inlined_subroutine that is contained within these unique DIEs. Each of 
> these should now have a variable within the block that is a parameter whose 
> name is "unused" and whose symbol context should be 0x210 for the 0x200 DIE, 
> and 0x410 for the 0x400 DIE. So it would be great to make sure this happens 
> correctly. From looking at the code, it seems like this should be happening 
> correctly, but you might know better since you made these new modifications.

Hi Greg, thanks for the detailed description! What you say is indeed happening 
until the point "Each of these [blocks] should now have a variable within the 
block that is a parameter whose name is "unused" and whose symbol context 
should be 0x210 for the 0x200 DIE, and 0x410 for the 0x400 DIE.".

With my patch, LLDB creates only one variable here, its symbol context will be 
whichever block was parsed first and that variable will be inserted into the 
variable lists of blocks corresponding to 0x210 and 0x410. The reason why LLDB 
creates only one variable is that there is a cache of variables indexed by 
DIEs. When we call ParseVariableDIE 

 first time for the variable "unused" (DIE 0x110) and symbol context 0x210, the 
variable gets created 

 and inserted 

 under the key 0x110. When we call ParseVariableDIE second time for "unused" 
(still 0x110) and symbol context 0x410, we will find and return 

 the originally created variable (with symbol context 0x210!) and happily 
insert it into the block for 0x410.

From what you say, this is not the desired behavior? If we wanted two instances 
of the variable (one for each block), we could change the DIE-to-variable cache 

 to be indexed by a pair .

I have validated this with a simple example below, after adding printing of the 
variable address (var_sp.get()) at its creation point 


[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-09-30 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 376124.
jarin marked an inline comment as done.
jarin added a comment.

Improved the comment, as Greg suggested.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110571/new/

https://reviews.llvm.org/D110571

Files:
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
  lldb/test/API/functionalities/unused-inlined-parameters/Makefile
  
lldb/test/API/functionalities/unused-inlined-parameters/TestUnusedInlinedParameters.py
  lldb/test/API/functionalities/unused-inlined-parameters/main.c
  lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
  lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test

Index: lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
@@ -0,0 +1,49 @@
+# UNSUPPORTED: system-darwin, system-windows
+
+# RUN: llvm-mc -filetype=obj %S/Inputs/unused-inlined-params.s \
+# RUN: -triple x86_64-pc-linux -o %t.o
+# RUN: %lldb %t.o -s %s -o exit | FileCheck %s
+
+
+# In this test we verify that inlined functions still mention
+# all their parameters in `frame variable`, even when those
+# parameters were completely optimized away from the concrete
+# instance of the inlined function in the debug info.
+# The debugger should look up the parameters in the abstract
+# origin of the concrete instance.
+
+# Let us check that unused parameters of an inlined function are listed
+# at the inlined function entry.
+image lookup -v -s break_at_inlined_f_in_main
+# CHECK-LABEL: image lookup -v -s break_at_inlined_f_in_main
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_consts +42
+# CHECK: name = "unused2", type = "int", location = 
+# CHECK: name = "partial", type = "int", location = DW_OP_reg4 RSI
+# CHECK: name = "unused3", type = "int", location = 
+
+# Show variables outsid of the live range of the 'partial' parameter
+# and verify that the output is as expected.
+image lookup -v -s break_at_inlined_f_in_main_between_printfs
+# CHECK-LABEL: image lookup -v -s break_at_inlined_f_in_main_between_printfs
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_reg3 RBX
+# CHECK: name = "unused2", type = "int", location = 
+# Note: image lookup does not show variables outside of their
+#   location, so |partial| is missing here.
+# CHECK: name = "unused3", type = "int", location = 
+
+# Check that we show parameters even if all of them are compiled away.
+image lookup -v -s  break_at_inlined_g_in_main
+# CHECK-LABEL: image lookup -v -s  break_at_inlined_g_in_main
+# CHECK: name = "unused", type = "int", location = 
+
+# Check that even the other inlined instance of f displays the correct
+# parameters.
+image lookup -v -s  break_at_inlined_f_in_other
+# CHECK-LABEL: image lookup -v -s  break_at_inlined_f_in_other
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_consts +1
+# CHECK: name = "unused2", type = "int", location = 
+# CHECK: name = "partial", type = "int", location =  DW_OP_consts +2
+# CHECK: name = "unused3", type = "int", location = 
\ No newline at end of file
Index: lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
@@ -0,0 +1,458 @@
+# The below program is roughly derived from the following C program.
+# To see the annotated debug info, look for the section 
+# '.section.debug_info' below.
+#
+# __attribute__((always_inline))
+# void f(void* unused1, int used, int unused2, int partial, int unused3) {
+#   used += partial;
+#   printf("f %i", partial);
+#   printf("f %i", used);   // |partial| is not live at this line.
+# }
+#
+# void g(int unused) {
+#   printf("Hello");
+# }
+#
+# __attribute__((noinline))
+# void other() {
+#   f(nullptr, 1, 0, 2, 0);
+# }
+#
+# int main(int argc, char** argv) {
+#   f(argv, 42, 1, argc, 2);
+#   g(1);
+#   other();
+#   return 0;
+# }
+
+.text
+.file"unused-inlined-params.c"
+
+.Lcu_begin:
+
+.globlother
+other:
+nop
+.Linlined_f_in_other:
+break_at_inlined_f_in_other:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_in_other_between_printfs:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_in_other_end:
+retq
+.Lother_end:
+.sizeother, .Lother_end-other
+
+.globlmain
+main:
+.file1 "/example" "unused-inlined-params.c"
+movl$1, %esi
+.Linlined_f:
+break_at_inlined_f_in_main:
+leal42(%rsi), %ebx
+.Linlined_f_before_printf:
+callqprintf   

[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-09-30 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

In D110571#3033078 , @labath wrote:

> Here's one more question. AIUI, lldb relies on the order of formal parameter 
> declarations in dwarf to establish the the function signature (dwarf doesn't 
> leave us much choice. This then affects how the function is printed in the 
> backtrace, for instance. What will be the resulting order of arguments for 
> these functions? I'm wondering if we don't need a two-pass algorithm, which 
> first parses the arguments in the function declaration (to establish their 
> order), and then do another pass over the concrete instance to fill in the 
> missing information. (I'm sorry if you're doing this already, but I'm still 
> too scared of the code to figure it out myself :P ).

The code already does the merging. For DW_TAG_inlined_subroutine, it first 
collects the formal_parameter list from from its abstract_origin and then it 
will parse/insert all the missing one while parsing the concrete instance. This 
will preserve the order of formal parameters. Now that I think about this, it 
might add some formal parameters after local variables, but I hope this is not 
a real problem for LLDB. If this is a problem, we could perhaps flush the 
abstract formal parameters whenever we encounter DW_TAG_variable.

> In D110571#3032599 , @jarin wrote:
>
>> From what you say, this is not the desired behavior? If we wanted two 
>> instances of the variable (one for each block), we could change the 
>> DIE-to-variable cache 
>> 
>>  to be indexed by a pair .
>
> Given that was Greg's (and yours, kinda) reaction as well. I guess we should 
> do something like that. Even if it does not cause problems now, it could 
> certainly cause them in the future, if something starts relying on the 
> symbol_context_scope link making sense.
>
> I am wondering about the best way to implement in though. Having a pair as a 
> key seems very redundant to me. As we already know the block its going to end 
> up in maybe we could somehow check if its already present there? Since 
> blocks/functions don't generally have that many variables [citation needed], 
> maybe even a simple iteration would suffice? (The situation is probably 
> different for global variables, but those don't need the extra key.)

Are you worried about code redundancy or memory redundancy? I do not think a 
pair would be much extra code. If you are worried about memory, we could also 
have a separate map for the abstract parameters - we always know whether we are 
inserting an abstract parameter or a concrete one. (I did not quite understand 
the idea with block lookup/iteration.)

An interesting question is whether the caching is needed at all in the context 
of functions - even without the cache, we should not parse block variables 
multiple times because the variables are already cached in their block's 
variable list. I actually verified that the cache never hits for function 
scoped variables on the LLDB test suite (with and without this patch). It does 
hit for global variables, but they take a different path now. So how would you 
feel about bypassing the cache when parsing in the function context? (I would 
basically move the caching code from SymbolFileDWARF::ParseVariableDIE to 
SymbolFileDWARF::ParseAndAppendGlobalVariable.)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110571/new/

https://reviews.llvm.org/D110571

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-09-30 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 376235.
jarin marked an inline comment as done.
jarin added a comment.

Cache only global variables.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110571/new/

https://reviews.llvm.org/D110571

Files:
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
  lldb/test/API/functionalities/unused-inlined-parameters/Makefile
  
lldb/test/API/functionalities/unused-inlined-parameters/TestUnusedInlinedParameters.py
  lldb/test/API/functionalities/unused-inlined-parameters/main.c
  lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
  lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test

Index: lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
@@ -0,0 +1,49 @@
+# UNSUPPORTED: system-darwin, system-windows
+
+# RUN: llvm-mc -filetype=obj %S/Inputs/unused-inlined-params.s \
+# RUN: -triple x86_64-pc-linux -o %t.o
+# RUN: %lldb %t.o -s %s -o exit | FileCheck %s
+
+
+# In this test we verify that inlined functions still mention
+# all their parameters in `frame variable`, even when those
+# parameters were completely optimized away from the concrete
+# instance of the inlined function in the debug info.
+# The debugger should look up the parameters in the abstract
+# origin of the concrete instance.
+
+# Let us check that unused parameters of an inlined function are listed
+# at the inlined function entry.
+image lookup -v -s break_at_inlined_f_in_main
+# CHECK-LABEL: image lookup -v -s break_at_inlined_f_in_main
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_consts +42
+# CHECK: name = "unused2", type = "int", location = 
+# CHECK: name = "partial", type = "int", location = DW_OP_reg4 RSI
+# CHECK: name = "unused3", type = "int", location = 
+
+# Show variables outsid of the live range of the 'partial' parameter
+# and verify that the output is as expected.
+image lookup -v -s break_at_inlined_f_in_main_between_printfs
+# CHECK-LABEL: image lookup -v -s break_at_inlined_f_in_main_between_printfs
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_reg3 RBX
+# CHECK: name = "unused2", type = "int", location = 
+# Note: image lookup does not show variables outside of their
+#   location, so |partial| is missing here.
+# CHECK: name = "unused3", type = "int", location = 
+
+# Check that we show parameters even if all of them are compiled away.
+image lookup -v -s  break_at_inlined_g_in_main
+# CHECK-LABEL: image lookup -v -s  break_at_inlined_g_in_main
+# CHECK: name = "unused", type = "int", location = 
+
+# Check that even the other inlined instance of f displays the correct
+# parameters.
+image lookup -v -s  break_at_inlined_f_in_other
+# CHECK-LABEL: image lookup -v -s  break_at_inlined_f_in_other
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_consts +1
+# CHECK: name = "unused2", type = "int", location = 
+# CHECK: name = "partial", type = "int", location =  DW_OP_consts +2
+# CHECK: name = "unused3", type = "int", location = 
\ No newline at end of file
Index: lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
@@ -0,0 +1,458 @@
+# The below program is roughly derived from the following C program.
+# To see the annotated debug info, look for the section 
+# '.section.debug_info' below.
+#
+# __attribute__((always_inline))
+# void f(void* unused1, int used, int unused2, int partial, int unused3) {
+#   used += partial;
+#   printf("f %i", partial);
+#   printf("f %i", used);   // |partial| is not live at this line.
+# }
+#
+# void g(int unused) {
+#   printf("Hello");
+# }
+#
+# __attribute__((noinline))
+# void other() {
+#   f(nullptr, 1, 0, 2, 0);
+# }
+#
+# int main(int argc, char** argv) {
+#   f(argv, 42, 1, argc, 2);
+#   g(1);
+#   other();
+#   return 0;
+# }
+
+.text
+.file"unused-inlined-params.c"
+
+.Lcu_begin:
+
+.globlother
+other:
+nop
+.Linlined_f_in_other:
+break_at_inlined_f_in_other:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_in_other_between_printfs:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_in_other_end:
+retq
+.Lother_end:
+.sizeother, .Lother_end-other
+
+.globlmain
+main:
+.file1 "/example" "unused-inlined-params.c"
+movl$1, %esi
+.Linlined_f:
+break_at_inlined_f_in_main:
+leal42(%rsi), %ebx
+.Linlined_f_before_printf:
+callqprintf# Omitted t

[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-10-01 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

In D110571#3033481 , @labath wrote:

> In D110571#3033282 , @jarin wrote:
>
>> In D110571#3033078 , @labath wrote:
>>
>>> Here's one more question. AIUI, lldb relies on the order of formal 
>>> parameter declarations in dwarf to establish the the function signature 
>>> (dwarf doesn't leave us much choice. This then affects how the function is 
>>> printed in the backtrace, for instance. What will be the resulting order of 
>>> arguments for these functions? I'm wondering if we don't need a two-pass 
>>> algorithm, which first parses the arguments in the function declaration (to 
>>> establish their order), and then do another pass over the concrete instance 
>>> to fill in the missing information. (I'm sorry if you're doing this 
>>> already, but I'm still too scared of the code to figure it out myself :P ).
>>
>> The code already does the merging. For DW_TAG_inlined_subroutine, it first 
>> collects the formal_parameter list from from its abstract_origin and then it 
>> will parse/insert all the missing one while parsing the concrete instance. 
>> This will preserve the order of formal parameters. Now that I think about 
>> this, it might add some formal parameters after local variables, but I hope 
>> this is not a real problem for LLDB. If this is a problem, we could perhaps 
>> flush the abstract formal parameters whenever we encounter DW_TAG_variable.
>
> Cool. I see you're way ahead of me. If you're not careful you may end up as 
> the dwarf maintainer. :P

Pavel, it is unfortunately really the case that with the current patch, the 
parameters might get interleaved with locals:

  #include 
  
  void f(int used, int unused) {
int local = 1 + used;
printf("Hello %i", local); // break here
  }
  
  int main() {
f(4, 3);
return 0;
  }

Here is the LLDB session:

  $ bin/lldb a.out
  ...
  (lldb) b f
  Breakpoint 1: 2 locations.
  (lldb) r
  ...
  * thread #1, name = 'a.out', stop reason = breakpoint 1.2
  frame #0: 0x00401151 a.out`main [inlined] f(used=4, 
unused=) at a.cc:5:3
  (lldb) frame var
  (int) used = 4
  (int) local = 5  <--- HERE, a local variables got between the parameters 
because we append unused parameters at the end.
  (int) unused = 

Let me try to rewrite the code so that the trailing unused parameters are 
inserted after the last concrete parameter (or at the beginning of variable 
list if there are no concrete parameters). Let me know if you think it is 
unnecessary.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110571/new/

https://reviews.llvm.org/D110571

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-10-01 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 376501.
jarin marked 5 inline comments as done.
jarin added a comment.

Addressed reviewer comments, separated merging of the abstract parameters into 
a function, prevented interleaving of parameters with locals.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110571/new/

https://reviews.llvm.org/D110571

Files:
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
  lldb/test/API/functionalities/unused-inlined-parameters/Makefile
  
lldb/test/API/functionalities/unused-inlined-parameters/TestUnusedInlinedParameters.py
  lldb/test/API/functionalities/unused-inlined-parameters/main.c
  lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
  lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test

Index: lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
@@ -0,0 +1,48 @@
+# RUN: llvm-mc -filetype=obj %S/Inputs/unused-inlined-params.s \
+# RUN: -triple x86_64-pc-linux -o %t.o
+# RUN: %lldb %t.o -s %s -o exit | FileCheck %s
+
+
+# In this test we verify that inlined functions still mention
+# all their parameters in `frame variable`, even when those
+# parameters were completely optimized away from the concrete
+# instance of the inlined function in the debug info.
+# The debugger should look up the parameters in the abstract
+# origin of the concrete instance.
+
+# Let us check that unused parameters of an inlined function are listed
+# at the inlined function entry.
+image lookup -v -s break_at_inlined_f_in_main
+# CHECK-LABEL: image lookup -v -s break_at_inlined_f_in_main
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_consts +42
+# CHECK: name = "unused2", type = "int", location = 
+# CHECK: name = "partial", type = "int", location = DW_OP_reg4 RSI
+# CHECK: name = "unused3", type = "int", location = 
+
+# Show variables outsid of the live range of the 'partial' parameter
+# and verify that the output is as expected.
+image lookup -v -s break_at_inlined_f_in_main_between_printfs
+# CHECK-LABEL: image lookup -v -s break_at_inlined_f_in_main_between_printfs
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_reg3 RBX
+# CHECK: name = "unused2", type = "int", location = 
+# Note: image lookup does not show variables outside of their
+#   location, so |partial| is missing here.
+# CHECK-NOT: partial
+# CHECK: name = "unused3", type = "int", location = 
+
+# Check that we show parameters even if all of them are compiled away.
+image lookup -v -s  break_at_inlined_g_in_main
+# CHECK-LABEL: image lookup -v -s  break_at_inlined_g_in_main
+# CHECK: name = "unused", type = "int", location = 
+
+# Check that even the other inlined instance of f displays the correct
+# parameters.
+image lookup -v -s  break_at_inlined_f_in_other
+# CHECK-LABEL: image lookup -v -s  break_at_inlined_f_in_other
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_consts +1
+# CHECK: name = "unused2", type = "int", location = 
+# CHECK: name = "partial", type = "int", location =  DW_OP_consts +2
+# CHECK: name = "unused3", type = "int", location = 
Index: lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
@@ -0,0 +1,458 @@
+# The below program is roughly derived from the following C program.
+# To see the annotated debug info, look for the section 
+# '.section.debug_info' below.
+#
+# __attribute__((always_inline))
+# void f(void* unused1, int used, int unused2, int partial, int unused3) {
+#   used += partial;
+#   printf("f %i", partial);
+#   printf("f %i", used);   // |partial| is not live at this line.
+# }
+#
+# void g(int unused) {
+#   printf("Hello");
+# }
+#
+# __attribute__((noinline))
+# void other() {
+#   f(nullptr, 1, 0, 2, 0);
+# }
+#
+# int main(int argc, char** argv) {
+#   f(argv, 42, 1, argc, 2);
+#   g(1);
+#   other();
+#   return 0;
+# }
+
+.text
+.file"unused-inlined-params.c"
+
+.Lcu_begin:
+
+.globlother
+other:
+nop
+.Linlined_f_in_other:
+break_at_inlined_f_in_other:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_in_other_between_printfs:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_in_other_end:
+retq
+.Lother_end:
+.sizeother, .Lother_end-other
+
+.globlmain
+main:
+.file1 "/example" "unused-inlined-params.c"
+movl$1, %esi
+.Linlined_f:
+break_at_inlined_f_in_main:
+leal42(%rsi), %ebx
+.Linlined_f_before_printf:
+callqprint

[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-10-01 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Thank you for the great comments, Pavel. I took a stab at merging the 
parameters without interleaving them with the locals. Let me know what you 
think; I can certainly put this back to the original state if you think this is 
a change for the worse.

(I am sorry for the churn, but I feel the code is fairly subtle and would like 
to leave it in a state we are all happy with.)




Comment at: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp:3561-3562
+const lldb::addr_t func_low_pc, VariableList &variable_list,
+llvm::SmallVectorImpl &abstract_formal_parameters,
+size_t &abstract_parameter_index) {
   size_t vars_added = 0;

labath wrote:
> I'm wondering if one could pass a single `ArrayRef &` argument 
> instead of the array+index pair. FWICS, you're processing the list in a 
> left-to-right fashion, which seems ideal for `ArrayRef::drop_front`. WDYT?
I have replaced the in place-merging with a separate merging function, so this 
should not be relevant anymore.



Comment at: 
lldb/test/API/functionalities/unused-inlined-parameters/TestUnusedInlinedParameters.py:17
+
+# For the unused parameters, only check the types.
+self.assertEqual("void *", 
self.frame().FindVariable("unused1").GetType().GetName())

labath wrote:
> Maybe we could check something else as well... Do `GetDescription` or 
> `str(value)` return something reasonable here?
Actually, the most important thing is the type here, so this was quite 
deliberate.

GetDescription returns `(void *) unused1 = \n\n`, but I am not sure if we can safely require that all future 
versions/platforms optimize the parameter out.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110571/new/

https://reviews.llvm.org/D110571

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-10-04 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 377020.
jarin marked 4 inline comments as done.
jarin added a comment.

Addressed Pavel's comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110571/new/

https://reviews.llvm.org/D110571

Files:
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
  lldb/test/API/functionalities/unused-inlined-parameters/Makefile
  
lldb/test/API/functionalities/unused-inlined-parameters/TestUnusedInlinedParameters.py
  lldb/test/API/functionalities/unused-inlined-parameters/main.c
  lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
  lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test

Index: lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
@@ -0,0 +1,48 @@
+# RUN: llvm-mc -filetype=obj %S/Inputs/unused-inlined-params.s \
+# RUN: -triple x86_64-pc-linux -o %t.o
+# RUN: %lldb %t.o -s %s -o exit | FileCheck %s
+
+
+# In this test we verify that inlined functions still mention
+# all their parameters in `frame variable`, even when those
+# parameters were completely optimized away from the concrete
+# instance of the inlined function in the debug info.
+# The debugger should look up the parameters in the abstract
+# origin of the concrete instance.
+
+# Let us check that unused parameters of an inlined function are listed
+# at the inlined function entry.
+image lookup -v -s break_at_inlined_f_in_main
+# CHECK-LABEL: image lookup -v -s break_at_inlined_f_in_main
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_consts +42
+# CHECK: name = "unused2", type = "int", location = 
+# CHECK: name = "partial", type = "int", location = DW_OP_reg4 RSI
+# CHECK: name = "unused3", type = "int", location = 
+
+# Show variables outsid of the live range of the 'partial' parameter
+# and verify that the output is as expected.
+image lookup -v -s break_at_inlined_f_in_main_between_printfs
+# CHECK-LABEL: image lookup -v -s break_at_inlined_f_in_main_between_printfs
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_reg3 RBX
+# CHECK: name = "unused2", type = "int", location = 
+# Note: image lookup does not show variables outside of their
+#   location, so |partial| is missing here.
+# CHECK-NOT: partial
+# CHECK: name = "unused3", type = "int", location = 
+
+# Check that we show parameters even if all of them are compiled away.
+image lookup -v -s  break_at_inlined_g_in_main
+# CHECK-LABEL: image lookup -v -s  break_at_inlined_g_in_main
+# CHECK: name = "unused", type = "int", location = 
+
+# Check that even the other inlined instance of f displays the correct
+# parameters.
+image lookup -v -s  break_at_inlined_f_in_other
+# CHECK-LABEL: image lookup -v -s  break_at_inlined_f_in_other
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_consts +1
+# CHECK: name = "unused2", type = "int", location = 
+# CHECK: name = "partial", type = "int", location =  DW_OP_consts +2
+# CHECK: name = "unused3", type = "int", location = 
Index: lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
@@ -0,0 +1,458 @@
+# The below program is roughly derived from the following C program.
+# To see the annotated debug info, look for the section 
+# '.section.debug_info' below.
+#
+# __attribute__((always_inline))
+# void f(void* unused1, int used, int unused2, int partial, int unused3) {
+#   used += partial;
+#   printf("f %i", partial);
+#   printf("f %i", used);   // |partial| is not live at this line.
+# }
+#
+# void g(int unused) {
+#   printf("Hello");
+# }
+#
+# __attribute__((noinline))
+# void other() {
+#   f(nullptr, 1, 0, 2, 0);
+# }
+#
+# int main(int argc, char** argv) {
+#   f(argv, 42, 1, argc, 2);
+#   g(1);
+#   other();
+#   return 0;
+# }
+
+.text
+.file"unused-inlined-params.c"
+
+.Lcu_begin:
+
+.globlother
+other:
+nop
+.Linlined_f_in_other:
+break_at_inlined_f_in_other:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_in_other_between_printfs:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_in_other_end:
+retq
+.Lother_end:
+.sizeother, .Lother_end-other
+
+.globlmain
+main:
+.file1 "/example" "unused-inlined-params.c"
+movl$1, %esi
+.Linlined_f:
+break_at_inlined_f_in_main:
+leal42(%rsi), %ebx
+.Linlined_f_before_printf:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_between_printfs:
+b

[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-10-04 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added inline comments.



Comment at: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp:3545
+
+DIEVector MergeBlockAbstractParameters(const DWARFDIE &block_die,
+   DIEVector &&variable_dies) {

labath wrote:
> In llvm, we prefer `static` functions over anonymous namespaces. 
> Theoretically, you could keep the anonymous namespace around the using 
> declaration (per 
> , as those 
> can't use `static`), though I would actually probably prefer  DIEArray type 
> defined in DIERef.h over a custom type.
Changed to static function, DIEArray (interestingly, this file actually starts 
with anonymous namespace, see line 121).



Comment at: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h:403
+  const llvm::SmallVectorImpl &variable_dies,
+  const lldb::addr_t func_low_pc);
 

labath wrote:
> We generally do not put a const qualifier on by-value arguments (it's pretty 
> useless).
> 
> (I see it's present on other functions too, but I don't know if they were 
> introduced by you or you're just propagating them.)
Copy pasta, unfortunately.



Comment at: 
lldb/test/API/functionalities/unused-inlined-parameters/TestUnusedInlinedParameters.py:17
+
+# For the unused parameters, only check the types.
+self.assertEqual("void *", 
self.frame().FindVariable("unused1").GetType().GetName())

labath wrote:
> jarin wrote:
> > labath wrote:
> > > Maybe we could check something else as well... Do `GetDescription` or 
> > > `str(value)` return something reasonable here?
> > Actually, the most important thing is the type here, so this was quite 
> > deliberate.
> > 
> > GetDescription returns `(void *) unused1 =  > been optimized out>\n\n`, but I am not sure if we can safely require that 
> > all future versions/platforms optimize the parameter out.
> I don't feel strongly about it, but I would say that this function is so 
> simple than any optimizer worthy of that name should be able to optimize 
> those arguments away. I might replace printf with a `noinline`/`optnone` 
> function though, to avoid any libc shenanigans.
I do not feel too strongly about this eiher.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110571/new/

https://reviews.llvm.org/D110571

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D110570: [lldb] Refactor variable parsing in DWARF symbol file

2021-10-06 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 377474.
jarin marked 2 inline comments as done.
jarin added a comment.

Avoid nullptr deref/ref.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110570/new/

https://reviews.llvm.org/D110570

Files:
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h

Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
===
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -378,11 +378,19 @@
 const DWARFDIE &die,
 const lldb::addr_t func_low_pc);
 
-  size_t ParseVariables(const lldb_private::SymbolContext &sc,
-const DWARFDIE &orig_die,
-const lldb::addr_t func_low_pc, bool parse_siblings,
-bool parse_children,
-lldb_private::VariableList *cc_variable_list = nullptr);
+  void
+  ParseAndAppendGlobalVariable(const lldb_private::SymbolContext &sc,
+   const DWARFDIE &die,
+   lldb_private::VariableList &cc_variable_list);
+
+  size_t ParseVariablesInFunctionContext(const lldb_private::SymbolContext &sc,
+ const DWARFDIE &die,
+ const lldb::addr_t func_low_pc);
+
+  size_t ParseVariablesInFunctionContextRecursive(
+  const lldb_private::SymbolContext &sc, const DWARFDIE &die,
+  const lldb::addr_t func_low_pc,
+  lldb_private::VariableList &variable_list);
 
   bool ClassOrStructIsVirtual(const DWARFDIE &die);
 
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2135,7 +2135,7 @@
   }
 }
 
-ParseVariables(sc, die, LLDB_INVALID_ADDRESS, false, false, &variables);
+ParseAndAppendGlobalVariable(sc, die, variables);
 while (pruned_idx < variables.GetSize()) {
   VariableSP var_sp = variables.GetVariableAtIndex(pruned_idx);
   if (name_is_mangled ||
@@ -2188,7 +2188,7 @@
   return true;
 sc.comp_unit = GetCompUnitForDWARFCompUnit(*dwarf_cu);
 
-ParseVariables(sc, die, LLDB_INVALID_ADDRESS, false, false, &variables);
+ParseAndAppendGlobalVariable(sc, die, variables);
 
 return variables.GetSize() - original_size < max_matches;
   });
@@ -3049,8 +3049,8 @@
   /*check_hi_lo_pc=*/true))
 func_lo_pc = ranges.GetMinRangeBase(0);
   if (func_lo_pc != LLDB_INVALID_ADDRESS) {
-const size_t num_variables = ParseVariables(
-sc, function_die.GetFirstChild(), func_lo_pc, true, true);
+const size_t num_variables =
+ParseVariablesInFunctionContext(sc, function_die, func_lo_pc);
 
 // Let all blocks know they have parse all their variables
 sc.function->GetBlock(false).SetDidParseVariables(true, true);
@@ -3479,117 +3479,136 @@
   return DWARFDIE();
 }
 
-size_t SymbolFileDWARF::ParseVariables(const SymbolContext &sc,
-   const DWARFDIE &orig_die,
-   const lldb::addr_t func_low_pc,
-   bool parse_siblings, bool parse_children,
-   VariableList *cc_variable_list) {
-  if (!orig_die)
-return 0;
+void SymbolFileDWARF::ParseAndAppendGlobalVariable(
+const SymbolContext &sc, const DWARFDIE &die,
+VariableList &cc_variable_list) {
+  if (!die)
+return;
 
+  dw_tag_t tag = die.Tag();
+  if (tag != DW_TAG_variable && tag != DW_TAG_constant)
+return;
+
+  // Check to see if we have already parsed this variable or constant?
+  VariableSP var_sp = GetDIEToVariable()[die.GetDIE()];
+  if (var_sp) {
+cc_variable_list.AddVariableIfUnique(var_sp);
+return;
+  }
+
+  // We haven't already parsed it, lets do that now.
   VariableListSP variable_list_sp;
+  DWARFDIE sc_parent_die = GetParentSymbolContextDIE(die);
+  dw_tag_t parent_tag = sc_parent_die.Tag();
+  switch (parent_tag) {
+  case DW_TAG_compile_unit:
+  case DW_TAG_partial_unit:
+if (sc.comp_unit != nullptr) {
+  variable_list_sp = sc.comp_unit->GetVariableList(false);
+} else {
+  GetObjectFile()->GetModule()->ReportError(
+  "parent 0x%8.8" PRIx64 " %s with no valid compile unit in "
+  "symbol context for 0x%8.8" PRIx64 " %s.\n",
+  sc_parent_die.GetID(), sc_parent_die.GetTagAsCString(), die.GetID(),
+  die.GetTagAsCString());
+  return;
+}
+break;
+
+  default:
+GetObjectFile()->GetModule()->ReportError(
+"didn't find appropriate parent DIE for variable list for "
+   

[Lldb-commits] [PATCH] D110570: [lldb] Refactor variable parsing in DWARF symbol file

2021-10-06 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Pavel, could you take another look? Interestingly the null-deref problem was 
already fixed in the follow-up patch , maybe 
I just did not land quickly enough :-)).


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110570/new/

https://reviews.llvm.org/D110570

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D110571: [lldb] Add omitted abstract formal parameters in DWARF symbol files

2021-10-21 Thread Jaroslav Sevcik via Phabricator via lldb-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG5a3556aa5563: [lldb] Add omitted abstract formal parameters 
in DWARF symbol files (authored by Jaroslav Sevcik , 
committed by jarin).

Changed prior to commit:
  https://reviews.llvm.org/D110571?vs=377020&id=381197#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110571/new/

https://reviews.llvm.org/D110571

Files:
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
  lldb/test/API/functionalities/unused-inlined-parameters/Makefile
  
lldb/test/API/functionalities/unused-inlined-parameters/TestUnusedInlinedParameters.py
  lldb/test/API/functionalities/unused-inlined-parameters/main.c
  lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
  lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test

Index: lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/unused-inlined-params.test
@@ -0,0 +1,48 @@
+# RUN: llvm-mc -filetype=obj %S/Inputs/unused-inlined-params.s \
+# RUN: -triple x86_64-pc-linux -o %t.o
+# RUN: %lldb %t.o -s %s -o exit | FileCheck %s
+
+
+# In this test we verify that inlined functions still mention
+# all their parameters in `frame variable`, even when those
+# parameters were completely optimized away from the concrete
+# instance of the inlined function in the debug info.
+# The debugger should look up the parameters in the abstract
+# origin of the concrete instance.
+
+# Let us check that unused parameters of an inlined function are listed
+# at the inlined function entry.
+image lookup -v -s break_at_inlined_f_in_main
+# CHECK-LABEL: image lookup -v -s break_at_inlined_f_in_main
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_consts +42
+# CHECK: name = "unused2", type = "int", location = 
+# CHECK: name = "partial", type = "int", location = DW_OP_reg4 RSI
+# CHECK: name = "unused3", type = "int", location = 
+
+# Show variables outsid of the live range of the 'partial' parameter
+# and verify that the output is as expected.
+image lookup -v -s break_at_inlined_f_in_main_between_printfs
+# CHECK-LABEL: image lookup -v -s break_at_inlined_f_in_main_between_printfs
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_reg3 RBX
+# CHECK: name = "unused2", type = "int", location = 
+# Note: image lookup does not show variables outside of their
+#   location, so |partial| is missing here.
+# CHECK-NOT: partial
+# CHECK: name = "unused3", type = "int", location = 
+
+# Check that we show parameters even if all of them are compiled away.
+image lookup -v -s  break_at_inlined_g_in_main
+# CHECK-LABEL: image lookup -v -s  break_at_inlined_g_in_main
+# CHECK: name = "unused", type = "int", location = 
+
+# Check that even the other inlined instance of f displays the correct
+# parameters.
+image lookup -v -s  break_at_inlined_f_in_other
+# CHECK-LABEL: image lookup -v -s  break_at_inlined_f_in_other
+# CHECK: name = "unused1", type = "void *", location = 
+# CHECK: name = "used", type = "int", location = DW_OP_consts +1
+# CHECK: name = "unused2", type = "int", location = 
+# CHECK: name = "partial", type = "int", location =  DW_OP_consts +2
+# CHECK: name = "unused3", type = "int", location = 
Index: lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
===
--- /dev/null
+++ lldb/test/Shell/SymbolFile/DWARF/x86/Inputs/unused-inlined-params.s
@@ -0,0 +1,458 @@
+# The below program is roughly derived from the following C program.
+# To see the annotated debug info, look for the section 
+# '.section.debug_info' below.
+#
+# __attribute__((always_inline))
+# void f(void* unused1, int used, int unused2, int partial, int unused3) {
+#   used += partial;
+#   printf("f %i", partial);
+#   printf("f %i", used);   // |partial| is not live at this line.
+# }
+#
+# void g(int unused) {
+#   printf("Hello");
+# }
+#
+# __attribute__((noinline))
+# void other() {
+#   f(nullptr, 1, 0, 2, 0);
+# }
+#
+# int main(int argc, char** argv) {
+#   f(argv, 42, 1, argc, 2);
+#   g(1);
+#   other();
+#   return 0;
+# }
+
+.text
+.file"unused-inlined-params.c"
+
+.Lcu_begin:
+
+.globlother
+other:
+nop
+.Linlined_f_in_other:
+break_at_inlined_f_in_other:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_in_other_between_printfs:
+callqprintf# Omitted the setup of arguments.
+.Linlined_f_in_other_end:
+retq
+.Lother_end:
+.sizeother, .Lother_end-other
+
+.globlmain
+main:
+.file1 "/example" "unused-inlined-params.c"
+movl$1, %

[Lldb-commits] [PATCH] D73191: Only match mangled name in full-name function lookup (with accelerators)

2021-08-04 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Thanks for getting back to this, Raphael!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D73191/new/

https://reviews.llvm.org/D73191

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D74398: [lldb-server] jThreadsInfo returns stack memory

2020-02-11 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin created this revision.
jarin added a reviewer: labath.
jarin added a project: LLDB.
Herald added a subscriber: lldb-commits.

This patch adds parts of the stack that should be useful for unwinding to the 
jThreadsInfo reply from lldb-server. We return the top of the stack (12 words), 
and we also try to walk the frame pointer linked list and return the memory 
containing frame pointer and return address pairs. The idea is to cover the 
cases with and without frame pointer omission.

Here are some questions:

- Does this approach sound reasonable?
- How do we test this?
- Is it fine if we do not handle the big-endian and 32-bit word cases? (There 
we will be basically never generate the frame list.)


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D74398

Files:
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp

Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
===
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -469,6 +469,118 @@
   return register_object;
 }
 
+static llvm::Expected
+GetRegisterValue(NativeRegisterContext ®_ctx, uint32_t generic_regnum) {
+  Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+  uint32_t reg_num = reg_ctx.ConvertRegisterKindToRegisterNumber(
+  eRegisterKindGeneric, generic_regnum);
+  const RegisterInfo *const reg_info_p =
+  reg_ctx.GetRegisterInfoAtIndex(reg_num);
+
+  if (reg_info_p == nullptr || reg_info_p->value_regs != nullptr) {
+LLDB_LOGF(log, "%s failed to get register info for register index %" PRIu32,
+  __FUNCTION__, reg_num);
+return llvm::make_error("failed to obtain register info",
+   llvm::inconvertibleErrorCode());
+  }
+
+  RegisterValue reg_value;
+  Status error = reg_ctx.ReadRegister(reg_info_p, reg_value);
+  if (error.Fail()) {
+LLDB_LOGF(log, "%s failed to read register '%s' index %" PRIu32 ": %s",
+  __FUNCTION__,
+  reg_info_p->name ? reg_info_p->name : "",
+  reg_num, error.AsCString());
+return llvm::make_error("failed to read register value",
+   llvm::inconvertibleErrorCode());
+  }
+  return reg_value;
+}
+
+static void AddMemoryChunk(json::Array &stack_memory_chunks, addr_t address,
+   std::vector &bytes) {
+  if (bytes.empty())
+return;
+  json::Object chunk;
+  chunk.try_emplace("address", static_cast(address));
+  StreamString stream;
+  for (int8_t b : bytes)
+stream.PutHex8(b);
+  chunk.try_emplace("bytes", stream.GetString().str());
+  stack_memory_chunks.push_back(std::move(chunk));
+}
+
+static json::Array GetStackMemoryAsJSON(NativeProcessProtocol &process,
+NativeThreadProtocol &thread) {
+  const size_t kStackTopMemoryInfoWordSize = 12;
+  const size_t kStackTopMemoryInfoByteSize =
+  kStackTopMemoryInfoWordSize * sizeof(addr_t);
+  const size_t kMaxStackSize = 128 * 1024;
+  const size_t kMaxFrameSize = 4 * 1024;
+  const size_t kFpAndRaSize = 2 * sizeof(addr_t);
+  const size_t kMaxFrameCount = 128;
+
+  NativeRegisterContext ®_ctx = thread.GetRegisterContext();
+
+  json::Array stack_memory_chunks;
+
+  lldb::addr_t sp_value;
+  if (llvm::Expected expected_sp_value =
+  GetRegisterValue(reg_ctx, LLDB_REGNUM_GENERIC_SP)) {
+sp_value = expected_sp_value->GetAsUInt64();
+  } else {
+return stack_memory_chunks;
+  }
+  lldb::addr_t fp_value;
+  if (llvm::Expected expected_fp_value =
+  GetRegisterValue(reg_ctx, LLDB_REGNUM_GENERIC_FP)) {
+fp_value = expected_fp_value->GetAsUInt64();
+  } else {
+return stack_memory_chunks;
+  }
+
+  // First, make sure we copy the top kStackTopMemoryInfoSize bytes from the
+  // stack.
+  size_t byte_count = std::min(kStackTopMemoryInfoByteSize,
+   static_cast(fp_value - sp_value));
+  std::vector buf(byte_count, 0);
+
+  size_t bytes_read = 0;
+  Status error = process.ReadMemoryWithoutTrap(sp_value, buf.data(), byte_count,
+   bytes_read);
+  if (error.Success() && bytes_read > 0) {
+buf.resize(bytes_read);
+AddMemoryChunk(stack_memory_chunks, sp_value, buf);
+  }
+
+  // Additionally, try to walk the frame pointer link chain. If the frame
+  // is too big or if the frame pointer points too far, stop the walk.
+  addr_t max_frame_pointer = sp_value + kMaxStackSize;
+  for (size_t i = 0; i < kMaxFrameCount; i++) {
+if (fp_value < sp_value || fp_value > sp_value + kMaxFrameSize ||
+fp_value > max_frame_pointer)
+  break;
+
+std::vector fp_ra_buf(kFpAndRaSize, 0);
+bytes_read = 0;
+error = process.ReadMemoryWithoutTrap(fp_value, fp_ra_buf.data(),
+

[Lldb-commits] [PATCH] D74398: [lldb-server] jThreadsInfo returns stack memory

2020-02-12 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Thank you for the feedback! I am a bit busy with other things ATM, but I should 
be able to get back to this next week.

I should give credit where it's due - Pavel pointed me to the debug-server code 
and I took the idea from there. We do not always have the frame pointer list, 
so I took the hybrid approach of copying the top stack section from each 
thread, too.

As for some preliminary numbers, with 8ms RTT we see thread list update time in 
our UI improve from 800ms to 250ms in an Unreal engine sample. I will get more 
numbers (packet sizes) when I hack on this again next week.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74398/new/

https://reviews.llvm.org/D74398



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D74217: Add target.xml support for qXfer request.

2020-02-17 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added inline comments.



Comment at: 
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp:465
+  response.PutChar(',');
+response.Printf("%" PRIx32, *reg_num);
+  }

I think this is not correct: target.xml expects this to be 
[decimal](https://github.com/llvm-mirror/lldb/blob/d01083a850f577b85501a0902b52fd0930de72c7/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp#L4417).
 (This is different from qRegisterInfo, which expects 
[hex](https://github.com/llvm-mirror/lldb/blob/d01083a850f577b85501a0902b52fd0930de72c7/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp#L579).)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74217/new/

https://reviews.llvm.org/D74217



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D74217: Add target.xml support for qXfer request.

2020-02-17 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added inline comments.



Comment at: 
lldb/packages/Python/lldbsuite/test/tools/lldb-server/registers-target-xml-reading/TestGdbRemoteTargetXmlPacket.py:69
+self.assertEqual(q_info_reg["offset"], xml_info_reg.get("offset"))
+self.assertEqual(q_info_reg["encoding"], 
xml_info_reg.get("encoding"))

Why don't you test all the fields here?



Comment at: 
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp:2814
+if (!encoding.empty())
+  response.Printf("encoding=\"%s\" ", encoding.str().c_str());
+

labath wrote:
> Similarly, `response << "encoding='" << encoding << "' "`, or 
> `response.Format("encoding='{0}'", encoding)` would be shorter, and avoid 
> string copying.
Nit: Now it is a funny mixture of operator<<, Printfs and PutCString. Is there 
a reason not to use << for everything? (I guess PutHex8 can't be easily done 
with <<, but everything else can?)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74217/new/

https://reviews.llvm.org/D74217



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D74217: Add target.xml support for qXfer request.

2020-02-17 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added inline comments.



Comment at: 
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp:2814
+
+if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) {
+  response.PutCString("invalidate_regnums=\"");

I know this is copy&paste from qRegisterInfo, but should not this be `if 
(reg_info->invalidate_regs && reg_info->invalidate_regs[0] != 
LLDB_INVALID_REGNUM)`?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74217/new/

https://reviews.llvm.org/D74217



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D74759: Treat RangeDataVector as an augmented BST

2020-02-18 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Thanks for putting this together, some comments below. Let us see what Pavel 
thinks.




Comment at: lldb/include/lldb/Utility/RangeMap.h:634
 
+  // We can treat the vector as a flattened BST, augmenting it with upper 
bounds (max of
+  // range endpoints) for every index allows us to query for intersections in 
O(log n) time.

BST -> binary search tree



Comment at: lldb/include/lldb/Utility/RangeMap.h:642
+  B ComputeUpperBounds(int lo, int hi) {
+if (lo > hi) return B();
+

Here, B() should be the min value of type B, no? Perhaps this should be 
`std::numeric_limits::min()` instead of `B()`?



Comment at: lldb/include/lldb/Utility/RangeMap.h:745
+  void FindEntryIndexesThatContain(B addr, int lo, int hi,
+   std::vector &indexes) {
+if (lo > hi) return;

Hmm, weird, I am surprised this is not `std::vector &indexes` (I realize 
this was in the code before).



Comment at: lldb/include/lldb/Utility/RangeMap.h:849
   Compare m_compare;
+  bool upper_bound_computed;
 };

I am guessing this should have the `m_` prefix?


Repository:
  rLLDB LLDB

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74759/new/

https://reviews.llvm.org/D74759



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D74759: Treat RangeDataVector as an augmented BST

2020-02-18 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

In D74759#1880499 , @labath wrote:

> I like this idea a lot, in principle. It is much simpler than a full blown 
> interval tree, and it should give us similar performance characteristics.
>
> Have you done a proper complexity analysis here? I doubt the `O(log n)` claim 
> is true in general. It would have to be at least `O(m + log n)` (m - number 
> of elements found), but it's not clear to me whether even this is true in 
> general. (However, I believe this can achieve ~~log(n) for non-degenerate 
> cases.)


Thanks for the feedback! We were aiming for something simple and efficient 
enough. Our preliminary results show that the lookup pretty much disappears 
even from the profiles it was dominating before.

The implementation is pretty much taken from the "Augmented tree" section of 
https://en.wikipedia.org/wiki/Interval_tree where we just use the tree induced 
by the pivots of the binary search as the binary search tree that we augment. I 
believe the complexity is O(m log n), even though the wikipedia article makes a 
O(m + log n) claim. This should be still much better than the current O(n) and 
the memory cost seems to be quite palatable (extra word per symbol).

> The implementation itself needs some work though. My incomplete list of 
> comments is:
> 
> - replace `int` with `size_t` and closed intervals with half-open ones
> - let's move the computation of the upper bound into the "Sort" function. 
> sorting is O(n log(n)), this is O(n) -- we can just hide it there.
> - make private functions private
> - we should avoid the business of figuring out what is the suitable "minimum" 
> value of B by ensuring we call the recursive function on non-empty intervals
> - clang-format the patch
> 
>   For testing you should add some c++ unit tests for the relevant interfaces.




Repository:
  rLLDB LLDB

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74759/new/

https://reviews.llvm.org/D74759



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D76216: Improve step over performance

2020-03-16 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin created this revision.
jarin added reviewers: clayborg, labath.
jarin added a project: LLDB.
Herald added a subscriber: lldb-commits.

This patch improves step over performance for the case when we are stepping 
over a call with a next-branch-breakpoint (see 
https://reviews.llvm.org/D58678), and we encounter a stop during the call. 
Currently, this causes the thread plan to step-out //each frame// until it 
reaches the step-over range. This is a regression introduced by 
https://reviews.llvm.org/D58678 (which did improve other things!). Prior to 
that change, the step-over plan would always step-out just once.

With this patch, if we find ourselves stopped in a deeper stack frame and we 
already have a next branch breakpoint, we simply return from the step-over 
plan's ShouldStop handler without pushing the step out plan.

In my experiments this improved the time of stepping over a call that loads 12 
dlls from 14s to 5s. This was in remote debugging scenario with 10ms RTT, the 
call in question was Vulkan initialization (vkCreateInstance), which loads 
various driver dlls. Loading those dlls must stop on the rendezvous breakpoint, 
causing the perf problem described above.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D76216

Files:
  lldb/source/Target/ThreadPlanStepOverRange.cpp


Index: lldb/source/Target/ThreadPlanStepOverRange.cpp
===
--- lldb/source/Target/ThreadPlanStepOverRange.cpp
+++ lldb/source/Target/ThreadPlanStepOverRange.cpp
@@ -171,6 +171,10 @@
   const SymbolContext &older_context =
   older_frame_sp->GetSymbolContext(eSymbolContextEverything);
   if (IsEquivalentContext(older_context)) {
+// If we have the next-branch-breakpoint in the range, we can just
+// rely on that breakpoint to trigger once we return to the range.
+if (m_next_branch_bp_sp)
+  return false;
 new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop(
 false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
 m_status, true);


Index: lldb/source/Target/ThreadPlanStepOverRange.cpp
===
--- lldb/source/Target/ThreadPlanStepOverRange.cpp
+++ lldb/source/Target/ThreadPlanStepOverRange.cpp
@@ -171,6 +171,10 @@
   const SymbolContext &older_context =
   older_frame_sp->GetSymbolContext(eSymbolContextEverything);
   if (IsEquivalentContext(older_context)) {
+// If we have the next-branch-breakpoint in the range, we can just
+// rely on that breakpoint to trigger once we return to the range.
+if (m_next_branch_bp_sp)
+  return false;
 new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop(
 false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
 m_status, true);
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D76216: Improve step over performance

2020-03-16 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin marked an inline comment as done.
jarin added inline comments.



Comment at: lldb/source/Target/ThreadPlanStepOverRange.cpp:176
+// rely on that breakpoint to trigger once we return to the range.
+if (m_next_branch_bp_sp)
+  return false;

We could do some more sanity checking here. 

For example, we could ensure that the return address is still before the next 
branch breakpoint, or, ideally, record the beginning of the next-branch range 
and check the return address is in that range. However, I am not quite sure 
what this would protect us against (mucking with the stack, perhaps?) and what 
to do if the check fail - falling back to the old behavior does not really seem 
to solve anything because that introduces even more noise by pushing all the 
step-out plans.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D76216/new/

https://reviews.llvm.org/D76216



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D76216: Improve step over performance

2020-03-17 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Thanks for all the clarifications, this is very useful. I have always wanted to 
learn about thread plans, and this was a nice opportunity to do that. The extra 
background from you guys is a nice bonus.

Regarding the patch itself, is there anything preventing an LGTM?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D76216/new/

https://reviews.llvm.org/D76216



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D74398: [lldb-server] jThreadsInfo returns stack memory

2020-03-17 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 250951.
jarin added a comment.

- Added a test that checks consistency of thread info's memory chunks with the 
actual memory.
- Using DataExtractor to extract pointers with the right endian-ness and the 
right size.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74398/new/

https://reviews.llvm.org/D74398

Files:
  
lldb/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteThreadsInStopReply.py
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp

Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
===
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -31,6 +31,7 @@
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Utility/Args.h"
 #include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/DataExtractor.h"
 #include "lldb/Utility/Endian.h"
 #include "lldb/Utility/LLDBAssert.h"
 #include "lldb/Utility/Log.h"
@@ -469,6 +470,119 @@
   return register_object;
 }
 
+static llvm::Expected
+GetRegisterValue(NativeRegisterContext ®_ctx, uint32_t generic_regnum) {
+  Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+  uint32_t reg_num = reg_ctx.ConvertRegisterKindToRegisterNumber(
+  eRegisterKindGeneric, generic_regnum);
+  const RegisterInfo *const reg_info_p =
+  reg_ctx.GetRegisterInfoAtIndex(reg_num);
+
+  if (reg_info_p == nullptr || reg_info_p->value_regs != nullptr) {
+LLDB_LOGF(log, "%s failed to get register info for register index %" PRIu32,
+  __FUNCTION__, reg_num);
+return llvm::make_error("failed to obtain register info",
+   llvm::inconvertibleErrorCode());
+  }
+
+  RegisterValue reg_value;
+  Status error = reg_ctx.ReadRegister(reg_info_p, reg_value);
+  if (error.Fail()) {
+LLDB_LOGF(log, "%s failed to read register '%s' index %" PRIu32 ": %s",
+  __FUNCTION__,
+  reg_info_p->name ? reg_info_p->name : "",
+  reg_num, error.AsCString());
+return llvm::make_error("failed to read register value",
+   llvm::inconvertibleErrorCode());
+  }
+  return reg_value;
+}
+
+static void AddMemoryChunk(json::Array &stack_memory_chunks, addr_t address,
+   std::vector &bytes) {
+  if (bytes.empty())
+return;
+  json::Object chunk;
+  chunk.try_emplace("address", static_cast(address));
+  StreamString stream;
+  for (int8_t b : bytes)
+stream.PutHex8(b);
+  chunk.try_emplace("bytes", stream.GetString().str());
+  stack_memory_chunks.push_back(std::move(chunk));
+}
+
+static json::Array GetStackMemoryAsJSON(NativeProcessProtocol &process,
+NativeThreadProtocol &thread) {
+  uint32_t address_size = process.GetArchitecture().GetAddressByteSize();
+  const size_t kStackTopMemoryInfoWordSize = 12;
+  size_t stack_top_memory_info_byte_size =
+  kStackTopMemoryInfoWordSize * address_size;
+  const size_t kMaxStackSize = 128 * 1024;
+  const size_t kMaxFrameSize = 4 * 1024;
+  size_t fp_and_ra_size = 2 * address_size;
+  const size_t kMaxFrameCount = 128;
+
+  NativeRegisterContext ®_ctx = thread.GetRegisterContext();
+
+  json::Array stack_memory_chunks;
+
+  lldb::addr_t sp_value;
+  if (llvm::Expected expected_sp_value =
+  GetRegisterValue(reg_ctx, LLDB_REGNUM_GENERIC_SP)) {
+sp_value = expected_sp_value->GetAsUInt64();
+  } else {
+return stack_memory_chunks;
+  }
+  lldb::addr_t fp_value;
+  if (llvm::Expected expected_fp_value =
+  GetRegisterValue(reg_ctx, LLDB_REGNUM_GENERIC_FP)) {
+fp_value = expected_fp_value->GetAsUInt64();
+  } else {
+return stack_memory_chunks;
+  }
+
+  // First, make sure we copy the top stack_top_memory_info_byte_size bytes
+  // from the stack.
+  size_t byte_count = std::min(stack_top_memory_info_byte_size,
+   static_cast(fp_value - sp_value));
+  std::vector buf(byte_count, 0);
+
+  size_t bytes_read = 0;
+  Status error = process.ReadMemoryWithoutTrap(sp_value, buf.data(), byte_count,
+   bytes_read);
+  if (error.Success() && bytes_read > 0) {
+buf.resize(bytes_read);
+AddMemoryChunk(stack_memory_chunks, sp_value, buf);
+  }
+
+  // Additionally, try to walk the frame pointer link chain. If the frame
+  // is too big or if the frame pointer points too far, stop the walk.
+  addr_t max_frame_pointer = sp_value + kMaxStackSize;
+  for (size_t i = 0; i < kMaxFrameCount; i++) {
+if (fp_value < sp_value || fp_value > sp_value + kMaxFrameSize ||
+fp_value > max_frame_pointer)
+  break;
+
+std::vector fp_ra_buf(fp_and_ra_size, 0);
+bytes_read = 0;
+error = process.ReadMemoryWithou

[Lldb-commits] [PATCH] D74398: [lldb-server] jThreadsInfo returns stack memory

2020-03-18 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 251181.
jarin marked 5 inline comments as done.
jarin added a comment.

Addressed reviewer comments in the code, but still have no clue how to write 
the test.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74398/new/

https://reviews.llvm.org/D74398

Files:
  
lldb/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteThreadsInStopReply.py
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp

Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
===
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -31,6 +31,7 @@
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Utility/Args.h"
 #include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/DataExtractor.h"
 #include "lldb/Utility/Endian.h"
 #include "lldb/Utility/LLDBAssert.h"
 #include "lldb/Utility/Log.h"
@@ -469,6 +470,119 @@
   return register_object;
 }
 
+static llvm::Optional
+GetRegisterValue(NativeRegisterContext ®_ctx, uint32_t generic_regnum) {
+  Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+  uint32_t reg_num = reg_ctx.ConvertRegisterKindToRegisterNumber(
+  eRegisterKindGeneric, generic_regnum);
+  const RegisterInfo *const reg_info_p =
+  reg_ctx.GetRegisterInfoAtIndex(reg_num);
+
+  if (reg_info_p == nullptr || reg_info_p->value_regs != nullptr) {
+LLDB_LOGF(log, "%s failed to get register info for register index %" PRIu32,
+  __FUNCTION__, reg_num);
+return {};
+  }
+
+  RegisterValue reg_value;
+  Status error = reg_ctx.ReadRegister(reg_info_p, reg_value);
+  if (error.Fail()) {
+LLDB_LOGF(log, "%s failed to read register '%s' index %" PRIu32 ": %s",
+  __FUNCTION__,
+  reg_info_p->name ? reg_info_p->name : "",
+  reg_num, error.AsCString());
+return {};
+  }
+  return reg_value;
+}
+
+static json::Object CreateMemoryChunk(json::Array &stack_memory_chunks,
+  addr_t address,
+  std::vector &bytes) {
+  json::Object chunk;
+  chunk.try_emplace("address", static_cast(address));
+  StreamString stream;
+  for (uint8_t b : bytes)
+stream.PutHex8(b);
+  chunk.try_emplace("bytes", stream.GetString().str());
+  return chunk;
+}
+
+static json::Array GetStackMemoryAsJSON(NativeProcessProtocol &process,
+NativeThreadProtocol &thread) {
+  uint32_t address_size = process.GetArchitecture().GetAddressByteSize();
+  const size_t kStackTopMemoryInfoWordSize = 12;
+  size_t stack_top_memory_info_byte_size =
+  kStackTopMemoryInfoWordSize * address_size;
+  const size_t kMaxStackSize = 128 * 1024;
+  const size_t kMaxFrameSize = 4 * 1024;
+  size_t fp_and_ra_size = 2 * address_size;
+  const size_t kMaxFrameCount = 128;
+
+  NativeRegisterContext ®_ctx = thread.GetRegisterContext();
+
+  json::Array stack_memory_chunks;
+
+  lldb::addr_t sp_value;
+  if (llvm::Optional optional_sp_value =
+  GetRegisterValue(reg_ctx, LLDB_REGNUM_GENERIC_SP)) {
+sp_value = optional_sp_value->GetAsUInt64();
+  } else {
+return stack_memory_chunks;
+  }
+  lldb::addr_t fp_value;
+  if (llvm::Optional optional_fp_value =
+  GetRegisterValue(reg_ctx, LLDB_REGNUM_GENERIC_FP)) {
+fp_value = optional_fp_value->GetAsUInt64();
+  } else {
+return stack_memory_chunks;
+  }
+
+  // First, make sure we copy the top stack_top_memory_info_byte_size bytes
+  // from the stack.
+  size_t byte_count = std::min(stack_top_memory_info_byte_size,
+   static_cast(fp_value - sp_value));
+  std::vector buf(byte_count, 0);
+
+  size_t bytes_read = 0;
+  Status error = process.ReadMemoryWithoutTrap(sp_value, buf.data(), byte_count,
+   bytes_read);
+  if (error.Success() && bytes_read > 0) {
+buf.resize(bytes_read);
+stack_memory_chunks.push_back(
+std::move(CreateMemoryChunk(stack_memory_chunks, sp_value, buf)));
+  }
+
+  // Additionally, try to walk the frame pointer link chain. If the frame
+  // is too big or if the frame pointer points too far, stop the walk.
+  addr_t max_frame_pointer = sp_value + kMaxStackSize;
+  for (size_t i = 0; i < kMaxFrameCount; i++) {
+if (fp_value < sp_value || fp_value > sp_value + kMaxFrameSize ||
+fp_value > max_frame_pointer)
+  break;
+
+std::vector fp_ra_buf(fp_and_ra_size, 0);
+bytes_read = 0;
+error = process.ReadMemoryWithoutTrap(fp_value, fp_ra_buf.data(),
+  fp_and_ra_size, bytes_read);
+if (error.Fail() || bytes_read != fp_and_ra_size)
+  break;
+
+stack_memory_chunks.push_back(
+std::move(CreateMemoryChunk(stack_memory_ch

[Lldb-commits] [PATCH] D74398: [lldb-server] jThreadsInfo returns stack memory

2020-03-18 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

In D74398#1929019 , @labath wrote:

> Thanks. Could you also add the other kind of test (the one inline asm) I 
> mentioned. In an ideal world we'd have a test case for every boundary 
> condition, but we're pretty far from that right now. Even so, one test case 
> like that would be nice.


Pavel, thank you for the careful review! I still do not quite understand how 
the asm test should look like and where it should live. Are you asking for 
creating a new directory with a compiled program below and building the 
machinery to stop at the right place and check the stack? If yes, that sounds 
like a fairly time-consuming undertaking, and I am afraid I cannot invest much 
more time into this. Perhaps it is better if we stick this patch only into our 
lldb branch, this one should be pretty easy for us to rebase.

As for the timings with local lldb on Linux, I see the time for jThreadsInfo of 
100 threads with fairly shallow stacks (10 entries or so) taking 20ms locally, 
as opposed to 4ms before this change. The jThreadsInfo reply size is 80kB, up 
from 11kB. While this seems excessive, I do not see any extra memory traffic 
for getting a thread list with the patch,  whereas without this patch we get 
over 100 roundtrips (each is at least 512 bytes of payload) to display the top 
of the stack of each thread.

> I am imagining the inferior doing something like:
> 
>   movabsq $0xdead, %rax
>   pushq %rax ; fake pc
>   leaq 0x1000(%rsp), %rbp ; larger than kMaxFrameSize
>   pushq %rbp
>   movq %rsp, %rbp
>   pushq $1 ; fake frame contents
>   pushq $2
>   pushq $3
>   
>   incq %rax
>   push %rax; second fake pc
>   pushq %rbp
>   movq %rsp, %rbp
>   pushq $4 ; fake frame contents
>   pushq $5
>   pushq $6
>   int3
> 
> 
> and then the test would assert that the result contains the entirety of the 
> first fake frame, the bp+pc of the second fake frame, and then would stop due 
> to hitting the kMaxFrameSize boundary.






Comment at: 
lldb/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteThreadsInStopReply.py:373
+# Read memory chunks from jThreadsInfo.
+memory_chunks = self.gather_threads_info_memory()
+# Check the chunks are correct.

labath wrote:
> Also assert that you have at least one chunk here?
I have asserted that for each thread now.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74398/new/

https://reviews.llvm.org/D74398



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D76216: Improve step over performance

2020-03-18 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 251208.
jarin added a comment.

Rebase


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D76216/new/

https://reviews.llvm.org/D76216

Files:
  lldb/source/Target/ThreadPlanStepOverRange.cpp


Index: lldb/source/Target/ThreadPlanStepOverRange.cpp
===
--- lldb/source/Target/ThreadPlanStepOverRange.cpp
+++ lldb/source/Target/ThreadPlanStepOverRange.cpp
@@ -171,6 +171,10 @@
   const SymbolContext &older_context =
   older_frame_sp->GetSymbolContext(eSymbolContextEverything);
   if (IsEquivalentContext(older_context)) {
+// If we have the  next-branch-breakpoint in the range, we can just
+// rely on that breakpoint to trigger once we return to the range.
+if (m_next_branch_bp_sp)
+  return false;
 new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop(
 false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
 m_status, true);


Index: lldb/source/Target/ThreadPlanStepOverRange.cpp
===
--- lldb/source/Target/ThreadPlanStepOverRange.cpp
+++ lldb/source/Target/ThreadPlanStepOverRange.cpp
@@ -171,6 +171,10 @@
   const SymbolContext &older_context =
   older_frame_sp->GetSymbolContext(eSymbolContextEverything);
   if (IsEquivalentContext(older_context)) {
+// If we have the  next-branch-breakpoint in the range, we can just
+// rely on that breakpoint to trigger once we return to the range.
+if (m_next_branch_bp_sp)
+  return false;
 new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop(
 false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
 m_status, true);
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D76216: Improve step over performance

2020-03-19 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Thanks Greg, I will wait for Jim's comment.

I also see that build-bot is not happy about my patch. Clang-tidy somewhat 
mysteriously fails on missing lldb/Target/ThreadPlanStepOverRange.h, which I 
did not touch at all (neither the fail nor the #include). Any idea what that is 
about?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D76216/new/

https://reviews.llvm.org/D76216



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D76216: Improve step over performance

2020-03-19 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Pavel or Jim, could you possibly land this for me?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D76216/new/

https://reviews.llvm.org/D76216



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D74398: [lldb-server] jThreadsInfo returns stack memory

2020-03-19 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 251512.
jarin added a comment.

Adding a tighter x64 test as suggested by labath@.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74398/new/

https://reviews.llvm.org/D74398

Files:
  
lldb/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteThreadsInStopReply.py
  lldb/packages/Python/lldbsuite/test/tools/lldb-server/threads-info/Makefile
  
lldb/packages/Python/lldbsuite/test/tools/lldb-server/threads-info/TestGdbRemoteThreadsInfoMemory.py
  lldb/packages/Python/lldbsuite/test/tools/lldb-server/threads-info/main.cpp
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp

Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
===
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -31,6 +31,7 @@
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Utility/Args.h"
 #include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/DataExtractor.h"
 #include "lldb/Utility/Endian.h"
 #include "lldb/Utility/LLDBAssert.h"
 #include "lldb/Utility/Log.h"
@@ -469,6 +470,119 @@
   return register_object;
 }
 
+static llvm::Optional
+GetRegisterValue(NativeRegisterContext ®_ctx, uint32_t generic_regnum) {
+  Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+  uint32_t reg_num = reg_ctx.ConvertRegisterKindToRegisterNumber(
+  eRegisterKindGeneric, generic_regnum);
+  const RegisterInfo *const reg_info_p =
+  reg_ctx.GetRegisterInfoAtIndex(reg_num);
+
+  if (reg_info_p == nullptr || reg_info_p->value_regs != nullptr) {
+LLDB_LOGF(log, "%s failed to get register info for register index %" PRIu32,
+  __FUNCTION__, reg_num);
+return {};
+  }
+
+  RegisterValue reg_value;
+  Status error = reg_ctx.ReadRegister(reg_info_p, reg_value);
+  if (error.Fail()) {
+LLDB_LOGF(log, "%s failed to read register '%s' index %" PRIu32 ": %s",
+  __FUNCTION__,
+  reg_info_p->name ? reg_info_p->name : "",
+  reg_num, error.AsCString());
+return {};
+  }
+  return reg_value;
+}
+
+static json::Object CreateMemoryChunk(json::Array &stack_memory_chunks,
+  addr_t address,
+  std::vector &bytes) {
+  json::Object chunk;
+  chunk.try_emplace("address", static_cast(address));
+  StreamString stream;
+  for (uint8_t b : bytes)
+stream.PutHex8(b);
+  chunk.try_emplace("bytes", stream.GetString().str());
+  return chunk;
+}
+
+static json::Array GetStackMemoryAsJSON(NativeProcessProtocol &process,
+NativeThreadProtocol &thread) {
+  uint32_t address_size = process.GetArchitecture().GetAddressByteSize();
+  const size_t kStackTopMemoryInfoWordSize = 12;
+  size_t stack_top_memory_info_byte_size =
+  kStackTopMemoryInfoWordSize * address_size;
+  const size_t kMaxStackSize = 128 * 1024;
+  const size_t kMaxFrameSize = 4 * 1024;
+  size_t fp_and_ra_size = 2 * address_size;
+  const size_t kMaxFrameCount = 128;
+
+  NativeRegisterContext ®_ctx = thread.GetRegisterContext();
+
+  json::Array stack_memory_chunks;
+
+  lldb::addr_t sp_value;
+  if (llvm::Optional optional_sp_value =
+  GetRegisterValue(reg_ctx, LLDB_REGNUM_GENERIC_SP)) {
+sp_value = optional_sp_value->GetAsUInt64();
+  } else {
+return stack_memory_chunks;
+  }
+  lldb::addr_t fp_value;
+  if (llvm::Optional optional_fp_value =
+  GetRegisterValue(reg_ctx, LLDB_REGNUM_GENERIC_FP)) {
+fp_value = optional_fp_value->GetAsUInt64();
+  } else {
+return stack_memory_chunks;
+  }
+
+  // First, make sure we copy the top stack_top_memory_info_byte_size bytes
+  // from the stack.
+  size_t byte_count = std::min(stack_top_memory_info_byte_size,
+   static_cast(fp_value - sp_value));
+  std::vector buf(byte_count, 0);
+
+  size_t bytes_read = 0;
+  Status error = process.ReadMemoryWithoutTrap(sp_value, buf.data(), byte_count,
+   bytes_read);
+  if (error.Success() && bytes_read > 0) {
+buf.resize(bytes_read);
+stack_memory_chunks.push_back(
+std::move(CreateMemoryChunk(stack_memory_chunks, sp_value, buf)));
+  }
+
+  // Additionally, try to walk the frame pointer link chain. If the frame
+  // is too big or if the frame pointer points too far, stop the walk.
+  addr_t max_frame_pointer = sp_value + kMaxStackSize;
+  for (size_t i = 0; i < kMaxFrameCount; i++) {
+if (fp_value < sp_value || fp_value > sp_value + kMaxFrameSize ||
+fp_value > max_frame_pointer)
+  break;
+
+std::vector fp_ra_buf(fp_and_ra_size, 0);
+bytes_read = 0;
+error = process.ReadMemoryWithoutTrap(fp_value, fp_ra_buf.data(),
+  fp_an

[Lldb-commits] [PATCH] D74398: [lldb-server] jThreadsInfo returns stack memory

2020-03-20 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 251714.
jarin marked 3 inline comments as done.
jarin added a comment.

Addressed comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74398/new/

https://reviews.llvm.org/D74398

Files:
  
lldb/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteThreadsInStopReply.py
  lldb/packages/Python/lldbsuite/test/tools/lldb-server/threads-info/Makefile
  
lldb/packages/Python/lldbsuite/test/tools/lldb-server/threads-info/TestGdbRemoteThreadsInfoMemory.py
  lldb/packages/Python/lldbsuite/test/tools/lldb-server/threads-info/main.cpp
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp

Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
===
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -31,6 +31,7 @@
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Utility/Args.h"
 #include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/DataExtractor.h"
 #include "lldb/Utility/Endian.h"
 #include "lldb/Utility/LLDBAssert.h"
 #include "lldb/Utility/Log.h"
@@ -469,6 +470,119 @@
   return register_object;
 }
 
+static llvm::Optional
+GetRegisterValue(NativeRegisterContext ®_ctx, uint32_t generic_regnum) {
+  Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+  uint32_t reg_num = reg_ctx.ConvertRegisterKindToRegisterNumber(
+  eRegisterKindGeneric, generic_regnum);
+  const RegisterInfo *const reg_info_p =
+  reg_ctx.GetRegisterInfoAtIndex(reg_num);
+
+  if (reg_info_p == nullptr || reg_info_p->value_regs != nullptr) {
+LLDB_LOGF(log, "%s failed to get register info for register index %" PRIu32,
+  __FUNCTION__, reg_num);
+return {};
+  }
+
+  RegisterValue reg_value;
+  Status error = reg_ctx.ReadRegister(reg_info_p, reg_value);
+  if (error.Fail()) {
+LLDB_LOGF(log, "%s failed to read register '%s' index %" PRIu32 ": %s",
+  __FUNCTION__,
+  reg_info_p->name ? reg_info_p->name : "",
+  reg_num, error.AsCString());
+return {};
+  }
+  return reg_value;
+}
+
+static json::Object CreateMemoryChunk(json::Array &stack_memory_chunks,
+  addr_t address,
+  std::vector &bytes) {
+  json::Object chunk;
+  chunk.try_emplace("address", static_cast(address));
+  StreamString stream;
+  for (uint8_t b : bytes)
+stream.PutHex8(b);
+  chunk.try_emplace("bytes", stream.GetString().str());
+  return chunk;
+}
+
+static json::Array GetStackMemoryAsJSON(NativeProcessProtocol &process,
+NativeThreadProtocol &thread) {
+  uint32_t address_size = process.GetArchitecture().GetAddressByteSize();
+  const size_t kStackTopMemoryInfoWordSize = 12;
+  size_t stack_top_memory_info_byte_size =
+  kStackTopMemoryInfoWordSize * address_size;
+  const size_t kMaxStackSize = 128 * 1024;
+  const size_t kMaxFrameSize = 4 * 1024;
+  size_t fp_and_ra_size = 2 * address_size;
+  const size_t kMaxFrameCount = 128;
+
+  NativeRegisterContext ®_ctx = thread.GetRegisterContext();
+
+  json::Array stack_memory_chunks;
+
+  lldb::addr_t sp_value;
+  if (llvm::Optional optional_sp_value =
+  GetRegisterValue(reg_ctx, LLDB_REGNUM_GENERIC_SP)) {
+sp_value = optional_sp_value->GetAsUInt64();
+  } else {
+return stack_memory_chunks;
+  }
+  lldb::addr_t fp_value;
+  if (llvm::Optional optional_fp_value =
+  GetRegisterValue(reg_ctx, LLDB_REGNUM_GENERIC_FP)) {
+fp_value = optional_fp_value->GetAsUInt64();
+  } else {
+return stack_memory_chunks;
+  }
+
+  // First, make sure we copy the top stack_top_memory_info_byte_size bytes
+  // from the stack.
+  size_t byte_count = std::min(stack_top_memory_info_byte_size,
+   static_cast(fp_value - sp_value));
+  std::vector buf(byte_count, 0);
+
+  size_t bytes_read = 0;
+  Status error = process.ReadMemoryWithoutTrap(sp_value, buf.data(), byte_count,
+   bytes_read);
+  if (error.Success() && bytes_read > 0) {
+buf.resize(bytes_read);
+stack_memory_chunks.push_back(
+std::move(CreateMemoryChunk(stack_memory_chunks, sp_value, buf)));
+  }
+
+  // Additionally, try to walk the frame pointer link chain. If the frame
+  // is too big or if the frame pointer points too far, stop the walk.
+  addr_t max_frame_pointer = sp_value + kMaxStackSize;
+  for (size_t i = 0; i < kMaxFrameCount; i++) {
+if (fp_value < sp_value || fp_value > sp_value + kMaxFrameSize ||
+fp_value > max_frame_pointer)
+  break;
+
+std::vector fp_ra_buf(fp_and_ra_size, 0);
+bytes_read = 0;
+error = process.ReadMemoryWithoutTrap(fp_value, fp_ra_buf.data(),
+  

[Lldb-commits] [PATCH] D74398: [lldb-server] jThreadsInfo returns stack memory

2020-03-21 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Regarding the packet savings - there are still things that worry me.

First of all, when lldb CLI stops on a breakpoint, it will first unwind top of 
the stack of each thread as part of ThreadList::ShouldStop. This sends lots of 
"x" packets to lldb-server and only then issues jThreadInfo, which then replies 
with the stack memory uselessly (with my patch). I am yet to investigate why 
the CLI does that.

My patch saves messages when we start stepping after the breakpoint - in my 
example with a hundred threads, when we stop on a breakpoint, take a step and 
then do "thread list", there are no additional 'x' packets sent to lldb-server 
for the "thread list" command; without my patch there is a packet per-thread. 
In our VS extension, this seems to help quite a bit, but I am not so sure about 
the CLI.

It also feels like jThreadsInfo might not the best place to send the stacks - I 
am wondering whether jstopinfo in the vCont/c packet response would be a better 
place (even though the encoding of that is quite terrible). What do you think?




Comment at: 
lldb/packages/Python/lldbsuite/test/tools/lldb-server/threads-info/main.cpp:1
+#include 
+

labath wrote:
> I don't believe this include is needed.
Good catch, copypasta :-/


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74398/new/

https://reviews.llvm.org/D74398



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D76650: Data formatters: fix detection of C strings

2020-03-23 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin created this revision.
jarin added a reviewer: teemperor.
jarin added a project: LLDB.
Herald added a subscriber: lldb-commits.

Detection of C strings does not work well for pointers. If the value object 
holding a (char*) pointer does not have an address (e.g., if it is a temp), the 
value is not considered a C string and its formatting is left to 
DumpDataExtractor rather than the special handling in  
ValueObject::DumpPrintableRepresentation. This leads to inconsistent outputs, 
e.g., in escaping non-ASCII characters. See the test for an example; the second 
test expectation is not met (without this patch). With this patch, the C string 
detection only insists that the pointer value is valid. The patch makes the 
code consistent with how the pointer is obtained in 
ValueObject::ReadPointedString.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D76650

Files:
  lldb/source/Core/ValueObject.cpp
  lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/Makefile
  
lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/TestCstringUnicode.py
  lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/main.cpp


Index: 
lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/main.cpp
===
--- /dev/null
+++ lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/main.cpp
@@ -0,0 +1,4 @@
+int main() {
+  const char *s = "é";
+  return 0; // break here
+}
Index: 
lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/TestCstringUnicode.py
===
--- /dev/null
+++ 
lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/TestCstringUnicode.py
@@ -0,0 +1,18 @@
+# coding=utf8
+
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+
+class CstringUnicodeTestCase(TestBase):
+
+mydir = TestBase.compute_mydir(__file__)
+NO_DEBUG_INFO_TESTCASE = True
+
+def test_cstring_unicode(self):
+self.build()
+lldbutil.run_to_source_breakpoint(self, "// break here",
+lldb.SBFileSpec("main.cpp", False))
+self.expect("expr s", substrs=['"é"'])
+self.expect("expr (const char*)s", substrs=['"é"'])
Index: 
lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/Makefile
===
--- /dev/null
+++ lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
Index: lldb/source/Core/ValueObject.cpp
===
--- lldb/source/Core/ValueObject.cpp
+++ lldb/source/Core/ValueObject.cpp
@@ -764,7 +764,7 @@
 return true;
   addr_t cstr_address = LLDB_INVALID_ADDRESS;
   AddressType cstr_address_type = eAddressTypeInvalid;
-  cstr_address = GetAddressOf(true, &cstr_address_type);
+  cstr_address = GetPointerValue(&cstr_address_type);
   return (cstr_address != LLDB_INVALID_ADDRESS);
 }
 


Index: lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/main.cpp
===
--- /dev/null
+++ lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/main.cpp
@@ -0,0 +1,4 @@
+int main() {
+  const char *s = "é";
+  return 0; // break here
+}
Index: lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/TestCstringUnicode.py
===
--- /dev/null
+++ lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/TestCstringUnicode.py
@@ -0,0 +1,18 @@
+# coding=utf8
+
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+
+class CstringUnicodeTestCase(TestBase):
+
+mydir = TestBase.compute_mydir(__file__)
+NO_DEBUG_INFO_TESTCASE = True
+
+def test_cstring_unicode(self):
+self.build()
+lldbutil.run_to_source_breakpoint(self, "// break here",
+lldb.SBFileSpec("main.cpp", False))
+self.expect("expr s", substrs=['"é"'])
+self.expect("expr (const char*)s", substrs=['"é"'])
Index: lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/Makefile
===
--- /dev/null
+++ lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
Index: lldb/source/Core/ValueObject.cpp
===
--- lldb/source/Core/ValueObject.cpp
+++ lldb/source/Core/ValueObject.cpp
@@ -764,7 +764,7 @@
 return true;
   addr_t cstr_address = LLDB_INVALID_ADDRESS;
   AddressType cstr_address_type = eAddressTypeInvalid;
-  cstr_address = GetAddressOf(true, &cstr_address_type);
+  cstr_address = GetPointerValue(&cstr_ad

[Lldb-commits] [PATCH] D76650: Data formatters: fix detection of C strings

2020-03-24 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Thanks for the review! Could you possibly land this for me?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D76650/new/

https://reviews.llvm.org/D76650



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D76650: Data formatters: fix detection of C strings

2020-03-24 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 252276.
jarin marked 2 inline comments as done.
jarin added a comment.

Addressed reviewer comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D76650/new/

https://reviews.llvm.org/D76650

Files:
  lldb/source/Core/ValueObject.cpp
  lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/Makefile
  
lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/TestCstringUnicode.py
  lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/main.cpp


Index: 
lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/main.cpp
===
--- /dev/null
+++ lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/main.cpp
@@ -0,0 +1,4 @@
+int main() {
+  const char *s = u8"🔥";
+  return 0; // break here
+}
Index: 
lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/TestCstringUnicode.py
===
--- /dev/null
+++ 
lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/TestCstringUnicode.py
@@ -0,0 +1,18 @@
+# coding=utf8
+
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+
+class CstringUnicodeTestCase(TestBase):
+
+mydir = TestBase.compute_mydir(__file__)
+NO_DEBUG_INFO_TESTCASE = True
+
+def test_cstring_unicode(self):
+self.build()
+lldbutil.run_to_source_breakpoint(self, "// break here",
+lldb.SBFileSpec("main.cpp", False))
+self.expect_expr("s", result_summary='"🔥"')
+self.expect_expr("(const char*)s", result_summary='"🔥"')
Index: 
lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/Makefile
===
--- /dev/null
+++ lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
Index: lldb/source/Core/ValueObject.cpp
===
--- lldb/source/Core/ValueObject.cpp
+++ lldb/source/Core/ValueObject.cpp
@@ -764,7 +764,7 @@
 return true;
   addr_t cstr_address = LLDB_INVALID_ADDRESS;
   AddressType cstr_address_type = eAddressTypeInvalid;
-  cstr_address = GetAddressOf(true, &cstr_address_type);
+  cstr_address = GetPointerValue(&cstr_address_type);
   return (cstr_address != LLDB_INVALID_ADDRESS);
 }
 


Index: lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/main.cpp
===
--- /dev/null
+++ lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/main.cpp
@@ -0,0 +1,4 @@
+int main() {
+  const char *s = u8"🔥";
+  return 0; // break here
+}
Index: lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/TestCstringUnicode.py
===
--- /dev/null
+++ lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/TestCstringUnicode.py
@@ -0,0 +1,18 @@
+# coding=utf8
+
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+
+class CstringUnicodeTestCase(TestBase):
+
+mydir = TestBase.compute_mydir(__file__)
+NO_DEBUG_INFO_TESTCASE = True
+
+def test_cstring_unicode(self):
+self.build()
+lldbutil.run_to_source_breakpoint(self, "// break here",
+lldb.SBFileSpec("main.cpp", False))
+self.expect_expr("s", result_summary='"🔥"')
+self.expect_expr("(const char*)s", result_summary='"🔥"')
Index: lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/Makefile
===
--- /dev/null
+++ lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
Index: lldb/source/Core/ValueObject.cpp
===
--- lldb/source/Core/ValueObject.cpp
+++ lldb/source/Core/ValueObject.cpp
@@ -764,7 +764,7 @@
 return true;
   addr_t cstr_address = LLDB_INVALID_ADDRESS;
   AddressType cstr_address_type = eAddressTypeInvalid;
-  cstr_address = GetAddressOf(true, &cstr_address_type);
+  cstr_address = GetPointerValue(&cstr_address_type);
   return (cstr_address != LLDB_INVALID_ADDRESS);
 }
 
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D74398: [lldb-server] jThreadsInfo returns stack memory

2020-03-24 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

In D74398#1935438 , @jasonmolenda 
wrote:

> (and if you're still seeing mystery reads, put a breakpoint on 
> ProcessGDBRemote::DoReadMemory and see who is doing it)


Thanks for the great explanations! I did put a breakpoint into DoReadMemory, 
and the unwinder doing the reads for each thread (called from 
https://github.com/llvm/llvm-project/blob/master/lldb/source/Target/ThreadList.cpp#L349).
 If I understand correctly, the Thread::WillStop/SelectMostRelevantFrame should 
care only about the current PC of each thread, but not about the stack 
contents. Let me double check that.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74398/new/

https://reviews.llvm.org/D74398



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D74398: [lldb-server] jThreadsInfo returns stack memory

2020-03-31 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

In D74398#1939372 , @jarin wrote:

> In D74398#1935438 , @jasonmolenda 
> wrote:
>
> > (and if you're still seeing mystery reads, put a breakpoint on 
> > ProcessGDBRemote::DoReadMemory and see who is doing it)
>
>
> Thanks for the great explanations! I did put a breakpoint into DoReadMemory, 
> and the unwinder doing the reads for each thread (called from 
> https://github.com/llvm/llvm-project/blob/master/lldb/source/Target/ThreadList.cpp#L349).
>  If I understand correctly, the Thread::WillStop/SelectMostRelevantFrame 
> should care only about the current PC of each thread, but not about the stack 
> contents. Let me double check that.


Looking at this in more detail, Thread::WillStop will unwind more than one 
frame (for each thread), the stack trace is below. I guess the surprising bit 
is that UnwindLLDB::UpdateUnwindPlanForFirstFrameIfInvalid (frame #11) always 
unwinds one more frame. Is that expected?

#0: process_gdb_remote::ProcessGDBRemote::DoReadMemory() at 
ProcessGDBRemote.cpp:2694:54
#1: Process::ReadMemoryFromInferior() at Process.cpp:2092:21
#2: Process::ReadMemoryFromInferior() at Process.cpp:2081
#3: MemoryCache::Read() at Memory.cpp:229:69
#4: RegisterContext::ReadRegisterValueFromMemory() at RegisterContext.cpp:337:31
#5: RegisterContextUnwind::ReadRegisterValueFromRegisterLocation() at 
RegisterContextUnwind.cpp:1040:15
#6: RegisterContextUnwind::ReadGPRValue() at RegisterContextUnwind.cpp:2008:44
#7: RegisterContextUnwind::InitializeNonZerothFrame() at 
RegisterContextUnwind.cpp:287:20
#8: RegisterContextUnwind::RegisterContextUnwind() at 
RegisterContextUnwind.cpp:70:29
#9: UnwindLLDB::GetOneMoreFrame() at UnwindLLDB.cpp:129:77
#10: UnwindLLDB::AddOneMoreFrame() at UnwindLLDB.cpp:332:32
#11: UnwindLLDB::UpdateUnwindPlanForFirstFrameIfInvalid() at 
UnwindLLDB.cpp:305:18
#12: UnwindLLDB::AddFirstFrame() at UnwindLLDB.cpp:99:41
#13: UnwindLLDB::AddFirstFrame() at UnwindLLDB.cpp:70
#14: UnwindLLDB::DoGetFrameInfoAtIndex() at UnwindLLDB.cpp:395:23
#15: StackFrameList::GetFramesUpTo() at Unwind.h:53:33
#16: StackFrameList::GetFrameAtIndex() at StackFrameList.cpp:660:16
#17: Thread::SelectMostRelevantFrame() at Thread.cpp:612:52
#18: Thread::WillStop() at Thread.cpp:634:26
#19: ThreadList::ShouldStop() at ThreadList.cpp:349:26
#20: Process::ShouldBroadcastEvent() at Process.cpp:3427:50
#21: Process::HandlePrivateEvent() at Process.cpp:3652:53
#22: Process::RunPrivateStateThread() at Process.cpp:3846:25


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74398/new/

https://reviews.llvm.org/D74398



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D74398: [lldb-server] jThreadsInfo returns stack memory

2020-04-02 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Pavel, could you land this for me?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74398/new/

https://reviews.llvm.org/D74398



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D74398: [lldb-server] jThreadsInfo returns stack memory

2020-04-07 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Looking at the code for flushing L1 cache 
,
 it appears broken. I am guessing that is the reason for the failure of my 
patch on the bots.

Here is the L1  flushing code (after checking L1 
 is not empty).

  AddrRange flush_range(addr, size);
  BlockMap::iterator pos = m_L1_cache.upper_bound(addr);
  if (pos != m_L1_cache.begin()) {
--pos;
  }
  while (pos != m_L1_cache.end()) {
AddrRange chunk_range(pos->first, pos->second->GetByteSize());
if (!chunk_range.DoesIntersect(flush_range))
  break;
pos = m_L1_cache.erase(pos);
  }

For instance, let the cache contains two chunks (10, 10) and (30, 10). Let us 
flush (25, 10). Then the while loop chunk_range will be (10, 10), which is not 
intersecting with (25, 10), so we do not flush anything. This is clearly wrong 
because (30, 10) should be flushed.

I am wondering whether something like this would be correct (I am still a bit 
worried about the case of overlapping things in L1 
).

  AddrRange flush_range(addr, size);
  BlockMap::iterator pos = m_L1_cache.upper_bound(addr);
  if (pos != m_L1_cache.begin()) {
// If we are not in the beginning, the previous range might be also 
intersecting.
BlockMap::iterator previous = pos;
previous--;
AddrRange previous_range(previous->first, previous->second->GetByteSize()) 
if (!previous_range.DoesIntersect(flush_range))
  pos = m_L1_cache.erase(previous);
  }
  while (pos != m_L1_cache.end()) {
AddrRange chunk_range(pos->first, pos->second->GetByteSize());
if (!chunk_range.DoesIntersect(flush_range))
  break;
pos = m_L1_cache.erase(pos);
  }


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74398/new/

https://reviews.llvm.org/D74398



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D77765: Fix incorrect L1 inferior memory cache flushing

2020-04-08 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin created this revision.
jarin added reviewers: labath, clayborg.
jarin added a project: LLDB.
Herald added subscribers: lldb-commits, mgorny.
jarin retitled this revision from "Fix incorrect L1 cache flushing" to "Fix 
incorrect L1 inferior memory cache flushing".

As discussed in https://reviews.llvm.org/D74398, the L1 
 memory cache flushing is incorrect.

For instance, if the L1  cache contains two chunks 
(10, 10) and (30, 10) and we call MemoryCache::Flush(25, 10), the current code 
does not flush anything (because it just tries to flush the previous range (10, 
10) and if that is not intersecting, it will bail out).

With this patch, if the previous chunk is not overlapping, we still try the 
next chunk, and only if that one is not overlapping, we bail out.

This also adds some unit tests for the cache (some of the tests fail with the 
current code). The unit tests required some changes for testability.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D77765

Files:
  lldb/include/lldb/Target/Memory.h
  lldb/include/lldb/Target/Process.h
  lldb/source/Target/Memory.cpp
  lldb/source/Target/Process.cpp
  lldb/unittests/Target/CMakeLists.txt
  lldb/unittests/Target/MemoryCacheTest.cpp

Index: lldb/unittests/Target/MemoryCacheTest.cpp
===
--- /dev/null
+++ lldb/unittests/Target/MemoryCacheTest.cpp
@@ -0,0 +1,144 @@
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "lldb/Target/Memory.h"
+#include "lldb/Utility/Status.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+namespace {
+
+class MemoryCacheTest : public MemoryFromInferiorReader, public testing::Test {
+  static const size_t k_memory_size = 256;
+  static const uint64_t k_cache_line_size = 16;
+
+  size_t ReadMemoryFromInferior(lldb::addr_t vm_addr, void *buf, size_t size,
+Status &error) override;
+
+public:
+  MemoryCacheTest();
+
+  void AddRangeToL1Cache(lldb::addr_t addr, size_t len);
+  void IncrementAndFlushRange(lldb::addr_t addr, size_t len);
+  std::vector ReadByBytes(lldb::addr_t addr, size_t len);
+
+protected:
+  MemoryCache m_cache;
+  std::vector m_memory;
+  size_t m_inferior_read_count;
+};
+
+MemoryCacheTest::MemoryCacheTest()
+: m_cache(*this, k_cache_line_size), m_inferior_read_count(0) {
+  for (size_t i = 0; i < k_memory_size; i++)
+m_memory.push_back(static_cast(i));
+}
+
+void MemoryCacheTest::AddRangeToL1Cache(lldb::addr_t addr, size_t len) {
+  m_cache.AddL1CacheData(addr, m_memory.data() + addr, len);
+}
+
+size_t MemoryCacheTest::ReadMemoryFromInferior(lldb::addr_t vm_addr, void *buf,
+   size_t size, Status &error) {
+  m_inferior_read_count++;
+
+  if (vm_addr >= m_memory.size())
+return 0;
+
+  size = std::min(size, m_memory.size() - vm_addr);
+  memcpy(buf, m_memory.data() + vm_addr, size);
+  return size;
+}
+
+void MemoryCacheTest::IncrementAndFlushRange(lldb::addr_t addr, size_t len) {
+  for (size_t i = 0; i < len; i++)
+m_memory[addr + i]++;
+  m_cache.Flush(addr, len);
+}
+
+std::vector MemoryCacheTest::ReadByBytes(lldb::addr_t addr,
+  size_t len) {
+  std::vector result(len, 0);
+  for (size_t i = 0; i < len; i++) {
+Status error;
+m_cache.Read(addr + i, &(result[i]), 1, error);
+EXPECT_TRUE(error.Success());
+  }
+  return result;
+}
+
+TEST_F(MemoryCacheTest, L1FlushSimple) {
+  Status error;
+  std::vector result(10);
+
+  m_cache.Read(10, result.data(), result.size(), error);
+  ASSERT_EQ(10, result[0]);
+
+  IncrementAndFlushRange(10, 1);
+
+  m_cache.Read(10, result.data(), result.size(), error);
+  ASSERT_EQ(m_memory[10], result[0]);
+}
+
+class MemoryCacheOverlapTest
+: public MemoryCacheTest,
+  public testing::WithParamInterface> {};
+
+TEST_P(MemoryCacheOverlapTest, L1FlushFromTwoWithOverlap) {
+  // Add two ranges to the cache.
+  std::vector> cached = {{10, 10}, {30, 10}};
+  for (std::pair p : cached)
+AddRangeToL1Cache(p.first, p.second);
+
+  // Flush the range given by the parameter.
+  IncrementAndFlushRange(GetParam().first, GetParam().second);
+
+  // Check the memory.
+  size_t check_size = 50;
+  std::vector result = ReadByBytes(0, check_size);
+  EXPECT_THAT(result, ::testing::ElementsAreArray(m_memory.data(), check_size));
+}
+
+INSTANTIATE_TEST_CASE_P(
+AllMemoryCacheOverlapTest, MemoryCacheOverlapTest,
+::testing::Values(
+std::make_pair(5, 6), std::make_pair(5, 10), std::make_pair(5, 20),
+std::make_pair(5, 30), std::make_pair(5, 40), std::make_pair(10, 1),
+std::make_pair(10, 21), std::make_pair(19, 1), std::make_pair(19, 11),
+std::make_pair(19, 12), std::make_pair(20, 11), std::make_pair(20, 25),
+std::make_pair(29, 2), std::make_pair(29, 12), std::make_pair(30, 1),
+std::make_pair(39, 1), std::

[Lldb-commits] [PATCH] D77765: Fix incorrect L1 inferior memory cache flushing

2020-04-09 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 256207.
jarin marked 10 inline comments as done.
jarin added a comment.

Addressed some of the reviewer comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77765/new/

https://reviews.llvm.org/D77765

Files:
  lldb/include/lldb/Target/Memory.h
  lldb/include/lldb/Target/Process.h
  lldb/source/Target/Memory.cpp
  lldb/source/Target/Process.cpp
  lldb/unittests/Target/CMakeLists.txt
  lldb/unittests/Target/MemoryCacheTest.cpp

Index: lldb/unittests/Target/MemoryCacheTest.cpp
===
--- /dev/null
+++ lldb/unittests/Target/MemoryCacheTest.cpp
@@ -0,0 +1,128 @@
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "lldb/Target/Memory.h"
+#include "lldb/Utility/Status.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+namespace {
+
+class MemoryCacheTest : public MemoryFromInferiorReader, public testing::Test {
+  static const size_t k_memory_size = 256;
+  static const uint64_t k_cache_line_size = 16;
+
+  size_t ReadMemoryFromInferior(lldb::addr_t vm_addr, void *buf, size_t size,
+Status &error) override {
+m_inferior_read_count++;
+
+if (vm_addr >= m_memory.size())
+  return 0;
+
+size = std::min(size, m_memory.size() - vm_addr);
+memcpy(buf, m_memory.data() + vm_addr, size);
+return size;
+  }
+
+public:
+  MemoryCacheTest()
+  : m_cache(*this, k_cache_line_size), m_inferior_read_count(0) {
+// Fill memory from [0x0 - 0x256) with byte values that match the index. We
+// will use this memory in each test and each test will start with a fresh
+// copy.
+for (size_t i = 0; i < k_memory_size; i++)
+  m_memory.push_back(static_cast(i));
+  }
+
+  void AddRangeToL1Cache(lldb::addr_t addr, size_t len) {
+m_cache.AddL1CacheData(addr, m_memory.data() + addr, len);
+  }
+
+  void IncrementAndFlushRange(lldb::addr_t addr, size_t len) {
+for (size_t i = 0; i < len; i++)
+  m_memory[addr + i]++;
+m_cache.Flush(addr, len);
+  }
+
+  uint8_t ReadByte(lldb::addr_t addr) {
+uint8_t result;
+Status error;
+m_cache.Read(addr, &result, 1, error);
+EXPECT_TRUE(error.Success());
+return result;
+  }
+
+protected:
+  MemoryCache m_cache;
+  std::vector m_memory;
+  size_t m_inferior_read_count;
+};
+
+TEST_F(MemoryCacheTest, L1FlushSimple) {
+  // Add a byte to the cache.
+  AddRangeToL1Cache(10, 1);
+
+  // Sanity check - memory should agree with what ReadByte returns.
+  EXPECT_EQ(10, m_memory[10]);
+  EXPECT_EQ(m_memory[10], ReadByte(10));
+  // Check that we have hit the cache and not the inferior's memory.
+  EXPECT_EQ(0u, m_inferior_read_count);
+
+  IncrementAndFlushRange(10, 1);
+
+  // Check the memory is incremented and the real memory agrees with ReadByte's
+  // result.
+  EXPECT_EQ(11, m_memory[11]);
+  EXPECT_EQ(m_memory[10], ReadByte(10));
+}
+
+// Let us do a parametrized test that caches two ranges. In the test, we then
+// try to modify (and flush) various regions of memory and check that the cache
+// still returns the correct values from reads.
+using AddrRange = Range;
+class MemoryCacheParametrizedTest
+: public MemoryCacheTest,
+  public testing::WithParamInterface {};
+
+TEST_P(MemoryCacheParametrizedTest, L1FlushWithTwoRegions) {
+  // Add two ranges to the cache.
+  std::vector cached = {{10, 10}, {30, 10}};
+  for (AddrRange cached_range : cached)
+AddRangeToL1Cache(cached_range.base, cached_range.size);
+
+  // Flush the range given by the parameter.
+  AddrRange flush_range = GetParam();
+  IncrementAndFlushRange(flush_range.base, flush_range.size);
+
+  // Check that reads from the cached ranges read the inferior's memory
+  // if and only if the flush range intersects with one of the cached ranges.
+  bool has_intersection = false;
+  for (AddrRange cached_range : cached) {
+if (flush_range.DoesIntersect(cached_range))
+  has_intersection = true;
+
+for (size_t i = 0; i < cached_range.size; i++)
+  ReadByte(cached_range.base + i);
+  }
+  EXPECT_EQ(has_intersection, m_inferior_read_count > 0);
+
+  // Sanity check: check the memory contents.
+  for (size_t i = 0; i < 50; i++) {
+EXPECT_EQ(m_memory[i], ReadByte(i)) << " (element at addr=" << i << ")";
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(
+AllMemoryCacheParametrizedTest, MemoryCacheParametrizedTest,
+::testing::Values(AddrRange(5, 6), AddrRange(5, 10), AddrRange(5, 20),
+  AddrRange(5, 30), AddrRange(5, 40), AddrRange(10, 1),
+  AddrRange(10, 21), AddrRange(19, 1), AddrRange(19, 11),
+  AddrRange(19, 12), AddrRange(20, 11), AddrRange(20, 25),
+  AddrRange(29, 2), AddrRange(29, 12), AddrRange(30, 1),
+  AddrRange(39, 1), AddrRange(39, 5), AddrRange(5, 1),
+  AddrRange(5, 5), AddrRange(9, 1), AddrRange(20, 1),
+

[Lldb-commits] [PATCH] D77765: Fix incorrect L1 inferior memory cache flushing

2020-04-09 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

I rewrote parts of the test, hopefully making it a bit clearer. Please let me 
know if this made it better.




Comment at: lldb/source/Target/Memory.cpp:23-24
 // MemoryCache constructor
-MemoryCache::MemoryCache(Process &process)
+MemoryCache::MemoryCache(MemoryFromInferiorReader &reader,
+ uint64_t cache_line_size)
 : m_mutex(), m_L1_cache(), m_L2_cache(), m_invalid_ranges(),

clayborg wrote:
> Might be cleaner to add getting the cache line size from the 
> MemoryFromInferiorReader as a second virtual function. This would avoid 
> having to add the extra parameter here and to the clear method.
That's what I thought originally, but it does not logically belong there - it 
does not feel like inferior's memory should control cache line sizes. I also 
like that the extra parameter makes it clear when we reflect changes in the 
cache line size setting in the cache itself rather than having to guess when 
the cache might do a callback. I had trouble understanding that part before. 

Also, note that Process::GetMemoryCacheLineSize would have to be some ugly 
forwarder method because the existing GetMemoryCacheLineSize method is in 
ProcessProperties.

I am happy to put the method there if you insist, but I do not think it is a 
good idea. I would like to hear Pavel's opinion, too.



Comment at: lldb/source/Target/Memory.cpp:65-66
+  // intersecting.
+  BlockMap::iterator previous = pos;
+  previous--;
+  AddrRange previous_range(previous->first,

clayborg wrote:
> This can just be:
> 
> ```
> BlockMap::iterator previous = pos - 1;
> ```
It cannot because `map::iterator` does not have `operator-`.



Comment at: lldb/source/Target/Process.cpp:488
   m_profile_data_comm_mutex(), m_profile_data(), m_iohandler_sync(0),
-  m_memory_cache(*this), m_allocated_memory_cache(*this),
-  m_should_detach(false), m_next_event_action_up(), m_public_run_lock(),
-  m_private_run_lock(), m_finalizing(false), m_finalize_called(false),
+  m_memory_cache(*this, GetMemoryCacheLineSize()),
+  m_allocated_memory_cache(*this), m_should_detach(false),

clayborg wrote:
> remove GetMemoryCacheLineSize() if we add virtual method to 
> MemoryFromInferiorReader
Is not calling virtual functions in constructors dangerous? Note that this is 
going to be called during the construction of process.



Comment at: lldb/unittests/Target/MemoryCacheTest.cpp:75-76
+
+  m_cache.Read(10, result.data(), result.size(), error);
+  ASSERT_EQ(10, result[0]);
+

clayborg wrote:
> So we are reading 10 bytes, but only verifying the first byte in the 10 bytes 
> we read? Why not verify all of them to be sure it worked with a for loop?
> 
> ```
> for (int i=0; i   ASSERT_EQ(i+10, result[i]);
> ```
> 
> or just do manual asserts:
> ```
> ASSERT_EQ(10, result[0]);
> ASSERT_EQ(11, result[1]);
> ASSERT_EQ(12, result[2]);
> ...
> ```
> 
Ouch, this test does not make sense because we do not put anything into L1. 
Fixed now.

Changed this to test just one byte.



Comment at: lldb/unittests/Target/MemoryCacheTest.cpp:81
+  m_cache.Read(10, result.data(), result.size(), error);
+  ASSERT_EQ(m_memory[10], result[0]);
+}

clayborg wrote:
> So with "IncrementAndFlushRange(10, 1);" we are modifying one byte at index 
> 10 by incrementing it right? It isn't clear from the:
> ```
> ASSERT_EQ(m_memory[10], result[0]);
> ```
> What we are verifying here. Wouldn't it be simpler to do:
> ```
> ASSERT_EQ(11, result[0]);
> ```
> And also verify that all of the other 9 bytes we read were unchanged?
> 
> ```
> ASSERT_EQ(11, result[1]);
> ASSERT_EQ(12, result[2]);
> ...
> ```
> 
What we really care about is that the value that Read returns is the same as 
the real one in memory, no? I actually do not really care how the 
IncrementAndFlushRange method modifies the memory as long as Read returns the 
correct value.

Nevertheless, I rewrote the code to read just one byte and to assert both the 
value and the invariant.



Comment at: lldb/unittests/Target/MemoryCacheTest.cpp:92
+  for (std::pair p : cached)
+AddRangeToL1Cache(p.first, p.second);
+

clayborg wrote:
> seems weird to use AddRangeToL1Cache instead of just reading memory from 
> these locations and it makes it less of a real world kind a test if we are 
> mucking with the L1 cache directly. Makes the test a bit harder to follow. 
> Maybe just reading from memory is easier to follow?:
> 
> ```
> // Read ranges from memory to populate the L1 cache
> std::vector result(10);
> for (std::pair p : cached)
>   ReadByBytes(p.first, p.second);
> ```
> 
I am quite confused by this comment. What the test does is precisely what we do 
in [the real 
world](https://github.com/llvm/llvm-project/blob/1d3b7370c466eba4bf22dce4a51f885f76698053/lldb/source/Plugi

[Lldb-commits] [PATCH] D77790: [NFC] Add a test for the inferior memory cache (mainly L1)

2020-04-09 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin created this revision.
jarin added reviewers: labath, clayborg.
jarin added a project: LLDB.
Herald added subscribers: lldb-commits, mgorny.

This patch adds a test for L1  of the inferior's 
memory cache and makes the cache testable. This is mostly in preparation for an 
L1  flushing bug fix and its regression test 
(context: https://reviews.llvm.org/D77765).


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D77790

Files:
  lldb/include/lldb/Target/Memory.h
  lldb/include/lldb/Target/Process.h
  lldb/source/Target/Memory.cpp
  lldb/source/Target/Process.cpp
  lldb/unittests/Target/CMakeLists.txt
  lldb/unittests/Target/MemoryCacheTest.cpp

Index: lldb/unittests/Target/MemoryCacheTest.cpp
===
--- /dev/null
+++ lldb/unittests/Target/MemoryCacheTest.cpp
@@ -0,0 +1,126 @@
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "lldb/Target/Memory.h"
+#include "lldb/Utility/Status.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+namespace {
+
+class MemoryCacheTest : public MemoryFromInferiorReader, public testing::Test {
+  static const size_t k_memory_size = 256;
+  static const uint64_t k_cache_line_size = 16;
+
+  size_t ReadMemoryFromInferior(lldb::addr_t vm_addr, void *buf, size_t size,
+Status &error) override {
+m_inferior_read_count++;
+
+if (vm_addr >= m_memory.size())
+  return 0;
+
+size = std::min(size, m_memory.size() - vm_addr);
+memcpy(buf, m_memory.data() + vm_addr, size);
+return size;
+  }
+
+public:
+  MemoryCacheTest()
+  : m_cache(*this, k_cache_line_size), m_inferior_read_count(0) {
+// Fill memory from [0x0 - 0x256) with byte values that match the index. We
+// will use this memory in each test and each test will start with a fresh
+// copy.
+for (size_t i = 0; i < k_memory_size; i++)
+  m_memory.push_back(static_cast(i));
+  }
+
+  void AddRangeToL1Cache(lldb::addr_t addr, size_t len) {
+m_cache.AddL1CacheData(addr, m_memory.data() + addr, len);
+  }
+
+  void IncrementAndFlushRange(lldb::addr_t addr, size_t len) {
+for (size_t i = 0; i < len; i++)
+  m_memory[addr + i]++;
+m_cache.Flush(addr, len);
+  }
+
+  uint8_t ReadByte(lldb::addr_t addr) {
+uint8_t result;
+Status error;
+m_cache.Read(addr, &result, 1, error);
+EXPECT_TRUE(error.Success());
+return result;
+  }
+
+protected:
+  MemoryCache m_cache;
+  std::vector m_memory;
+  size_t m_inferior_read_count;
+};
+
+TEST_F(MemoryCacheTest, L1FlushSimple) {
+  // Add a byte to the cache.
+  AddRangeToL1Cache(10, 1);
+
+  // Sanity check - memory should agree with what ReadByte returns.
+  EXPECT_EQ(10, m_memory[10]);
+  EXPECT_EQ(m_memory[10], ReadByte(10));
+  // Check that we have hit the cache and not the inferior's memory.
+  EXPECT_EQ(0u, m_inferior_read_count);
+
+  IncrementAndFlushRange(10, 1);
+
+  // Check the memory is incremented and the real memory agrees with ReadByte's
+  // result.
+  EXPECT_EQ(11, m_memory[11]);
+  EXPECT_EQ(m_memory[10], ReadByte(10));
+}
+
+// Let us do a parametrized test that caches two ranges. In the test, we then
+// try to modify (and flush) various regions of memory and check that the cache
+// still returns the correct values from reads.
+using AddrRange = Range;
+class MemoryCacheParametrizedTest
+: public MemoryCacheTest,
+  public testing::WithParamInterface {};
+
+TEST_P(MemoryCacheParametrizedTest, L1FlushWithTwoRegions) {
+  // Add two ranges to the cache.
+  std::vector cached = {{10, 10}, {30, 10}};
+  for (AddrRange cached_range : cached)
+AddRangeToL1Cache(cached_range.base, cached_range.size);
+
+  // Flush the range given by the parameter.
+  AddrRange flush_range = GetParam();
+  IncrementAndFlushRange(flush_range.base, flush_range.size);
+
+  // Check that reads from the cached ranges read the inferior's memory
+  // if and only if the flush range intersects with one of the cached ranges.
+  bool has_intersection = false;
+  for (AddrRange cached_range : cached) {
+if (flush_range.DoesIntersect(cached_range))
+  has_intersection = true;
+
+for (size_t i = 0; i < cached_range.size; i++)
+  ReadByte(cached_range.base + i);
+  }
+  EXPECT_EQ(has_intersection, m_inferior_read_count > 0);
+
+  // Sanity check: check the memory contents.
+  for (size_t i = 0; i < 50; i++) {
+EXPECT_EQ(m_memory[i], ReadByte(i)) << " (element at addr=" << i << ")";
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(
+AllMemoryCacheParametrizedTest, MemoryCacheParametrizedTest,
+::testing::Values(AddrRange(5, 6), AddrRange(5, 10), AddrRange(5, 20),
+  AddrRange(5, 30), AddrRange(5, 40), AddrRange(10, 1),
+  AddrRange(10, 21), AddrRange(19, 1), AddrRange(19, 11),
+  AddrRange(19, 12), AddrRange(30, 1), AddrRange(39, 1),
+  Ad

[Lldb-commits] [PATCH] D77790: [NFC] Add a test for the inferior memory cache (mainly L1)

2020-04-09 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 256257.
jarin marked 2 inline comments as done.
jarin added a comment.

Addressed reviewer comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77790/new/

https://reviews.llvm.org/D77790

Files:
  lldb/include/lldb/Target/Memory.h
  lldb/include/lldb/Target/Process.h
  lldb/source/Target/Memory.cpp
  lldb/source/Target/Process.cpp
  lldb/unittests/Target/CMakeLists.txt
  lldb/unittests/Target/MemoryCacheTest.cpp

Index: lldb/unittests/Target/MemoryCacheTest.cpp
===
--- /dev/null
+++ lldb/unittests/Target/MemoryCacheTest.cpp
@@ -0,0 +1,125 @@
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "lldb/Target/Memory.h"
+#include "lldb/Utility/Status.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+namespace {
+
+class MemoryCacheTest : public MemoryFromInferiorReader, public testing::Test {
+  static const size_t k_memory_size = 256;
+  static const uint64_t k_cache_line_size = 16;
+
+  size_t ReadMemoryFromInferior(lldb::addr_t vm_addr, void *buf, size_t size,
+Status &error) override {
+++m_inferior_read_count;
+
+if (vm_addr >= m_memory.size())
+  return 0;
+
+size = std::min(size, m_memory.size() - vm_addr);
+memcpy(buf, m_memory.data() + vm_addr, size);
+return size;
+  }
+
+public:
+  MemoryCacheTest() : m_cache(*this, k_cache_line_size) {
+// Fill memory from [0x0 - 0x256) with byte values that match the index. We
+// will use this memory in each test and each test will start with a fresh
+// copy.
+for (size_t i = 0; i < k_memory_size; ++i)
+  m_memory.push_back(static_cast(i));
+  }
+
+  void AddRangeToL1Cache(lldb::addr_t addr, size_t len) {
+m_cache.AddL1CacheData(addr, m_memory.data() + addr, len);
+  }
+
+  void IncrementAndFlushRange(lldb::addr_t addr, size_t len) {
+for (size_t i = 0; i < len; ++i)
+  ++m_memory[addr + i];
+m_cache.Flush(addr, len);
+  }
+
+  uint8_t ReadByte(lldb::addr_t addr) {
+uint8_t result;
+Status error;
+m_cache.Read(addr, &result, 1, error);
+EXPECT_TRUE(error.Success());
+return result;
+  }
+
+protected:
+  MemoryCache m_cache;
+  std::vector m_memory;
+  size_t m_inferior_read_count = 0;
+};
+
+TEST_F(MemoryCacheTest, L1FlushSimple) {
+  // Add a byte to the cache.
+  AddRangeToL1Cache(10, 1);
+
+  // Sanity check - memory should agree with what ReadByte returns.
+  EXPECT_EQ(10, m_memory[10]);
+  EXPECT_EQ(m_memory[10], ReadByte(10));
+  // Check that we have hit the cache and not the inferior's memory.
+  EXPECT_EQ(0u, m_inferior_read_count);
+
+  IncrementAndFlushRange(10, 1);
+
+  // Check the memory is incremented and the real memory agrees with ReadByte's
+  // result.
+  EXPECT_EQ(11, m_memory[11]);
+  EXPECT_EQ(m_memory[10], ReadByte(10));
+}
+
+// Let us do a parametrized test that caches two ranges. In the test, we then
+// try to modify (and flush) various regions of memory and check that the cache
+// still returns the correct values from reads.
+using AddrRange = Range;
+class MemoryCacheParametrizedTest
+: public MemoryCacheTest,
+  public testing::WithParamInterface {};
+
+TEST_P(MemoryCacheParametrizedTest, L1FlushWithTwoRegions) {
+  // Add two ranges to the cache.
+  std::vector cached = {{10, 10}, {30, 10}};
+  for (AddrRange cached_range : cached)
+AddRangeToL1Cache(cached_range.base, cached_range.size);
+
+  // Flush the range given by the parameter.
+  AddrRange flush_range = GetParam();
+  IncrementAndFlushRange(flush_range.base, flush_range.size);
+
+  // Check that reads from the cached ranges read the inferior's memory
+  // if and only if the flush range intersects with one of the cached ranges.
+  bool has_intersection = false;
+  for (AddrRange cached_range : cached) {
+if (flush_range.DoesIntersect(cached_range))
+  has_intersection = true;
+
+for (size_t i = 0; i < cached_range.size; ++i)
+  ReadByte(cached_range.base + i);
+  }
+  EXPECT_EQ(has_intersection, m_inferior_read_count > 0);
+
+  // Sanity check: check the memory contents.
+  for (size_t i = 0; i < 50; ++i) {
+EXPECT_EQ(m_memory[i], ReadByte(i)) << " (element at addr=" << i << ")";
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(
+AllMemoryCacheParametrizedTest, MemoryCacheParametrizedTest,
+::testing::Values(AddrRange(5, 6), AddrRange(5, 10), AddrRange(5, 20),
+  AddrRange(5, 30), AddrRange(5, 40), AddrRange(10, 1),
+  AddrRange(10, 21), AddrRange(19, 1), AddrRange(19, 11),
+  AddrRange(19, 12), AddrRange(30, 1), AddrRange(39, 1),
+  AddrRange(39, 5), AddrRange(5, 1), AddrRange(5, 5),
+  AddrRange(9, 1), AddrRange(20, 1), AddrRange(20, 10),
+  AddrRange(29, 1), AddrRange(40, 1), AddrRange(40, 10)));
+
+} // namespace
Index: lldb/unittests/Target

[Lldb-commits] [PATCH] D77790: [NFC] Add a test for the inferior memory cache (mainly L1)

2020-04-09 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added inline comments.



Comment at: lldb/source/Target/Memory.cpp:63
 if (pos != m_L1_cache.begin()) {
-  --pos;
+  pos--;
 }

labath wrote:
> I guess this is a leftover from splitting the patches?
> 
> Speaking of post-increment the [[ 
> http://llvm.org/docs/CodingStandards.html#prefer-preincrement | llvm rule ]] 
> is to use pre-increment whereever possible. I see the test uses 
> post-increment exclusively for no good reason.
But, but,... I only increment/decrement in statement position!

Just kidding, I am sorry, fixed now...


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77790/new/

https://reviews.llvm.org/D77790



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D77765: Fix incorrect L1 inferior memory cache flushing

2020-04-09 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

As labath@ suggested, I have teased apart the test and the testability 
refactoring into a separate patch. The patch lives at 
https://reviews.llvm.org/D77790, could you please take a look?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77765/new/

https://reviews.llvm.org/D77765



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D85719: Initialize static const fields in the AST for expression evaluation

2020-08-11 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin created this revision.
jarin added a reviewer: teemperor.
jarin added a project: LLDB.
Herald added subscribers: lldb-commits, JDevlieghere.
Herald added a reviewer: shafik.
jarin requested review of this revision.

This patch is for discussion.

Currently, the evaluator does not know about static const fields if
the code does not contain a definition (but only a declaration).

For example:

  struct C { static const int f = 42; };
  int main() {
return C::f;  // Evaluating C::f does not work here!
  }

This patch tries to fix that by initializing the varDecl of the static
field with the constant value. This works reasonably well when the
static member is only used as rvalue, but any lvalue usage still does
not work because the static member does not have a memory location.

To fix this properly, do we have to teach the materializer about the
static fields, too? What would be the best way to go about that?


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D85719

Files:
  lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
  lldb/test/API/lang/cpp/static_const_members/Makefile
  lldb/test/API/lang/cpp/static_const_members/TestStaticConstMembers.py
  lldb/test/API/lang/cpp/static_const_members/main.cpp

Index: lldb/test/API/lang/cpp/static_const_members/main.cpp
===
--- /dev/null
+++ lldb/test/API/lang/cpp/static_const_members/main.cpp
@@ -0,0 +1,29 @@
+enum class E {
+  E0 = 0,
+  E42 = 42,
+};
+
+struct C {
+  static const int static_const_i32 = 40;
+  static const int static_const_i32_neg = -40;
+  static constexpr int static_constexpr_i32 = 41;
+  static const unsigned static_const_ui32 = 0x;
+  static constexpr unsigned static_constexpr_ui32 = 0xfffe;
+  static const int static_const_var_i32;
+  static constexpr int static_constexpr_i32_other = 43;
+  static const E static_const_enum = E::E42;
+  static const char static_const_i8 = -1;
+};
+
+const int C::static_const_var_i32 = 42;
+constexpr int C::static_constexpr_i32_other;
+
+int deref(const int *p) { return *p; }
+
+int main() {
+  const int *pi = &C::static_constexpr_i32_other;
+  int rv = C::static_const_i32 + C::static_const_i32_neg +
+   C::static_constexpr_i32 + (int)C::static_const_ui32 +
+   C::static_const_var_i32 + deref(pi);
+  return rv; // break here
+}
Index: lldb/test/API/lang/cpp/static_const_members/TestStaticConstMembers.py
===
--- /dev/null
+++ lldb/test/API/lang/cpp/static_const_members/TestStaticConstMembers.py
@@ -0,0 +1,50 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+
+class TestStaticConstMembers(TestBase):
+
+mydir = TestBase.compute_mydir(__file__)
+NO_DEBUG_INFO_TESTCASE = True
+
+def test_static_const_var_definition(self):
+self.build()
+lldbutil.run_to_source_breakpoint(self, "// break here",
+lldb.SBFileSpec("main.cpp", False))
+self.expect_expr("C::static_const_var_i32", result_value="42")
+self.expect_expr("C::static_constexpr_i32_other", result_value="43")
+
+@expectedFailureAll()
+def test_static_const_member_lval(self):
+self.build()
+lldbutil.run_to_source_breakpoint(self, "// break here",
+lldb.SBFileSpec("main.cpp", False))
+self.expect_expr("C::static_const_i32", result_value="40")
+self.expect_expr("C::static_const_i32_neg", result_value="-40")
+self.expect_expr("C::static_constexpr_i32", result_value="41")
+self.expect_expr("C::static_const_ui32", result_value="4294967295")
+self.expect_expr("C::static_const_enum", result_value="E42")
+self.expect_expr("C::static_const_i8", result_value="-1")
+
+def test_static_const_member_rval(self):
+self.build()
+lldbutil.run_to_source_breakpoint(self, "// break here",
+lldb.SBFileSpec("main.cpp", False))
+self.expect_expr("C::static_const_i32 + 2", result_value="42")
+self.expect_expr("-C::static_const_i32_neg", result_value="40")
+self.expect_expr("C::static_constexpr_i32 | 0", result_value="41")
+self.expect_expr("-C::static_const_ui32", result_value="1")
+self.expect_expr("C::static_const_ui32 + 0u", result_value="4294967295")
+self.expect_expr("-C::static_constexpr_ui32", result_value="2")
+self.expect_expr("(int)C::static_const_enum", result_value="42")
+self.expect_expr("C::static_const_i8 + 0", result_value="-1")
+
+@expectedFailureAll()
+def test_static_const_member_address(self):
+self.build()
+lldbutil.run_to_source_breakpoint(self, "// break here",
+lldb.SBFileSpec("main.cpp", False))
+self.expect_expr("deref(&(C::static_const_var_i32))", result_value="42")
+self.expect_expr("deref(&(C::static

[Lldb-commits] [PATCH] D68278: Fix evaluation of nested classes with parent from other CU

2019-10-01 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin created this revision.
Herald added subscribers: lldb-commits, JDevlieghere, teemperor.
Herald added a project: LLDB.

This makes sure that we associate DIEs that are imported from other CUs with 
the appropriate decl context.

Without this fix, nested classes can be dumped directly into their CU context 
if their parent was imported from another CU.


Repository:
  rLLDB LLDB

https://reviews.llvm.org/D68278

Files:
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/Makefile
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/TestNestedClassWithParentInAnotherCU.py
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/main.cpp
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/other.cpp
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/shared.h
  source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Index: source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
===
--- source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -690,6 +690,8 @@
 type_sp = unique_ast_entry_up->m_type_sp;
 if (type_sp) {
   dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
+  LinkDeclContextToDIE(
+  GetCachedClangDeclContextForDIE(unique_ast_entry_up->m_die), die);
   return type_sp;
 }
   }
Index: packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/shared.h
===
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/shared.h
@@ -0,0 +1,17 @@
+struct OuterX {
+  template
+  struct Inner {
+int oX_inner = 42;
+  };
+};
+
+struct OuterY {
+  template
+  struct Inner {
+typename OuterX::Inner oY_inner;
+  };
+};
+
+struct WrapperB;
+
+WrapperB* foo();
Index: packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/other.cpp
===
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/other.cpp
@@ -0,0 +1,10 @@
+#include "shared.h"
+
+struct WrapperB {
+  OuterY y;
+  OuterX x;
+};
+
+WrapperB* foo() {
+  return  new WrapperB();
+}
Index: packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/main.cpp
===
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/main.cpp
@@ -0,0 +1,11 @@
+#include "shared.h"
+
+struct WrapperA {
+  OuterY::Inner y;
+};
+
+int main() {
+  WrapperA a;
+  WrapperB* b = foo();
+  return 0;  // break here
+}
Index: packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/TestNestedClassWithParentInAnotherCU.py
===
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/TestNestedClassWithParentInAnotherCU.py
@@ -0,0 +1,22 @@
+"""
+Test that we can call C++ template fucntions.
+"""
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestNestedClassWithParentInAnotherCU(TestBase):
+mydir = TestBase.compute_mydir(__file__)
+
+def test_nested_class_with_parent_in_another_cu(self):
+self.main_source_file = lldb.SBFileSpec("main.cpp")
+self.build()
+(_, _, thread, _) = lldbutil.run_to_source_breakpoint(self, "// break here", self.main_source_file)
+frame = thread.GetSelectedFrame()
+warmup_result = frame.EvaluateExpression("b")
+self.assertTrue(warmup_result.IsValid())
+expr_result = frame.EvaluateExpression("a.y.oY_inner.oX_inner")
+self.assertTrue(expr_result.IsValid())
+self.assertEqual(expr_result.GetValue(), "42")
Index: packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/Makefile
===
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp other.cpp
+
+include $(LEVEL)/Makefile.rules
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D68278: Fix evaluation of nested classes with parent from other CU

2019-10-01 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 222756.
jarin added a comment.

I have added some comments to the test (I hope it is not too overboard), 
removed the LEVEL stuff from the Makefile and fixed the formatting.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68278/new/

https://reviews.llvm.org/D68278

Files:
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/Makefile
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/TestNestedClassWithParentInAnotherCU.py
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/main.cpp
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/other.cpp
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/shared.h
  source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Index: source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
===
--- source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -690,6 +690,8 @@
 type_sp = unique_ast_entry_up->m_type_sp;
 if (type_sp) {
   dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
+  LinkDeclContextToDIE(
+  GetCachedClangDeclContextForDIE(unique_ast_entry_up->m_die), die);
   return type_sp;
 }
   }
Index: packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/shared.h
===
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/shared.h
@@ -0,0 +1,17 @@
+struct OuterX {
+  template
+  struct Inner {
+int oX_inner = 42;
+  };
+};
+
+struct OuterY {
+  template
+  struct Inner {
+typename OuterX::Inner oY_inner;
+  };
+};
+
+struct WrapperB;
+
+WrapperB* foo();
Index: packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/other.cpp
===
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/other.cpp
@@ -0,0 +1,10 @@
+#include "shared.h"
+
+struct WrapperB {
+  OuterY y;
+  OuterX x;
+};
+
+WrapperB* foo() {
+  return new WrapperB();
+}
Index: packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/main.cpp
===
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/main.cpp
@@ -0,0 +1,22 @@
+#include "shared.h"
+
+struct WrapperA {
+  OuterY::Inner y;
+};
+
+int main() {
+  // WrapperA refers to the Inner and Outer class DIEs from this CU.
+  WrapperA a;
+  // WrapperB refers to the Inner and Outer DIEs from the other.cpp CU.
+  // It is important that WrapperB is only foward-declared in shared.h.
+  WrapperB* b = foo();
+
+  // Evaluating 'b' here will parse other.cpp's DIEs for all
+  // the Inner and Outer classes from shared.h.
+  //
+  // Evaluating 'a' here will find and reuse the already-parsed
+  // versions of the Inner and Outer classes. In the associated test
+  // we make sure that we can still resolve all the types properly
+  // by evaluating 'a.y.oY_inner.oX_inner'.
+  return 0;  // break here
+}
Index: packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/TestNestedClassWithParentInAnotherCU.py
===
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/TestNestedClassWithParentInAnotherCU.py
@@ -0,0 +1,29 @@
+"""
+Test that expression evaluator can access members of nested classes even if
+the parents of the nested classes where imported from another compilation unit.
+"""
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestNestedClassWithParentInAnotherCU(TestBase):
+mydir = TestBase.compute_mydir(__file__)
+
+def test_nested_class_with_parent_in_another_cu(self):
+self.main_source_file = lldb.SBFileSpec("main.cpp")
+self.build()
+(_, _, thread, _) = lldbutil.run_to_source_breakpoint(self, "// break here", self.main_source_file)
+frame = thread.GetSelectedFrame()
+# Parse the DIEs of the parent classes and the nested classes from
+# other.cpp's CU.
+warmup_result = frame.EvaluateExpression("b")
+self.assertTrue(warmup_result.IsValid())
+# Inspect fields of the nested classes. This will reuse the types that
+# were parsed during the evaluation above. By accessing a chain of
+# fields, we try to verify that all the DIEs, reused types and
+# declaration contexts were wired properly into lldb's parser's state.
+expr_result = frame.EvaluateExpression("a.y.oY_inner.oX_inner")
+self.assertTrue(expr_

[Lldb-commits] [PATCH] D68278: Fix evaluation of nested classes with parent from other CU

2019-10-01 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 222757.
jarin added a comment.

Fixed a typo.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68278/new/

https://reviews.llvm.org/D68278

Files:
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/Makefile
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/TestNestedClassWithParentInAnotherCU.py
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/main.cpp
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/other.cpp
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/shared.h
  source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Index: source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
===
--- source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -690,6 +690,8 @@
 type_sp = unique_ast_entry_up->m_type_sp;
 if (type_sp) {
   dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
+  LinkDeclContextToDIE(
+  GetCachedClangDeclContextForDIE(unique_ast_entry_up->m_die), die);
   return type_sp;
 }
   }
Index: packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/shared.h
===
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/shared.h
@@ -0,0 +1,17 @@
+struct OuterX {
+  template
+  struct Inner {
+int oX_inner = 42;
+  };
+};
+
+struct OuterY {
+  template
+  struct Inner {
+typename OuterX::Inner oY_inner;
+  };
+};
+
+struct WrapperB;
+
+WrapperB* foo();
Index: packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/other.cpp
===
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/other.cpp
@@ -0,0 +1,10 @@
+#include "shared.h"
+
+struct WrapperB {
+  OuterY y;
+  OuterX x;
+};
+
+WrapperB* foo() {
+  return new WrapperB();
+}
Index: packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/main.cpp
===
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/main.cpp
@@ -0,0 +1,22 @@
+#include "shared.h"
+
+struct WrapperA {
+  OuterY::Inner y;
+};
+
+int main() {
+  // WrapperA refers to the Inner and Outer class DIEs from this CU.
+  WrapperA a;
+  // WrapperB refers to the Inner and Outer DIEs from the other.cpp CU.
+  // It is important that WrapperB is only foward-declared in shared.h.
+  WrapperB* b = foo();
+
+  // Evaluating 'b' here will parse other.cpp's DIEs for all
+  // the Inner and Outer classes from shared.h.
+  //
+  // Evaluating 'a' here will find and reuse the already-parsed
+  // versions of the Inner and Outer classes. In the associated test
+  // we make sure that we can still resolve all the types properly
+  // by evaluating 'a.y.oY_inner.oX_inner'.
+  return 0;  // break here
+}
Index: packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/TestNestedClassWithParentInAnotherCU.py
===
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/TestNestedClassWithParentInAnotherCU.py
@@ -0,0 +1,29 @@
+"""
+Test that expression evaluator can access members of nested classes even if
+the parents of the nested classes were imported from another compilation unit.
+"""
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestNestedClassWithParentInAnotherCU(TestBase):
+mydir = TestBase.compute_mydir(__file__)
+
+def test_nested_class_with_parent_in_another_cu(self):
+self.main_source_file = lldb.SBFileSpec("main.cpp")
+self.build()
+(_, _, thread, _) = lldbutil.run_to_source_breakpoint(self, "// break here", self.main_source_file)
+frame = thread.GetSelectedFrame()
+# Parse the DIEs of the parent classes and the nested classes from
+# other.cpp's CU.
+warmup_result = frame.EvaluateExpression("b")
+self.assertTrue(warmup_result.IsValid())
+# Inspect fields of the nested classes. This will reuse the types that
+# were parsed during the evaluation above. By accessing a chain of
+# fields, we try to verify that all the DIEs, reused types and
+# declaration contexts were wired properly into lldb's parser's state.
+expr_result = frame.EvaluateExpression("a.y.oY_inner.oX_inner")
+self.assertTrue(expr_result.IsValid())
+self.assertEqual(expr_result.GetValue(), "42")
Index: packages/Python/lldbsuite/test/lang/cpp/nested-c

[Lldb-commits] [PATCH] D68278: Fix evaluation of nested classes with parent from other CU

2019-10-02 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added inline comments.



Comment at: 
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/TestNestedClassWithParentInAnotherCU.py:2
+"""
+Test that expression evaluator can access members of nested classes even if
+the parents of the nested classes were imported from another compilation unit.

teemperor wrote:
> missing 'the' between 'that' and 'expression evaluator'. Also a missing 'a' 
> between 'of' and 'nested'.
Fixing "the expression evaluator"; "of a nested classes" does not sound right, 
though.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68278/new/

https://reviews.llvm.org/D68278



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D68278: Fix evaluation of nested classes with parent from other CU

2019-10-02 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 222803.
jarin marked 5 inline comments as done.
jarin added a comment.

Fixed the nits, thanks for the careful review!

I will indeed need someone to submit this for me. Thanks in advance :-)


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68278/new/

https://reviews.llvm.org/D68278

Files:
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/Makefile
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/TestNestedClassWithParentInAnotherCU.py
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/main.cpp
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/other.cpp
  
packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/shared.h
  source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Index: source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
===
--- source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -690,6 +690,8 @@
 type_sp = unique_ast_entry_up->m_type_sp;
 if (type_sp) {
   dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
+  LinkDeclContextToDIE(
+  GetCachedClangDeclContextForDIE(unique_ast_entry_up->m_die), die);
   return type_sp;
 }
   }
Index: packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/shared.h
===
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/shared.h
@@ -0,0 +1,17 @@
+struct OuterX {
+  template
+  struct Inner {
+int oX_inner = 42;
+  };
+};
+
+struct OuterY {
+  template
+  struct Inner {
+typename OuterX::Inner oY_inner;
+  };
+};
+
+struct WrapperB;
+
+WrapperB* foo();
Index: packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/other.cpp
===
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/other.cpp
@@ -0,0 +1,10 @@
+#include "shared.h"
+
+struct WrapperB {
+  OuterY y;
+  OuterX x;
+};
+
+WrapperB* foo() {
+  return new WrapperB();
+}
Index: packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/main.cpp
===
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/main.cpp
@@ -0,0 +1,22 @@
+#include "shared.h"
+
+struct WrapperA {
+  OuterY::Inner y;
+};
+
+int main() {
+  // WrapperA refers to the Inner and Outer class DIEs from this CU.
+  WrapperA a;
+  // WrapperB refers to the Inner and Outer DIEs from the other.cpp CU.
+  // It is important that WrapperB is only forward-declared in shared.h.
+  WrapperB* b = foo();
+
+  // Evaluating 'b' here will parse other.cpp's DIEs for all
+  // the Inner and Outer classes from shared.h.
+  //
+  // Evaluating 'a' here will find and reuse the already-parsed
+  // versions of the Inner and Outer classes. In the associated test
+  // we make sure that we can still resolve all the types properly
+  // by evaluating 'a.y.oY_inner.oX_inner'.
+  return 0;  // break here
+}
Index: packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/TestNestedClassWithParentInAnotherCU.py
===
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/nested-class-other-compilation-unit/TestNestedClassWithParentInAnotherCU.py
@@ -0,0 +1,29 @@
+"""
+Test that the expression evaluator can access members of nested classes even if
+the parents of the nested classes were imported from another compilation unit.
+"""
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestNestedClassWithParentInAnotherCU(TestBase):
+mydir = TestBase.compute_mydir(__file__)
+
+def test_nested_class_with_parent_in_another_cu(self):
+self.main_source_file = lldb.SBFileSpec("main.cpp")
+self.build()
+(_, _, thread, _) = lldbutil.run_to_source_breakpoint(self, "// break here", self.main_source_file)
+frame = thread.GetSelectedFrame()
+# Parse the DIEs of the parent classes and the nested classes from
+# other.cpp's CU.
+warmup_result = frame.EvaluateExpression("b")
+self.assertTrue(warmup_result.IsValid())
+# Inspect fields of the nested classes. This will reuse the types that
+# were parsed during the evaluation above. By accessing a chain of
+# fields, we try to verify that all the DIEs, reused types and
+# declaration contexts were wired properly into lldb's parser's state.
+expr_result = frame.EvaluateExpression("a.y.oY_inner.oX_inner")
+   

[Lldb-commits] [PATCH] D68454: Fix the unwinding plan augmentation from x86 assembly

2019-10-04 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin created this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

Unwind plan augmentation should compute the plan row at offset x from the 
instruction before offset x, but currently we compute it from the instruction 
at offset x. Note that this behavior is a regression introduced when moving the 
x86 assembly inspection engine to its own file 
(https://github.com/llvm/llvm-project/commit/1c9858b298d79ce82c45a2954096718b39550109#diff-375a2be066db6f34bb9a71442c9b71fcL913);
 the original version handled this properly by copying the previous instruction 
out before advancing the instruction pointer.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D68454

Files:
  lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
  lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp

Index: lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
===
--- lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
+++ lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
@@ -2199,6 +2199,97 @@
   EXPECT_EQ(-40, regloc.GetOffset());
 }
 
+TEST_F(Testx86AssemblyInspectionEngine, TestSpArithx86_64Augmented) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr engine64 = Getx86_64Inspector();
+
+  uint8_t data[] = {
+  0x55, // pushq %rbp
+  0x48, 0x89, 0xe5, // movq %rsp, %rbp
+
+  // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
+  // has a bug where it can't augment a function that is just
+  // prologue+epilogue - it needs at least one other instruction
+  // in between.
+
+  0x90,// nop
+  0x48, 0x81, 0xec, 0x88, 0, 0, 0, // subq   $0x88, %rsp
+  0x90,// nop
+  0x48, 0x81, 0xc4, 0x88, 0, 0, 0, // addq   $0x88, %rsp
+
+  0x5d, // popq %rbp
+  0xc3  // retq
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  unwind_plan.SetSourceName("unit testing hand-created unwind plan");
+  unwind_plan.SetPlanValidAddressRange(sample_range);
+  unwind_plan.SetRegisterKind(eRegisterKindLLDB);
+
+  row_sp = std::make_shared();
+
+  // Describe offset 0
+  row_sp->SetOffset(0);
+  row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 8);
+
+  regloc.SetAtCFAPlusOffset(-8);
+  row_sp->SetRegisterInfo(k_rip, regloc);
+
+  unwind_plan.AppendRow(row_sp);
+
+  // Allocate a new Row, populate it with the existing Row contents.
+  UnwindPlan::Row *new_row = new UnwindPlan::Row;
+  *new_row = *row_sp.get();
+  row_sp.reset(new_row);
+
+  // Describe offset 1
+  row_sp->SetOffset(1);
+  row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16);
+  regloc.SetAtCFAPlusOffset(-16);
+  row_sp->SetRegisterInfo(k_rbp, regloc);
+  unwind_plan.AppendRow(row_sp);
+
+  // Allocate a new Row, populate it with the existing Row contents.
+  new_row = new UnwindPlan::Row;
+  *new_row = *row_sp.get();
+  row_sp.reset(new_row);
+
+  // Describe offset 4
+  row_sp->SetOffset(4);
+  row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16);
+  unwind_plan.AppendRow(row_sp);
+
+  RegisterContextSP reg_ctx_sp;
+  EXPECT_TRUE(engine64->AugmentUnwindPlanFromCallSite(
+  data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
+
+  // Before we touch the stack pointer, we should still refer to the
+  // row from after the prologue.
+  row_sp = unwind_plan.GetRowForFunctionOffset(5);
+  EXPECT_EQ(4ull, row_sp->GetOffset());
+
+  // Check the first stack pointer update.
+  row_sp = unwind_plan.GetRowForFunctionOffset(12);
+  EXPECT_EQ(12ull, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_EQ(152, row_sp->GetCFAValue().GetOffset());
+
+  // After the nop, we should still refer to the same row.
+  row_sp = unwind_plan.GetRowForFunctionOffset(13);
+  EXPECT_EQ(12ull, row_sp->GetOffset());
+
+  // Check that the second stack pointer update is reflected in the
+  // unwind plan.
+  row_sp = unwind_plan.GetRowForFunctionOffset(20);
+  EXPECT_EQ(20ull, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+}
+
 TEST_F(Testx86AssemblyInspectionEngine, TestSimplex86_64Augmented) {
   UnwindPlan::Row::RegisterLocation regloc;
   UnwindPlan::RowSP row_sp;
Index: lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
===
--- lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
+++ lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
@@ -1371,7 +1371,6 @@
   int row_id = 1;
   bool unwind_plan_updated = false;
   UnwindPlan::RowSP row(new UnwindPlan::Row(*first_row));
-  m_cur_insn =

[Lldb-commits] [PATCH] D68454: Fix the unwinding plan augmentation from x86 assembly

2019-10-09 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a reviewer: labath.
jarin added a comment.

Pavel, could you possibly take a look? It looks like Jason is busy with 
something else...


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68454/new/

https://reviews.llvm.org/D68454



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D68454: Fix the unwinding plan augmentation from x86 assembly

2019-10-10 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Thank you for the review! Could you also possibly commit the change for me?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68454/new/

https://reviews.llvm.org/D68454



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D69309: Support template instantiation in the expression evaluator

2019-10-22 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin created this revision.
Herald added subscribers: lldb-commits, arphaman, aprantl.
Herald added a project: LLDB.

WORK IN PROGRESS

This change is mostly for discussion, it is messy and likely wrong as I am new 
to the lldb codebase.

The goal of this exercise is to support expressions containing template 
instantiations, e.g. foo::x.

The idea here is to collect all template types in the dwarf index. Later, when 
asked to find a name X, we import all the instantiations of X and pass the 
template declaration with the instantiations to Clang. In addition to my poor 
abstraction skills, the major problem with this is that we need to import all 
the instantiations even when only one is used. I tried to only import forward 
declarations, but if the instantiations were already previously completed, the 
AST importer still imports everything. This leads to massive evaluation times 
(tens of seconds) on templates with many instantiations (std::vector and the 
likes).

I am planning to pursue a different avenue, where I would introduce another 
hook into clang (perhaps in Sema::CheckTemplateIdType), but I am not sure how 
viable that path is.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D69309

Files:
  
lldb/packages/Python/lldbsuite/test/lang/cpp/class-template-instantiation/Makefile
  
lldb/packages/Python/lldbsuite/test/lang/cpp/class-template-instantiation/TestClassTemplateInstantiation.py
  
lldb/packages/Python/lldbsuite/test/lang/cpp/class-template-instantiation/main.cpp
  lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
  lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp
  lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h
  lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
  lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
  lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h
  lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
  lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Symbol/TypeMap.cpp

Index: lldb/source/Symbol/TypeMap.cpp
===
--- lldb/source/Symbol/TypeMap.cpp
+++ lldb/source/Symbol/TypeMap.cpp
@@ -141,6 +141,27 @@
exact_match);
 }
 
+namespace {
+
+bool TypeBasenamesMatch(const std::string &type_basename,
+llvm::StringRef match_type_basename,
+bool is_instantiation) {
+  if (match_type_basename == type_basename)
+return true;
+  // If the basenames do not match, let us see if {match_type_basename} could
+  // be an instantiation of {type_basename}.
+  if (is_instantiation)
+return false;
+  size_t basename_size = type_basename.size();
+  if (match_type_basename.size() <= basename_size)
+return false;
+  if (match_type_basename[basename_size] != '<')
+return false;
+  return match_type_basename.take_front(basename_size) == type_basename;
+}
+
+} // namespace
+
 void TypeMap::RemoveMismatchedTypes(const std::string &type_scope,
 const std::string &type_basename,
 TypeClass type_class, bool exact_match) {
@@ -152,6 +173,8 @@
 
   iterator pos, end = m_types.end();
 
+  bool is_instantiation = type_basename.find('<') != std::string::npos;
+
   for (pos = m_types.begin(); pos != end; ++pos) {
 Type *the_type = pos->second.get();
 bool keep_match = false;
@@ -171,7 +194,8 @@
   if (Type::GetTypeScopeAndBasename(match_type_name, match_type_scope,
 match_type_basename,
 match_type_class)) {
-if (match_type_basename == type_basename) {
+if (TypeBasenamesMatch(type_basename, match_type_basename,
+   is_instantiation)) {
   const size_t type_scope_size = type_scope.size();
   const size_t match_type_scope_size = match_type_scope.size();
   if (exact_match || (type_scope_size == match_type_scope_size)) {
@@ -203,7 +227,9 @@
   } else {
 // The type we are currently looking at doesn't exists in a namespace
 // or class, so it only matches if there is no type scope...
-keep_match = type_scope.empty() && type_basename == match_type_name;
+keep_match = type_scope.empty() &&
+ TypeBasenamesMatch(type_basename, match_type_name,
+is_instantiation);
   }
 }
 
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2419,6 +2419,24 @@
 }
   }
 
+  die_offsets.clear();
+  m_index->GetGenericTypes(name, die_offsets);
+  for (size_t i = 0; i < die_offsets.size(); ++i) {

[Lldb-commits] [PATCH] D69843: Expression eval lookup - prune methods without parsing

2019-11-05 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin created this revision.
jarin added a reviewer: labath.
jarin added a project: LLDB.
Herald added subscribers: lldb-commits, aprantl.

In large codebases, we sometimes see Module::FindFunctions (when called from
ClangExpressionDeclMap::FindExternalVisibleDecls) returning huge amounts of
functions. For example, a simple unreal engine example contains

> 1 of functions with the name 'operator*'. Evaluating an expression "*x",

where x is an instance of a class, will cause all those function's decl
contexts to be parsed, taking multiple seconds. However, most of those
parsed contexts will be immediately thrown away because most of the
functions are methods.

With this patch, I am trying to avoid the parsing by checking method-ness
directly from debug info rather than from parsed contexts. This helps a lot:
our unreal engine expression evaluation pause goes roughly from 4.5s to 0.3s.

However, my patch feels wrong - ideally, we would ignore methods already
during lookup (in ManualDWARFIndex::GetFunctions).

A resonable solution would be to change the meaning of
eFunctionNameTypeFull to only mean mangled names, and if the caller
wanted methods and basenames, they would have to call with
eFunctionNameTypeFull | eFunctionNameTypeMethod |
eFunctionNameTypeBase. This would require some amount churn at
(Get|Find)Functions call sites. Also, I am not sure about implications
for Apple's lookup index.

Thoughts?


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D69843

Files:
  lldb/include/lldb/Symbol/Function.h
  lldb/include/lldb/Symbol/SymbolFile.h
  lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
  lldb/source/Symbol/Function.cpp


Index: lldb/source/Symbol/Function.cpp
===
--- lldb/source/Symbol/Function.cpp
+++ lldb/source/Symbol/Function.cpp
@@ -454,6 +454,16 @@
   return CompilerDeclContext();
 }
 
+bool Function::CanBeMethod() {
+  ModuleSP module_sp = CalculateSymbolContextModule();
+
+  if (module_sp) {
+if (SymbolFile *sym_file = module_sp->GetSymbolFile())
+  return sym_file->CanBeMethod(GetID());
+  }
+  return true;
+}
+
 Type *Function::GetType() {
   if (m_type == nullptr) {
 SymbolContext sc;
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
===
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -144,6 +144,8 @@
   lldb_private::CompilerDeclContext
   GetDeclContextContainingUID(lldb::user_id_t uid) override;
 
+  bool CanBeMethod(lldb::user_id_t uid) override;
+
   void
   ParseDeclsForContext(lldb_private::CompilerDeclContext decl_ctx) override;
 
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -1314,6 +1314,16 @@
   return CompilerDeclContext();
 }
 
+bool SymbolFileDWARF::CanBeMethod(lldb::user_id_t uid) {
+  std::lock_guard guard(GetModuleMutex());
+  // Anytime we have a lldb::user_id_t, we must get the DIE by calling
+  // SymbolFileDWARF::GetDIE(). See comments inside the
+  // SymbolFileDWARF::GetDIE() for details.
+  if (DWARFDIE die = GetDIE(uid))
+return die.IsMethod();
+  return true;
+}
+
 Type *SymbolFileDWARF::ResolveTypeUID(lldb::user_id_t type_uid) {
   std::lock_guard guard(GetModuleMutex());
   // Anytime we have a lldb::user_id_t, we must get the DIE by calling
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
===
--- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -1292,6 +1292,8 @@
   // Filter out functions without declaration contexts, as well as
   // class/instance methods, since they'll be skipped in the code that
   // follows anyway.
+  if (function->CanBeMethod())
+continue;
   CompilerDeclContext func_decl_context = function->GetDeclContext();
   if (!func_decl_context ||
   func_decl_context.IsClassMethod(nullptr, nullptr, nullptr))
Index: lldb/include/lldb/Symbol/SymbolFile.h
===
--- lldb/include/lldb/Symbol/SymbolFile.h
+++ lldb/include/lldb/Symbol/SymbolFile.h
@@ -164,6 +164,7 @@
   virtual CompilerDeclContext GetDeclContextContainingUID(lldb::user_id_t uid) 
{
 return CompilerDeclContext();
   }
+  virtual bool CanBeMethod(lldb::user_id_t uid) { return true; }
   virtual uint32_t ResolveSymbolContext(const Address &so_addr,
   

[Lldb-commits] [PATCH] D69843: Expression eval lookup - prune methods without parsing

2019-11-06 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Thanks for the feedback! We will experiment with filtering in GetFunctions 
sometime next week.

Regarding the FindTypes patch, it would be really nice to have that for Linux, 
as well. I see the type pruning (TypeMap::RemoveMismatchedTypes) taking several 
seconds for some expression evaluations; it is likely to be the same problem 
you are solving.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69843/new/

https://reviews.llvm.org/D69843



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D69309: Support template instantiation in the expression evaluator

2019-11-19 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 230069.
jarin added a comment.

This update introduces a callback from clang for template specialization. The 
callback allows lldb to construct instantiations on demand, rather than having 
to create the instantiation eagerly.

Perhaps it would still beneficial to prune the instantiations (we only need one 
"sample" instantiation per template) when querying the generic type from the 
symbol file so that we do not have to parse all the instantiations eagerly.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69309/new/

https://reviews.llvm.org/D69309

Files:
  clang/include/clang/AST/ExternalASTSource.h
  clang/lib/AST/ExternalASTSource.cpp
  clang/lib/Sema/SemaTemplate.cpp
  
lldb/packages/Python/lldbsuite/test/lang/cpp/class-template-instantiation/Makefile
  
lldb/packages/Python/lldbsuite/test/lang/cpp/class-template-instantiation/TestClassTemplateInstantiation.py
  
lldb/packages/Python/lldbsuite/test/lang/cpp/class-template-instantiation/main.cpp
  lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
  lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
  lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp
  lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h
  lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
  lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
  lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h
  lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
  lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Symbol/TypeMap.cpp

Index: lldb/source/Symbol/TypeMap.cpp
===
--- lldb/source/Symbol/TypeMap.cpp
+++ lldb/source/Symbol/TypeMap.cpp
@@ -141,6 +141,27 @@
exact_match);
 }
 
+namespace {
+
+bool TypeBasenamesMatch(const std::string &type_basename,
+llvm::StringRef match_type_basename,
+bool is_instantiation) {
+  if (match_type_basename == type_basename)
+return true;
+  // If the basenames do not match, let us see if {match_type_basename} could
+  // be an instantiation of {type_basename}.
+  if (is_instantiation)
+return false;
+  size_t basename_size = type_basename.size();
+  if (match_type_basename.size() <= basename_size)
+return false;
+  if (match_type_basename[basename_size] != '<')
+return false;
+  return match_type_basename.take_front(basename_size) == type_basename;
+}
+
+} // namespace
+
 void TypeMap::RemoveMismatchedTypes(const std::string &type_scope,
 const std::string &type_basename,
 TypeClass type_class, bool exact_match) {
@@ -152,6 +173,8 @@
 
   iterator pos, end = m_types.end();
 
+  bool is_instantiation = type_basename.find('<') != std::string::npos;
+
   for (pos = m_types.begin(); pos != end; ++pos) {
 Type *the_type = pos->second.get();
 bool keep_match = false;
@@ -171,7 +194,8 @@
   if (Type::GetTypeScopeAndBasename(match_type_name, match_type_scope,
 match_type_basename,
 match_type_class)) {
-if (match_type_basename == type_basename) {
+if (TypeBasenamesMatch(type_basename, match_type_basename,
+   is_instantiation)) {
   const size_t type_scope_size = type_scope.size();
   const size_t match_type_scope_size = match_type_scope.size();
   if (exact_match || (type_scope_size == match_type_scope_size)) {
@@ -203,7 +227,9 @@
   } else {
 // The type we are currently looking at doesn't exists in a namespace
 // or class, so it only matches if there is no type scope...
-keep_match = type_scope.empty() && type_basename == match_type_name;
+keep_match = type_scope.empty() &&
+ TypeBasenamesMatch(type_basename, match_type_name,
+is_instantiation);
   }
 }
 
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2499,6 +2499,24 @@
 }
   }
 
+  die_offsets.clear();
+  m_index->GetGenericTypes(name, die_offsets);
+  for (size_t i = 0; i < die_offsets.size(); ++i) {
+const DIERef &die_ref = die_offsets[i];
+DWARFDIE die = GetDIE(die_ref);
+if (die) {
+  if (!DIEInDeclContext(parent_decl_ctx, die))
+continue; // The containing decl contexts don't match
+  if (Type *matching_type = ResolveType(die, true, true)) {
+types.InsertUnique(matching_type->shared_from_this());
+if (types.GetSize() >= max_matches)
+  break;
+  }
+} else {
+  m_index->ReportIn

[Lldb-commits] [PATCH] D90318: Return actual type from SBType::GetArrayElementType

2020-10-28 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin accepted this revision.
jarin added a comment.
This revision is now accepted and ready to land.

The code change looks good to me and it is in line with the change that Raphael 
and Greg wanted in https://reviews.llvm.org/D72133. As far as I remember, 
https://reviews.llvm.org/D72133 did not change the previous behavior because I 
felt that changing API semantics was out of scope of what I wanted to do with 
the formatters.

Someone else should look at the test. The addition seems to be a bit ad-hoc, 
but overall reasonable.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D90318/new/

https://reviews.llvm.org/D90318

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D77790: [NFC] Add a test for the inferior memory cache (mainly L1)

2020-04-10 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Regarding the callback idea, I have bad experience with callbacks because they 
break if the code is not crafted for re-entrancy and they are much harder to 
understand. That change feels out of scope for just adding a test and fixing an 
unrelated bug.

Adding the SetCacheLineSize method sounds good, but if we want to keep this 
patch making NFC (which is what I would prefer), it would have to be called at 
exactly the same places as Clear. How about Pavel's idea to rename Clear -> 
Reset, and leave the refactoring to SetCacheLineSize for later?

It appears it is really hard to reach agreement about this, so another 
alternative is I submit a bug report about the L1  
invalidation problem and leave it to you to figure this out. In the mean time, 
we will fix the bug only in our private fork of lldb. Greg, perhaps you would 
prefer that?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77790/new/

https://reviews.llvm.org/D77790



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D77790: [NFC] Add a test for the inferior memory cache (mainly L1)

2020-04-11 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

In D77790#1975324 , @clayborg wrote:

> In D77790#1974047 , @jarin wrote:
>
> > It appears it is really hard to reach agreement about this, so another 
> > alternative is I submit a bug report about the L1 
> >  invalidation problem and leave it to you to 
> > figure this out. In the mean time, we will fix the bug only in our private 
> > fork of lldb. Greg, perhaps you would prefer that?
>
>
> I don't see this as really that hard to fix correctly. Feel free to do what 
> you need to if this is too much.


Ack, abandoning.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77790/new/

https://reviews.llvm.org/D77790



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D77765: Fix incorrect L1 inferior memory cache flushing

2020-04-11 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Abandoning the patch since we cannot reach agreement on how this should be 
tested.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77765/new/

https://reviews.llvm.org/D77765



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D79308: [lldb-server] Reset stop reason of all threads when resuming

2020-05-03 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin created this revision.
jarin added a reviewer: jingham.
jarin added a project: LLDB.
Herald added a subscriber: lldb-commits.

This patch makes the stop reason reset logic similar to MacOS' debugserver, 
where exceptions are reset for all threads when resuming process for stepping 
or continuing (see MachThreadList::ProcessWillResume 

 and MachThread::ThreadWillResume 
).

Resetting stop reasons on resume fixes problems where LLDB spuriously reports 
SIGTRAP signal stop reason for deleted breakpoints (both internal and public) 
and where  LLDB stops on an internal breakpoint while stepping over while a 
breakpoint is hit in another thread. See PR45642 
 for details.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D79308

Files:
  lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
  lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
  lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
  lldb/test/API/functionalities/thread/break_step_other/Makefile
  
lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py
  lldb/test/API/functionalities/thread/break_step_other/main.cpp

Index: lldb/test/API/functionalities/thread/break_step_other/main.cpp
===
--- /dev/null
+++ lldb/test/API/functionalities/thread/break_step_other/main.cpp
@@ -0,0 +1,20 @@
+#include 
+
+volatile int g_test = 0;
+
+void thread_func () {
+g_test = 0;  // break here
+
+while (true) {
+  g_test++;
+}
+}
+
+int main () {
+std::thread thread_1(thread_func);
+std::thread thread_2(thread_func);
+
+thread_1.join();
+thread_2.join();
+return 0;
+}
Index: lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py
===
--- /dev/null
+++ lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py
@@ -0,0 +1,68 @@
+"""
+Test stop reasons after hitting and deleting a breakpoint and
+stepping another thread. Scenario:
+  - run two threads
+  - stop one thread at a breakpoint
+  - delete the breakpoint
+  - single step the other thread
+The thread stopped at the deleted breakpoint should have stop reason
+'none'.
+"""
+
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class ThreadBreakStepOtherTestCase(TestBase):
+mydir = TestBase.compute_mydir(__file__)
+
+def test_hit_breakpoint_delete_step_other_thread(self):
+self.main_source_file = lldb.SBFileSpec("main.cpp")
+self.build()
+(target, process, thread, breakpoint) = lldbutil.run_to_source_breakpoint(
+self, "// break here", self.main_source_file, only_one_thread = False)
+
+# Make sure both threads reach the breakpoint so that we are
+# sure both threads started. Also remember the thread that is
+# stopped at the breakpoint and the other thread.
+stopped_threads = lldbutil.get_threads_stopped_at_breakpoint(
+process, breakpoint)
+if len(stopped_threads) == 1:
+other_thread = stopped_threads[0]
+process.Continue()
+stopped_threads = lldbutil.get_threads_stopped_at_breakpoint(
+process, breakpoint)
+self.assertEquals(
+1,
+len(stopped_threads),
+"only one thread expected stopped at breakpoint")
+breakpoint_thread = stopped_threads[0]
+else:
+self.assertEquals(
+2,
+len(stopped_threads),
+"unexpected number of threads stopped at breakpoint")
+other_thread = stopped_threads[0]
+breakpoint_thread = stopped_threads[1]
+
+target.BreakpointDelete(breakpoint.GetID())
+
+other_thread.StepInstruction(False)
+
+reason = other_thread.GetStopReason()
+self.assertEqual(
+lldb.eStopReasonPlanComplete,
+reason,
+"Expected thread stop reason 'plancomplete', but got '%s'" %
+lldbutil.stop_reason_to_str(reason))
+
+reason = breakpoint_thread.GetStopReason()
+self.assertEqual(
+lldb.eStopReasonNone,
+reason,
+"Expected thread stop reason 'none', but got '%s'" %
+lldbutil.stop_reason_to_str(reason))
Index: lldb/test/API/functionalities/thread/break_step_other/Makefile
===
--- /dev/null
+++ lldb/test/API/functionalities/thread/break_step

[Lldb-commits] [PATCH] D79308: [lldb-server] Reset stop reason of all threads when resuming

2020-05-04 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

In D79308#2017348 , @labath wrote:

> The test setup here seems unnecessarily complex. Wouldn't an inferior like 
> this work better?
>
>   void thread1() {
> pseudo_barrier_wait(g_barrier); // See other tests how this works.
> g_foo = 0; // break_here
>   }
>   int main() {
> pseudo_barrier_init(g_barrier1, 2);
> std::thread t1(thread1);
> pseudo_barrier_wait(g_barrier);
> for (int i = 0; i<1; ++i) g_bar = i; // empty loop to have something 
> to step over
> t1.join();
>   }
>
>
> That way you always know only one thread will hit a breakpoint, and and you 
> can just pick the "other" thread as the target for stepping.


Yeah, I considered something like that, but then I thought it would be better 
if the "other" thread only runs code that we completely control. In my patch, 
the "other" thread is guaranteed to be in thread_func after we hit the 
breakpoint. In your suggested inferior, it could be still in 
pseudo_barrier_wait. If you feel stepping in external code is safe, I am happy 
to rewrite the test to the simpler version.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D79308/new/

https://reviews.llvm.org/D79308



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D79308: [lldb-server] Reset stop reason of all threads when resuming

2020-05-04 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 261805.
jarin added a comment.

Simplify the test based on the suggestion from labath@.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D79308/new/

https://reviews.llvm.org/D79308

Files:
  lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
  lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
  lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
  lldb/test/API/functionalities/thread/break_step_other/Makefile
  
lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py
  lldb/test/API/functionalities/thread/break_step_other/main.cpp

Index: lldb/test/API/functionalities/thread/break_step_other/main.cpp
===
--- /dev/null
+++ lldb/test/API/functionalities/thread/break_step_other/main.cpp
@@ -0,0 +1,27 @@
+#include 
+#include "pseudo_barrier.h"
+
+// Barrier for starting the thread and reaching the loop in main.
+pseudo_barrier_t g_barrier;
+volatile int g_foo = 0;
+
+void thread_func() {
+  // Wait until all the threads are running
+  pseudo_barrier_wait(g_barrier);
+  g_foo = 0; // thread break here
+}
+
+int main() {
+  g_foo = 0; // main break here
+
+  pseudo_barrier_init(g_barrier, 2);
+  std::thread t(thread_func);
+  pseudo_barrier_wait(g_barrier);
+
+  // A dummy loop to have something to step through.
+  unsigned int i = 0;
+  while (true) {
+g_foo = ++i;
+  }
+  return 0;
+}
Index: lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py
===
--- /dev/null
+++ lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py
@@ -0,0 +1,62 @@
+"""
+Test stop reasons after hitting and deleting a breakpoint and
+stepping another thread. Scenario:
+  - run a thread
+  - stop the thread at a breakpoint
+  - delete the breakpoint
+  - single step on the main thread
+The thread stopped at the deleted breakpoint should have stop reason
+'none'.
+"""
+
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class ThreadBreakStepOtherTestCase(TestBase):
+mydir = TestBase.compute_mydir(__file__)
+
+def test_hit_breakpoint_delete_step_other_thread(self):
+main_source_file = lldb.SBFileSpec("main.cpp")
+self.build()
+(target, process, main_thread, _) = lldbutil.run_to_source_breakpoint(
+self, "// main break here", main_source_file, only_one_thread = False)
+
+# Run until the breakpoint in the thread.
+thread_breakpoint = target.BreakpointCreateBySourceRegex(
+"// thread break here", main_source_file)
+self.assertGreater(
+thread_breakpoint.GetNumLocations(),
+0,
+"thread breakpoint has no locations associated with it.")
+process.Continue()
+stopped_threads = lldbutil.get_threads_stopped_at_breakpoint(
+process, thread_breakpoint)
+self.assertEquals(
+1,
+len(stopped_threads),
+"only one thread expected stopped at the thread breakpoint")
+breakpoint_thread = stopped_threads[0]
+
+# Delete the breakpint in the thread and do a step in the main thread.
+target.BreakpointDelete(thread_breakpoint.GetID())
+main_thread.StepInstruction(False)
+
+# Check the stop reasons.
+reason = main_thread.GetStopReason()
+self.assertEqual(
+lldb.eStopReasonPlanComplete,
+reason,
+"Expected thread stop reason 'plancomplete', but got '%s'" %
+lldbutil.stop_reason_to_str(reason))
+
+reason = breakpoint_thread.GetStopReason()
+self.assertEqual(
+lldb.eStopReasonNone,
+reason,
+"Expected thread stop reason 'none', but got '%s'" %
+lldbutil.stop_reason_to_str(reason))
Index: lldb/test/API/functionalities/thread/break_step_other/Makefile
===
--- /dev/null
+++ lldb/test/API/functionalities/thread/break_step_other/Makefile
@@ -0,0 +1,4 @@
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+
+include Makefile.rules
Index: lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
===
--- lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
+++ lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
@@ -94,6 +94,8 @@
 
   void SetStopped();
 
+  void ResetStopReason();
+
   // Member Variables
   lldb::StateType m_state;
   ThreadStopInfo m_stop_info;
Index: lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
===
--- lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
+++ lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
@@ -396,7 

[Lldb-commits] [PATCH] D79404: Fix error handling after [] in 'frame variable'

2020-05-05 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin created this revision.
jarin added reviewers: teemperor, labath.
Herald added subscribers: lldb-commits, arphaman.
Herald added a project: LLDB.
jarin retitled this revision from "Fix handling of [] in 'frame 
variable'" to "Fix error handling after [] in 'frame variable'".

This fixes a bug where

frame var a[0]+5

returns the value a[0] without any warning because the current logic simply 
ignores everything after ']' as long as there is no '.', '-' or '[' in the rest 
of the string.

The fix simplifies the termination condition of the expression path parsing 
loop to check if have a non-empty remaining string to parse. Previously, the 
condition checked if a separator was found. That condition coincided with the 
remaining string-to-parse condition except for the buggy indexed case where 
non-empty string was left ("+5" in the example above), but the separator index 
was 'npos'.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D79404

Files:
  lldb/source/Target/StackFrame.cpp
  lldb/test/API/functionalities/var_path/TestVarPath.py


Index: lldb/test/API/functionalities/var_path/TestVarPath.py
===
--- lldb/test/API/functionalities/var_path/TestVarPath.py
+++ lldb/test/API/functionalities/var_path/TestVarPath.py
@@ -25,7 +25,7 @@
 def verify_point(self, frame, var_name, var_typename, x_value, y_value):
 v = frame.GetValueForVariablePath(var_name)
 self.assertTrue(v.GetError().Success(), "Make sure we find '%s'" % 
(var_name))
-self.assertEquals(v.GetType().GetName(), var_typename, 
+self.assertEquals(v.GetType().GetName(), var_typename,
 "Make sure '%s' has type '%s'" % (var_name, 
var_typename))
 
 if '*' in var_typename:
@@ -76,11 +76,14 @@
 self.verify_point(frame, 'pt_ptr[1]', 'Point', 5050, 6060)
 # Test arrays
 v = frame.GetValueForVariablePath('points')
-self.assertTrue(v.GetError().Success(), 
+self.assertTrue(v.GetError().Success(),
 "Make sure we find 'points'")
 self.verify_point(frame, 'points[0]', 'Point', 1010, 2020)
 self.verify_point(frame, 'points[1]', 'Point', 3030, 4040)
 self.verify_point(frame, 'points[2]', 'Point', 5050, 6060)
+v = frame.GetValueForVariablePath('points[0]+5')
+self.assertTrue(v.GetError().Fail(),
+"Make sure we do not ignore characters between ']' and 
the end")
 # Test a reference
 self.verify_point(frame, 'pt_ref', 'Point &', 1, 2)
 v = frame.GetValueForVariablePath('pt_sp')
@@ -88,7 +91,7 @@
 # Make sure we don't crash when looking for non existant child
 # in type with synthetic children. This used to cause a crash.
 v = frame.GetValueForVariablePath('pt_sp->not_valid_child')
-self.assertTrue(v.GetError().Fail(), 
+self.assertTrue(v.GetError().Fail(),
 "Make sure we don't find 'pt_sp->not_valid_child'")
 
 
Index: lldb/source/Target/StackFrame.cpp
===
--- lldb/source/Target/StackFrame.cpp
+++ lldb/source/Target/StackFrame.cpp
@@ -606,7 +606,7 @@
   }
 
   // We are dumping at least one child
-  while (separator_idx != std::string::npos) {
+  while (!var_expr.empty()) {
 // Calculate the next separator index ahead of time
 ValueObjectSP child_valobj_sp;
 const char separator_type = var_expr[0];
@@ -940,7 +940,6 @@
   return ValueObjectSP();
 }
 
-separator_idx = var_expr.find_first_of(".-[");
 if (use_dynamic != eNoDynamicValues) {
   ValueObjectSP dynamic_value_sp(
   child_valobj_sp->GetDynamicValue(use_dynamic));
@@ -1025,7 +1024,6 @@
 return ValueObjectSP();
   }
 
-  separator_idx = var_expr.find_first_of(".-[");
   if (use_dynamic != eNoDynamicValues) {
 ValueObjectSP dynamic_value_sp(
 child_valobj_sp->GetDynamicValue(use_dynamic));
@@ -1051,9 +1049,6 @@
 
 if (child_valobj_sp)
   valobj_sp = child_valobj_sp;
-
-if (var_expr.empty())
-  break;
   }
   if (valobj_sp) {
 if (deref) {


Index: lldb/test/API/functionalities/var_path/TestVarPath.py
===
--- lldb/test/API/functionalities/var_path/TestVarPath.py
+++ lldb/test/API/functionalities/var_path/TestVarPath.py
@@ -25,7 +25,7 @@
 def verify_point(self, frame, var_name, var_typename, x_value, y_value):
 v = frame.GetValueForVariablePath(var_name)
 self.assertTrue(v.GetError().Success(), "Make sure we find '%s'" % (var_name))
-self.assertEquals(v.GetType().GetName(), var_typename, 
+self.assertEquals(v.GetType().GetName(), var_typename,
 "Make sure '%s' has type '%s'" % (var_name, var_typename))
 
 if '*' in var_typename:
@@ -76,1

[Lldb-commits] [PATCH] D79404: Fix error handling after [] in 'frame variable'

2020-05-05 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Do you think Raphael would want to review this as well? If you think it is not 
necessary, could you land the patch for me?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D79404/new/

https://reviews.llvm.org/D79404



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D79308: [lldb-server] Reset stop reason of all threads when resuming

2020-05-05 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 262082.
jarin added a comment.

... and remove the extra braces.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D79308/new/

https://reviews.llvm.org/D79308

Files:
  lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
  lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
  lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
  lldb/test/API/functionalities/thread/break_step_other/Makefile
  
lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py
  lldb/test/API/functionalities/thread/break_step_other/main.cpp

Index: lldb/test/API/functionalities/thread/break_step_other/main.cpp
===
--- /dev/null
+++ lldb/test/API/functionalities/thread/break_step_other/main.cpp
@@ -0,0 +1,28 @@
+#include 
+#include "pseudo_barrier.h"
+
+// Barrier for starting the thread and reaching the loop in main.
+pseudo_barrier_t g_barrier;
+volatile int g_foo = 0;
+
+void thread_func() {
+  // Wait until all the threads are running
+  pseudo_barrier_wait(g_barrier);
+  g_foo = 1; // thread break here
+}
+
+int main() {
+  g_foo = 0; // main break here
+
+  pseudo_barrier_init(g_barrier, 2);
+  std::thread t(thread_func);
+  pseudo_barrier_wait(g_barrier);
+
+  // A dummy loop to have something to step through.
+  unsigned int i = 0;
+  while (g_foo == 0)
+++i;
+
+  t.join();
+  return 0;
+}
Index: lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py
===
--- /dev/null
+++ lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py
@@ -0,0 +1,63 @@
+"""
+Test stop reasons after hitting and deleting a breakpoint and
+stepping another thread. Scenario:
+  - run a thread
+  - stop the thread at a breakpoint
+  - delete the breakpoint
+  - single step on the main thread
+The thread stopped at the deleted breakpoint should have stop reason
+'none'.
+"""
+
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class ThreadBreakStepOtherTestCase(TestBase):
+mydir = TestBase.compute_mydir(__file__)
+NO_DEBUG_INFO_TESTCASE = True
+
+def test_hit_breakpoint_delete_step_other_thread(self):
+main_source_file = lldb.SBFileSpec("main.cpp")
+self.build()
+(target, process, main_thread, _) = lldbutil.run_to_source_breakpoint(
+self, "// main break here", main_source_file, only_one_thread = False)
+
+# Run until the breakpoint in the thread.
+thread_breakpoint = target.BreakpointCreateBySourceRegex(
+"// thread break here", main_source_file)
+self.assertGreater(
+thread_breakpoint.GetNumLocations(),
+0,
+"thread breakpoint has no locations associated with it.")
+process.Continue()
+stopped_threads = lldbutil.get_threads_stopped_at_breakpoint(
+process, thread_breakpoint)
+self.assertEquals(
+1,
+len(stopped_threads),
+"only one thread expected stopped at the thread breakpoint")
+breakpoint_thread = stopped_threads[0]
+
+# Delete the breakpint in the thread and do a step in the main thread.
+target.BreakpointDelete(thread_breakpoint.GetID())
+main_thread.StepInstruction(False)
+
+# Check the stop reasons.
+reason = main_thread.GetStopReason()
+self.assertEqual(
+lldb.eStopReasonPlanComplete,
+reason,
+"Expected thread stop reason 'plancomplete', but got '%s'" %
+lldbutil.stop_reason_to_str(reason))
+
+reason = breakpoint_thread.GetStopReason()
+self.assertEqual(
+lldb.eStopReasonNone,
+reason,
+"Expected thread stop reason 'none', but got '%s'" %
+lldbutil.stop_reason_to_str(reason))
Index: lldb/test/API/functionalities/thread/break_step_other/Makefile
===
--- /dev/null
+++ lldb/test/API/functionalities/thread/break_step_other/Makefile
@@ -0,0 +1,4 @@
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+
+include Makefile.rules
Index: lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
===
--- lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
+++ lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
@@ -94,6 +94,8 @@
 
   void SetStopped();
 
+  void ResetStopReason();
+
   // Member Variables
   lldb::StateType m_state;
   ThreadStopInfo m_stop_info;
Index: lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
===
--- lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
+++ lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
@@ -396,7 +396,10 @@
 
 void Na

[Lldb-commits] [PATCH] D79308: [lldb-server] Reset stop reason of all threads when resuming

2020-05-05 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 262081.
jarin marked an inline comment as done.
jarin added a comment.

Addressed reviewer comments.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D79308/new/

https://reviews.llvm.org/D79308

Files:
  lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
  lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
  lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
  lldb/test/API/functionalities/thread/break_step_other/Makefile
  
lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py
  lldb/test/API/functionalities/thread/break_step_other/main.cpp

Index: lldb/test/API/functionalities/thread/break_step_other/main.cpp
===
--- /dev/null
+++ lldb/test/API/functionalities/thread/break_step_other/main.cpp
@@ -0,0 +1,29 @@
+#include 
+#include "pseudo_barrier.h"
+
+// Barrier for starting the thread and reaching the loop in main.
+pseudo_barrier_t g_barrier;
+volatile int g_foo = 0;
+
+void thread_func() {
+  // Wait until all the threads are running
+  pseudo_barrier_wait(g_barrier);
+  g_foo = 1; // thread break here
+}
+
+int main() {
+  g_foo = 0; // main break here
+
+  pseudo_barrier_init(g_barrier, 2);
+  std::thread t(thread_func);
+  pseudo_barrier_wait(g_barrier);
+
+  // A dummy loop to have something to step through.
+  unsigned int i = 0;
+  while (g_foo == 0) {
+++i;
+  }
+
+  t.join();
+  return 0;
+}
Index: lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py
===
--- /dev/null
+++ lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py
@@ -0,0 +1,63 @@
+"""
+Test stop reasons after hitting and deleting a breakpoint and
+stepping another thread. Scenario:
+  - run a thread
+  - stop the thread at a breakpoint
+  - delete the breakpoint
+  - single step on the main thread
+The thread stopped at the deleted breakpoint should have stop reason
+'none'.
+"""
+
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class ThreadBreakStepOtherTestCase(TestBase):
+mydir = TestBase.compute_mydir(__file__)
+NO_DEBUG_INFO_TESTCASE = True
+
+def test_hit_breakpoint_delete_step_other_thread(self):
+main_source_file = lldb.SBFileSpec("main.cpp")
+self.build()
+(target, process, main_thread, _) = lldbutil.run_to_source_breakpoint(
+self, "// main break here", main_source_file, only_one_thread = False)
+
+# Run until the breakpoint in the thread.
+thread_breakpoint = target.BreakpointCreateBySourceRegex(
+"// thread break here", main_source_file)
+self.assertGreater(
+thread_breakpoint.GetNumLocations(),
+0,
+"thread breakpoint has no locations associated with it.")
+process.Continue()
+stopped_threads = lldbutil.get_threads_stopped_at_breakpoint(
+process, thread_breakpoint)
+self.assertEquals(
+1,
+len(stopped_threads),
+"only one thread expected stopped at the thread breakpoint")
+breakpoint_thread = stopped_threads[0]
+
+# Delete the breakpint in the thread and do a step in the main thread.
+target.BreakpointDelete(thread_breakpoint.GetID())
+main_thread.StepInstruction(False)
+
+# Check the stop reasons.
+reason = main_thread.GetStopReason()
+self.assertEqual(
+lldb.eStopReasonPlanComplete,
+reason,
+"Expected thread stop reason 'plancomplete', but got '%s'" %
+lldbutil.stop_reason_to_str(reason))
+
+reason = breakpoint_thread.GetStopReason()
+self.assertEqual(
+lldb.eStopReasonNone,
+reason,
+"Expected thread stop reason 'none', but got '%s'" %
+lldbutil.stop_reason_to_str(reason))
Index: lldb/test/API/functionalities/thread/break_step_other/Makefile
===
--- /dev/null
+++ lldb/test/API/functionalities/thread/break_step_other/Makefile
@@ -0,0 +1,4 @@
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+
+include Makefile.rules
Index: lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
===
--- lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
+++ lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
@@ -94,6 +94,8 @@
 
   void SetStopped();
 
+  void ResetStopReason();
+
   // Member Variables
   lldb::StateType m_state;
   ThreadStopInfo m_stop_info;
Index: lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
===
--- lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
+++ lldb/source/Plugins/Process/Linux/NativeThre

[Lldb-commits] [PATCH] D79308: [lldb-server] Reset stop reason of all threads when resuming

2020-05-05 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 262087.
jarin marked 2 inline comments as done.
jarin added a comment.

... now also fixed the 'volatile'. It took only three patches to copy four 
lines of code by hand. Not bad, huh?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D79308/new/

https://reviews.llvm.org/D79308

Files:
  lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
  lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
  lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
  lldb/test/API/functionalities/thread/break_step_other/Makefile
  
lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py
  lldb/test/API/functionalities/thread/break_step_other/main.cpp

Index: lldb/test/API/functionalities/thread/break_step_other/main.cpp
===
--- /dev/null
+++ lldb/test/API/functionalities/thread/break_step_other/main.cpp
@@ -0,0 +1,27 @@
+#include 
+#include "pseudo_barrier.h"
+
+// Barrier for starting the thread and reaching the loop in main.
+pseudo_barrier_t g_barrier;
+volatile int g_foo = 0;
+
+void thread_func() {
+  // Wait until all the threads are running
+  pseudo_barrier_wait(g_barrier);
+  g_foo = 1; // thread break here
+}
+
+int main() {
+  g_foo = 0; // main break here
+
+  pseudo_barrier_init(g_barrier, 2);
+  std::thread t(thread_func);
+  pseudo_barrier_wait(g_barrier);
+
+  // A dummy loop to have something to step through.
+  volatile int i = 0;
+  while (g_foo == 0)
+++i;
+  t.join();
+  return 0;
+}
Index: lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py
===
--- /dev/null
+++ lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py
@@ -0,0 +1,63 @@
+"""
+Test stop reasons after hitting and deleting a breakpoint and
+stepping another thread. Scenario:
+  - run a thread
+  - stop the thread at a breakpoint
+  - delete the breakpoint
+  - single step on the main thread
+The thread stopped at the deleted breakpoint should have stop reason
+'none'.
+"""
+
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class ThreadBreakStepOtherTestCase(TestBase):
+mydir = TestBase.compute_mydir(__file__)
+NO_DEBUG_INFO_TESTCASE = True
+
+def test_hit_breakpoint_delete_step_other_thread(self):
+main_source_file = lldb.SBFileSpec("main.cpp")
+self.build()
+(target, process, main_thread, _) = lldbutil.run_to_source_breakpoint(
+self, "// main break here", main_source_file, only_one_thread = False)
+
+# Run until the breakpoint in the thread.
+thread_breakpoint = target.BreakpointCreateBySourceRegex(
+"// thread break here", main_source_file)
+self.assertGreater(
+thread_breakpoint.GetNumLocations(),
+0,
+"thread breakpoint has no locations associated with it.")
+process.Continue()
+stopped_threads = lldbutil.get_threads_stopped_at_breakpoint(
+process, thread_breakpoint)
+self.assertEquals(
+1,
+len(stopped_threads),
+"only one thread expected stopped at the thread breakpoint")
+breakpoint_thread = stopped_threads[0]
+
+# Delete the breakpint in the thread and do a step in the main thread.
+target.BreakpointDelete(thread_breakpoint.GetID())
+main_thread.StepInstruction(False)
+
+# Check the stop reasons.
+reason = main_thread.GetStopReason()
+self.assertEqual(
+lldb.eStopReasonPlanComplete,
+reason,
+"Expected thread stop reason 'plancomplete', but got '%s'" %
+lldbutil.stop_reason_to_str(reason))
+
+reason = breakpoint_thread.GetStopReason()
+self.assertEqual(
+lldb.eStopReasonNone,
+reason,
+"Expected thread stop reason 'none', but got '%s'" %
+lldbutil.stop_reason_to_str(reason))
Index: lldb/test/API/functionalities/thread/break_step_other/Makefile
===
--- /dev/null
+++ lldb/test/API/functionalities/thread/break_step_other/Makefile
@@ -0,0 +1,4 @@
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+
+include Makefile.rules
Index: lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
===
--- lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
+++ lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
@@ -94,6 +94,8 @@
 
   void SetStopped();
 
+  void ResetStopReason();
+
   // Member Variables
   lldb::StateType m_state;
   ThreadStopInfo m_stop_info;
Index: lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
===
--- lldb/source/Plugins/Process/L

[Lldb-commits] [PATCH] D79308: [lldb-server] Reset stop reason of all threads when resuming

2020-05-05 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added inline comments.



Comment at: 
lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py:21
+class ThreadBreakStepOtherTestCase(TestBase):
+mydir = TestBase.compute_mydir(__file__)
+

labath wrote:
> You can add `NO_DEBUG_INFO_TESTCASE = True` here.
Out of curiosity, what does that do?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D79308/new/

https://reviews.llvm.org/D79308



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D73191: Only match mangled name in full-name function lookup (with accelerators)

2020-05-05 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin reopened this revision.
jarin added a comment.
This revision is now accepted and ready to land.

Reopening for further investigation.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D73191/new/

https://reviews.llvm.org/D73191



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D79308: [lldb-server] Reset stop reason of all threads when resuming

2020-05-06 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Jim, do you think this is good to go?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D79308/new/

https://reviews.llvm.org/D79308



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D79308: [lldb-server] Reset stop reason of all threads when resuming

2020-05-19 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

Pavel, could you possibly land this for us?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D79308/new/

https://reviews.llvm.org/D79308



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D80254: Prevent GetNumChildren from transitively walking pointer chains

2020-05-19 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin created this revision.
jarin added reviewers: teemperor, jingham.
jarin added a project: LLDB.
Herald added a subscriber: lldb-commits.

This is an attempt to fix https://bugs.llvm.org/show_bug.cgi?id=45988, where 
SBValue::GetNumChildren returns 2, but SBValue::GetChildAtIndex(1) returns an 
invalid value sentinel.

The root cause of this seems to be that GetNumChildren can return the number of 
children of a wrong value. In particular, for pointers GetNumChildren just 
recursively calls itself on the pointee type, so it effectively walks chains of 
pointers. This is different from the logic of GetChildAtIndex, which only 
recurses if pointee.IsAggregateType() returns true (IsAggregateType is false 
for pointers and references), so it never follows chain of pointers.

This patch aims to make GetNumChildren (more) consistent with GetChildAtIndex 
by only recursively calling GetNumChildren for aggregate types.

Ideally, GetNumChildren and GetChildAtIndex would share the code that decides 
which pointers/references are followed, but that is a bit more invasive change.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D80254

Files:
  lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
  lldb/test/API/functionalities/pointer_num_children/Makefile
  lldb/test/API/functionalities/pointer_num_children/TestPointerNumChildren.py
  lldb/test/API/functionalities/pointer_num_children/main.cpp

Index: lldb/test/API/functionalities/pointer_num_children/main.cpp
===
--- /dev/null
+++ lldb/test/API/functionalities/pointer_num_children/main.cpp
@@ -0,0 +1,19 @@
+struct Inner
+{
+  int a;
+  int b;
+};
+
+struct Outer
+{
+  Inner *inner;
+};
+
+int main()
+{
+  Inner inner{42, 56};
+  Outer outer{&inner};
+  auto Ptr = &(outer.inner);
+  auto& Ref = outer.inner;
+  return 0;  // break here
+}
Index: lldb/test/API/functionalities/pointer_num_children/TestPointerNumChildren.py
===
--- /dev/null
+++ lldb/test/API/functionalities/pointer_num_children/TestPointerNumChildren.py
@@ -0,0 +1,24 @@
+"""
+"""
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestPointerNumChilden(TestBase):
+mydir = TestBase.compute_mydir(__file__)
+
+def test_pointer_num_children(self):
+self.main_source_file = lldb.SBFileSpec("main.cpp")
+self.build()
+(_, _, thread, _) = lldbutil.run_to_source_breakpoint(self, "// break here", self.main_source_file)
+frame = thread.GetSelectedFrame()
+
+result = frame.FindVariable("Ref")
+self.assertEqual("42", result.GetChildAtIndex(0).GetChildAtIndex(0).GetValue())
+self.assertEqual(1, result.GetNumChildren())
+
+result = frame.FindVariable("Ptr")
+self.assertEqual("42", result.GetChildAtIndex(0).GetChildAtIndex(0).GetValue())
+self.assertEqual(1, result.GetNumChildren())
Index: lldb/test/API/functionalities/pointer_num_children/Makefile
===
--- /dev/null
+++ lldb/test/API/functionalities/pointer_num_children/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
Index: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
===
--- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -5173,11 +5173,12 @@
 break;
 
   case clang::Type::ObjCObjectPointer: {
-const clang::ObjCObjectPointerType *pointer_type =
-llvm::cast(qual_type.getTypePtr());
-clang::QualType pointee_type = pointer_type->getPointeeType();
-uint32_t num_pointee_children =
-GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx);
+CompilerType pointee_clang_type(GetPointeeType(type));
+
+uint32_t num_pointee_children = 0;
+if (pointee_clang_type.IsAggregateType())
+  num_pointee_children =
+  pointee_clang_type.GetNumChildren(omit_empty_base_classes, exe_ctx);
 // If this type points to a simple type, then it has 1 child
 if (num_pointee_children == 0)
   num_children = 1;
@@ -5209,8 +5210,11 @@
 const clang::PointerType *pointer_type =
 llvm::cast(qual_type.getTypePtr());
 clang::QualType pointee_type(pointer_type->getPointeeType());
-uint32_t num_pointee_children =
-GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx);
+CompilerType pointee_clang_type(GetType(pointee_type));
+uint32_t num_pointee_children = 0;
+if (pointee_clang_type.IsAggregateType())
+  num_pointee_children =
+  pointee_clang_type.GetNumChildren(omit_empty_base_classes, exe_ctx);
 if (num_pointee_children == 0) {
   // We have a pointer to a pointee type that claims it has no 

[Lldb-commits] [PATCH] D80254: Prevent GetNumChildren from transitively walking pointer chains

2020-05-19 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 265141.
jarin marked 2 inline comments as done.
jarin added a comment.

Added more assertions, reformatted the test code.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D80254/new/

https://reviews.llvm.org/D80254

Files:
  lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
  lldb/test/API/functionalities/pointer_num_children/Makefile
  lldb/test/API/functionalities/pointer_num_children/TestPointerNumChildren.py
  lldb/test/API/functionalities/pointer_num_children/main.cpp

Index: lldb/test/API/functionalities/pointer_num_children/main.cpp
===
--- /dev/null
+++ lldb/test/API/functionalities/pointer_num_children/main.cpp
@@ -0,0 +1,16 @@
+struct Inner {
+  int a;
+  int b;
+};
+
+struct Outer {
+  Inner *inner;
+};
+
+int main() {
+  Inner inner{42, 56};
+  Outer outer{&inner};
+  auto Ptr = &(outer.inner);
+  auto &Ref = outer.inner;
+  return 0; // break here
+}
Index: lldb/test/API/functionalities/pointer_num_children/TestPointerNumChildren.py
===
--- /dev/null
+++ lldb/test/API/functionalities/pointer_num_children/TestPointerNumChildren.py
@@ -0,0 +1,28 @@
+"""
+"""
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestPointerNumChilden(TestBase):
+mydir = TestBase.compute_mydir(__file__)
+
+def test_pointer_num_children(self):
+self.main_source_file = lldb.SBFileSpec("main.cpp")
+self.build()
+(_, _, thread, _) = lldbutil.run_to_source_breakpoint(self, "// break here", self.main_source_file)
+frame = thread.GetSelectedFrame()
+
+result = frame.FindVariable("Ref")
+self.assertEqual(1, result.GetNumChildren())
+self.assertEqual(2, result.GetChildAtIndex(0).GetNumChildren())
+self.assertEqual("42", result.GetChildAtIndex(0).GetChildAtIndex(0).GetValue())
+self.assertEqual("56", result.GetChildAtIndex(0).GetChildAtIndex(1).GetValue())
+
+result = frame.FindVariable("Ptr")
+self.assertEqual(1, result.GetNumChildren())
+self.assertEqual(2, result.GetChildAtIndex(0).GetNumChildren())
+self.assertEqual("42", result.GetChildAtIndex(0).GetChildAtIndex(0).GetValue())
+self.assertEqual("56", result.GetChildAtIndex(0).GetChildAtIndex(1).GetValue())
Index: lldb/test/API/functionalities/pointer_num_children/Makefile
===
--- /dev/null
+++ lldb/test/API/functionalities/pointer_num_children/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
Index: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
===
--- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -5173,11 +5173,12 @@
 break;
 
   case clang::Type::ObjCObjectPointer: {
-const clang::ObjCObjectPointerType *pointer_type =
-llvm::cast(qual_type.getTypePtr());
-clang::QualType pointee_type = pointer_type->getPointeeType();
-uint32_t num_pointee_children =
-GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx);
+CompilerType pointee_clang_type(GetPointeeType(type));
+
+uint32_t num_pointee_children = 0;
+if (pointee_clang_type.IsAggregateType())
+  num_pointee_children =
+  pointee_clang_type.GetNumChildren(omit_empty_base_classes, exe_ctx);
 // If this type points to a simple type, then it has 1 child
 if (num_pointee_children == 0)
   num_children = 1;
@@ -5209,8 +5210,11 @@
 const clang::PointerType *pointer_type =
 llvm::cast(qual_type.getTypePtr());
 clang::QualType pointee_type(pointer_type->getPointeeType());
-uint32_t num_pointee_children =
-GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx);
+CompilerType pointee_clang_type(GetType(pointee_type));
+uint32_t num_pointee_children = 0;
+if (pointee_clang_type.IsAggregateType())
+  num_pointee_children =
+  pointee_clang_type.GetNumChildren(omit_empty_base_classes, exe_ctx);
 if (num_pointee_children == 0) {
   // We have a pointer to a pointee type that claims it has no children. We
   // will want to look at
@@ -5223,9 +5227,11 @@
   case clang::Type::RValueReference: {
 const clang::ReferenceType *reference_type =
 llvm::cast(qual_type.getTypePtr());
-clang::QualType pointee_type = reference_type->getPointeeType();
-uint32_t num_pointee_children =
-GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx);
+CompilerType pointee_clang_type = GetType(reference_type->getPointeeType());
+uint32_t num_pointee_children = 0;
+if (pointee_clang_type.IsAggregateType())
+  num_pointee_childr

[Lldb-commits] [PATCH] D80254: Prevent GetNumChildren from transitively walking pointer chains

2020-05-19 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin marked an inline comment as not done.
jarin added inline comments.



Comment at: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp:5215
+uint32_t num_pointee_children = 0;
+if (pointee_clang_type.IsAggregateType())
+  num_pointee_children =

shafik wrote:
> I am curious what cases are pointers aggregates? Do we test this case?
As far as I understand, pointers are never aggregates, see [ 
https://github.com/llvm/llvm-project/blob/58684fbb6f2e6871f3f96ac8c7166a7d7486e971/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp#L2683
 | IsAggregate ]].


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D80254/new/

https://reviews.llvm.org/D80254



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D80254: Prevent GetNumChildren from transitively walking pointer chains

2020-05-20 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin added a comment.

In D80254#2046275 , @labath wrote:

> Looks fine to me too. The way this test is phrased, it would probably make 
> more sense under `test/API/python_api/value`, than here. (I mean, it's not 
> technically wrong because everything is a "functionality", but i'd like to 
> avoid putting stuff here precisely because the category is so vague.)


I was actually considering `lang/cpp` since this is about Clang's type system 
and how it handles pointers and references. In any case, 
`test/API/python_api/value` is C, so I could not even test the reference case 
there. Would you prefer creating a new subdirectory in `python_api`?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D80254/new/

https://reviews.llvm.org/D80254



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D80254: Prevent GetNumChildren from transitively walking pointer chains

2020-05-20 Thread Jaroslav Sevcik via Phabricator via lldb-commits
jarin updated this revision to Diff 265237.
jarin marked 3 inline comments as done.
jarin added a comment.

Merged the ObjC pointer case with the reference case, simplified the test.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D80254/new/

https://reviews.llvm.org/D80254

Files:
  lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
  lldb/test/API/functionalities/pointer_num_children/Makefile
  lldb/test/API/functionalities/pointer_num_children/TestPointerNumChildren.py
  lldb/test/API/functionalities/pointer_num_children/main.cpp

Index: lldb/test/API/functionalities/pointer_num_children/main.cpp
===
--- /dev/null
+++ lldb/test/API/functionalities/pointer_num_children/main.cpp
@@ -0,0 +1,16 @@
+struct Inner {
+  int a;
+  int b;
+};
+
+struct Outer {
+  Inner *inner;
+};
+
+int main() {
+  Inner inner{42, 56};
+  Outer outer{&inner};
+  Inner **Ptr = &(outer.inner);
+  Inner *&Ref = outer.inner;
+  return 0; // break here
+}
Index: lldb/test/API/functionalities/pointer_num_children/TestPointerNumChildren.py
===
--- /dev/null
+++ lldb/test/API/functionalities/pointer_num_children/TestPointerNumChildren.py
@@ -0,0 +1,28 @@
+"""
+Test children counts of pointer values.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestPointerNumChilden(TestBase):
+mydir = TestBase.compute_mydir(__file__)
+
+def test_pointer_num_children(self):
+self.build()
+lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.cpp"))
+
+result = self.frame().FindVariable("Ref")
+self.assertEqual(1, result.GetNumChildren())
+self.assertEqual(2, result.GetChildAtIndex(0).GetNumChildren())
+self.assertEqual("42", result.GetChildAtIndex(0).GetChildAtIndex(0).GetValue())
+self.assertEqual("56", result.GetChildAtIndex(0).GetChildAtIndex(1).GetValue())
+
+result = self.frame().FindVariable("Ptr")
+self.assertEqual(1, result.GetNumChildren())
+self.assertEqual(2, result.GetChildAtIndex(0).GetNumChildren())
+self.assertEqual("42", result.GetChildAtIndex(0).GetChildAtIndex(0).GetValue())
+self.assertEqual("56", result.GetChildAtIndex(0).GetChildAtIndex(1).GetValue())
Index: lldb/test/API/functionalities/pointer_num_children/Makefile
===
--- /dev/null
+++ lldb/test/API/functionalities/pointer_num_children/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
Index: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
===
--- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -5172,12 +5172,15 @@
 }
 break;
 
+  case clang::Type::LValueReference:
+  case clang::Type::RValueReference:
   case clang::Type::ObjCObjectPointer: {
-const clang::ObjCObjectPointerType *pointer_type =
-llvm::cast(qual_type.getTypePtr());
-clang::QualType pointee_type = pointer_type->getPointeeType();
-uint32_t num_pointee_children =
-GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx);
+CompilerType pointee_clang_type(GetPointeeType(type));
+
+uint32_t num_pointee_children = 0;
+if (pointee_clang_type.IsAggregateType())
+  num_pointee_children =
+  pointee_clang_type.GetNumChildren(omit_empty_base_classes, exe_ctx);
 // If this type points to a simple type, then it has 1 child
 if (num_pointee_children == 0)
   num_children = 1;
@@ -5209,8 +5212,11 @@
 const clang::PointerType *pointer_type =
 llvm::cast(qual_type.getTypePtr());
 clang::QualType pointee_type(pointer_type->getPointeeType());
-uint32_t num_pointee_children =
-GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx);
+CompilerType pointee_clang_type(GetType(pointee_type));
+uint32_t num_pointee_children = 0;
+if (pointee_clang_type.IsAggregateType())
+  num_pointee_children =
+  pointee_clang_type.GetNumChildren(omit_empty_base_classes, exe_ctx);
 if (num_pointee_children == 0) {
   // We have a pointer to a pointee type that claims it has no children. We
   // will want to look at
@@ -5219,20 +5225,6 @@
   num_children = num_pointee_children;
   } break;
 
-  case clang::Type::LValueReference:
-  case clang::Type::RValueReference: {
-const clang::ReferenceType *reference_type =
-llvm::cast(qual_type.getTypePtr());
-clang::QualType pointee_type = reference_type->getPointeeType();
-uint32_t num_pointee_children =
-GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx);
-// If this type points to a simple type, 

  1   2   >