alcroito
alcroito

Reputation: 421

How to configure lldb to stop at a breakpoint that is hit by multiple threads, one by one?

I have a simple macOS app that spawns 14 threads running the same function. If I set a breakpoint within the function, and run the application from within command line lldb, instead of breaking on the location one by one, lldb reports that multiple threads have stopped there (not all of them, it's random each time).

Is there some setting I could set within an lldb to ensure it breakpoints one thread at a time, rather than alltogether?

Here is some sample output from lldb, which shows multiple threads being stopped at the same initial breakpo

lldb -- /Users/alex/Dev/projects/builds/build-simple_test_app-Qt_6_8_0_mac_official_2-Debug/simple_test_app.app/Contents/MacOS/simple_test_app
(lldb) target create "/Users/alex/Dev/projects/builds/build-simple_test_app-Qt_6_8_0_mac_official_2-Debug/simple_test_app.app/Contents/MacOS/simple_test_app"

Current executable set to '/Users/alex/Dev/projects/builds/build-simple_test_app-Qt_6_8_0_mac_official_2-Debug/simple_test_app.app/Contents/MacOS/simple_test_app' (arm64).

(lldb) b /Users/alex/Dev/qtcreator/worktrees/qtcreatordev/tests/manual/debugger/simple/simple_test_app.cpp:4209
Breakpoint 1: where = simple_test_app`qthread::Thread::run() + 24 at simple_test_app.cpp:4209:17, address = 0x000000010002e734

(lldb) run
Process 24223 launched: '/Users/alex/Dev/projects/builds/build-simple_test_app-Qt_6_8_0_mac_official_2-Debug/simple_test_app.app/Contents/MacOS/simple_test_app' (arm64)
warning: 'QtCore' contains a debug script. To run this script in this debug session:

    command script import "/Users/alex/Dev/qt/official/6.8.0/macos/lib/QtCore.framework.dSYM/Contents/Resources/Python/QtCore.py"

To run all discovered debug scripts in this session:

    settings set target.load-script-from-symbol-file true

2024-10-15 15:45:48.832326+0200 simple_test_app[24223:2627260] '\u1e9e' true
2024-10-15 15:45:48.832341+0200 simple_test_app[24223:2627260] Creator: Switch off magic autorun.
2024-10-15 15:45:48.936005+0200 simple_test_app[24223:2627260] qDebug() 1
2024-10-15 15:45:48.936011+0200 simple_test_app[24223:2627260] qDebug() 2
2024-10-15 15:45:48.936014+0200 simple_test_app[24223:2627260] qDebug() 3
2024-10-15 15:45:48.936016+0200 simple_test_app[24223:2627260] qDebug <foo & bar>
std::cout @@ 1
std::cout @@ 2
std::cout @@ 3
std::cout <foo & bar>
std::cerr 1
std::cerr 2
std::cerr 3
std::cerr <foo & bar>
2024-10-15 15:45:48.937637+0200 simple_test_app[24223:2627260] SENDER:  qobject::Sender(0x16fdfdb70, name = "Sender")
2024-10-15 15:45:48.938025+0200 simple_test_app[24223:2627260] "HiDu"
Process 24223 stopped
* thread #6, name = 'Thread #0', stop reason = breakpoint 1.1
    frame #0: 0x000000010002e734 simple_test_app`qthread::Thread::run(this=0x000000016fdfda28) at simple_test_app.cpp:4209:17
   4206
   4207         void run() override
   4208         {
-> 4209             int j = 2;
   4210             ++j;
   4211             for (int i = 0; i != 1000; ++i) {
   4212                 //sleep(1);
  thread #7, name = 'Thread #1', stop reason = breakpoint 1.1
    frame #0: 0x000000010002e734 simple_test_app`qthread::Thread::run(this=0x000000016fdfda40) at simple_test_app.cpp:4209:17
   4206
   4207         void run() override
   4208         {
-> 4209             int j = 2;
   4210             ++j;
   4211             for (int i = 0; i != 1000; ++i) {
   4212                 //sleep(1);
  thread #8, name = 'Thread #2', stop reason = breakpoint 1.1
    frame #0: 0x000000010002e734 simple_test_app`qthread::Thread::run(this=0x000000016fdfda58) at simple_test_app.cpp:4209:17
   4206
   4207         void run() override
   4208         {
-> 4209             int j = 2;
   4210             ++j;
   4211             for (int i = 0; i != 1000; ++i) {
   4212                 //sleep(1);
  thread #9, name = 'Thread #3', stop reason = breakpoint 1.1
    frame #0: 0x000000010002e734 simple_test_app`qthread::Thread::run(this=0x000000016fdfda70) at simple_test_app.cpp:4209:17
   4206
   4207         void run() override
   4208         {
-> 4209             int j = 2;
   4210             ++j;
   4211             for (int i = 0; i != 1000; ++i) {
   4212                 //sleep(1);
  thread #10, name = 'Thread #4', stop reason = breakpoint 1.1
    frame #0: 0x000000010002e734 simple_test_app`qthread::Thread::run(this=0x000000016fdfda88) at simple_test_app.cpp:4209:17
   4206
   4207         void run() override
   4208         {
-> 4209             int j = 2;
   4210             ++j;
   4211             for (int i = 0; i != 1000; ++i) {
   4212                 //sleep(1);
  thread #11, name = 'Thread #5', stop reason = breakpoint 1.1
    frame #0: 0x000000010002e734 simple_test_app`qthread::Thread::run(this=0x000000016fdfdaa0) at simple_test_app.cpp:4209:17
   4206
   4207         void run() override
   4208         {
-> 4209             int j = 2;
   4210             ++j;
   4211             for (int i = 0; i != 1000; ++i) {
   4212                 //sleep(1);
  thread #12, name = 'Thread #6', stop reason = breakpoint 1.1
    frame #0: 0x000000010002e734 simple_test_app`qthread::Thread::run(this=0x000000016fdfdab8) at simple_test_app.cpp:4209:17
   4206
   4207         void run() override
   4208         {
-> 4209             int j = 2;
   4210             ++j;
   4211             for (int i = 0; i != 1000; ++i) {
   4212                 //sleep(1);
Target 0: (simple_test_app) stopped.

Upvotes: 0

Views: 68

Answers (1)

Jim Ingham
Jim Ingham

Reputation: 27110

That's actually the way the events get reported to lldb. When lldb gets a stop event for one thread, there are also multiple other threads that are reported stopped at the same or even several different breakpoints. As you have observed, this is seemingly random, based on how the kernel scheduled your process. There isn't a way to tell the kernel to serialize the reporting of breakpoint exceptions.

Early on, lldb tried to hide this fact from you and pretend the hits were serialized, but that ended up being buggy and more confusing than helpful, so instead it just reports what the kernel says is true.

Upvotes: 0

Related Questions