Problem Description =================== GDB enables users to select threads and frames from the gdb command line prompt using the "thread n" and "frame n" commands. When used, these commands display output to the display, e.g.: <snippet> (gdb) thread 2 [Switching to thread 2 (Thread 0x155538885700 (LWP 8875))] #0 0x0000155552be3aa8 in hack_digit (p=0x155538882480) at printf_fp.c:175 175 printf_fp.c: No such file or directory. (gdb) (gdb) frame 1 #1 __GI___printf_fp_l (...) at printf_fp.c:962 962 in printf_fp.c (gdb) </snippet> GDB also supports the "up" and "down" commands for selecting a frame relative to the currently selected one. Like "frame n", they also display output to the screen. Thankfully, gdb has a silent version of "frame n", i.e. "select-frame n": <snippet> #0 0x0000155552be3aa8 in hack_digit (p=0x155538882480) at printf_fp.c:175 175 in printf_fp.c (gdb) select-frame 1 (gdb) </snippet> The value of this silent selection command cannot be overstated. It enables complex custom commands to make many frame selections without producing display "noise" as an artifact. The problem is that there is no analog for silently selecting threads. No matter how one tries, it is impossible to select a thread without getting unwanted output on the display. Playing with logging commands, set commands, and the like do not help. Here is an example of a custom command run that executes "thread n" commands internally, producing a messy display output: <snippet> (gdb) custom_command [Switching to thread 3 (Thread 0x155555354b00 (LWP 16327))] #0 0x0000155554019ad3 in ... [Switching to thread 4 (Thread 0x15553084e700 (LWP 13823))] #0 std::_Hashtable<std::pair< ... (5 lines of output) [Switching to thread 5 (Thread 0x155532695700 (LWP 8874))] #0 0x0000155552ca5947 in ... [Switching to thread 6 (Thread 0x155551a19700 (LWP 16826))] #0 0x0000155554019ad3 in ... [Switching to thread 1 (Thread 0x155538844700 (LWP 8876))] #0 __GI_raise (sig=sig@entry=6) at ... [Switching to thread 2 (Thread 0x155538885700 (LWP 8875))] #0 0x0000155552be3aa8 in ... </snippet> Request ======= Can a silent gdb-prompt thread-selecting command (e.g., 'select-thread') be added to the already existing 'select-frame'?
Adding a command would be fine IMO. However I think it can already be done like: pipe thread 5 | cat > /dev/null Though... are you really on gdb 8.2? "pipe" wasn't added until later.
Thanks or your prompt reply <g>. I see that "pipe" was introduced in gdb 9.1. My company currently uses version 8.2.1 across the organization. You can imagine that IT's changing this will take time. Your suggestion to use pipe is an interesting one and would answer the immediate need. I look forward to my organization upgrading to GDB 9.1. I do think, however, that having "select-thread" as a parallel to "select-frame" is logical and makes the Python code clearer and better understood.
(In reply to Moshe Rubin from comment #2) > immediate need. I look forward to my organization upgrading to GDB 9.1. I > do think, however, that having "select-thread" as a parallel to > "select-frame" is logical and makes the Python code clearer and better > understood. Python can use InferiorThread.switch or gdb.execute("thread ...", to_string=True)
Hi Tom, Your intriguing suggestion about using "pipe" (albeit in later versions of gdb) got me thinking. Checking two versions of gdb 8.2 my organization uses: GNU gdb (Ubuntu 8.1.1-0ubuntu1) 8.1.1 GNU gdb (GDB) 8.2.1 it turns out that they support an earlier version of "pipe": (gdb) help pipe Pipe gdb output via a shell command (gdb) pipe cmd1 cmd2 is equivalent to $ cmd1 | cmd2 Examples: pipe "p Vehicles::g_cliquer._members" "grep rectRaw" pipe "p g_invlut" "tail -10|sort -n" (This differs from what I found in gdb 13.1: (gdb) help pipe pipe, | Send the output of a gdb command to a shell command. Usage: | [COMMAND] | SHELL_COMMAND Usage: | -d DELIM COMMAND DELIM SHELL_COMMAND Usage: pipe [COMMAND] | SHELL_COMMAND Usage: pipe -d DELIM COMMAND DELIM SHELL_COMMAND Executes COMMAND and sends its output to SHELL_COMMAND. The -d option indicates to use the string DELIM to separate COMMAND from SHELL_COMMAND, in alternative to |. This is useful in case COMMAND contains a | character. With no COMMAND, repeat the last executed command and send its output to SHELL_COMMAND.) I figured I'd give the older "pipe" a try, and found some intriguing but less than satisfactory results. Here is a session I had in 8.2.1 (the results in 8.1.1 are identical) with my comments based on the line numbers: <session> 1 (gdb) info thread 1 2 3 2 Id Target Id Frame 3 * 1 Thread 0x155538844700 (LWP 8876) __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51 4 2 Thread 0x155538885700 (LWP 8875) 0x0000155552be3aa8 in hack_digit (p=0x155538882480) at printf_fp.c:175 5 3 Thread 0x155555354b00 (LWP 16327) 0x0000155554019ad3 in futex_wait_cancelable (...) at ../sysdeps/unix/sysv/linux/futex-internal.h:88 7 8 (gdb) pipe "thread 2" "cat > /dev/null" 9 [Switching to thread 2 (Thread 0x155538885700 (LWP 8875))] 10 #0 0x0000155552be3aa8 in hack_digit (p=0x155538882480) at printf_fp.c:175 11 12 (gdb) pipe "thread 2" "cat > /dev/null" 13 14 (gdb) pipe "thread 3" "cat > /dev/null" 15 [Switching to thread 3 (Thread 0x155555354b00 (LWP 16327))] 16 #0 0x0000155554019ad3 in futex_wait_cancelable (...) at ../sysdeps/unix/sysv/linux/futex-internal.h:88 17 18 (gdb) pipe "thread 3" "cat > /dev/null" 19 20 (gdb) pipe "thread 2" "cat > /dev/null" 21 [Switching to thread 2 (Thread 0x155538885700 (LWP 8875))] 22 #0 0x0000155552be3aa8 in hack_digit (p=0x155538882480) at printf_fp.c:175 23 24 (gdb) pipe "thread 2" "cat > /dev/null" 25 26 (gdb) thread 1 27 [Switching to thread 1 (Thread 0x155538844700 (LWP 8876))] 28 #0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51 29 51 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory. 30 (gdb) thread 1 31 [Switching to thread 1 (Thread 0x155538844700 (LWP 8876))] 32 #0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51 33 51 in ../sysdeps/unix/sysv/linux/raise.c 34 (gdb) thread 1 35 [Switching to thread 1 (Thread 0x155538844700 (LWP 8876))] 36 #0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51 37 51 in ../sysdeps/unix/sysv/linux/raise.c 38 (gdb) 39 </session> To simplify things, I only show the first three threads. Here are the findings: +-------+---------+------------------+----------+--------------------------------------------+ | Lines | Mode | Thread Selection | Visible? | Comment | +-------+---------+------------------+----------+--------------------------------------------+ | 3 | | | | gdb session opens with thread #1 selected | | 8-10 | pipe | #1 -> #2 | yes | | | 12 | pipe | #2 -> #2 | NO | see lines 26-29 for VISIBLE case (regular) | | 14-16 | pipe | #2 -> #3 | yes | | | 18 | pipe | #3 -> #3 | NO | | | 20-22 | pipe | #3 -> #2 | yes | | | 24 | pipe | #2 -> #2 | NO | | | 26-29 | regular | #1 -> #1 | yes | | +-------+---------+------------------+----------+--------------------------------------------+ Using ">&" instead of ">" to pipe cat's output doesn't make a difference: (gdb) pipe "thread 3" "cat >& /dev/null" [Switching to thread 3 (Thread 0x155555354b00 (LWP 16327))] #0 0x0000155554019ad3 in futex_wait_cancelable (...) at ../sysdeps/unix/sysv/linux/futex-internal.h:88 When I left out the pipe character ">" I expected to see two identical outputs, but it does not: (gdb) pipe "thread 3" "cat" [Switching to thread 3 (Thread 0x155555354b00 (LWP 16327))] #0 0x0000155554019ad3 in futex_wait_cancelable (...) at ../sysdeps/unix/sysv/linux/futex-internal.h:88 88 in ../sysdeps/unix/sysv/linux/futex-internal.h (gdb) ----------------------------------- Questions re gdb 8.2 "pipe" command: ----------------------------------- (1) Why is it not silent when selecting between non-identical threads, but silent with identical threads? (2) Is there a way to get the 8.2 "pipe" to work correctly and silence the output completely?
At least from the gdb NEWS file, it seems that "pipe" was not in GDB 8 at all. Are you sure yours isn't some sort of local command? I looked at my checkout of the gdb-8 branch and it doesn't have this.
You were right - a local "pipe" custom command was getting automatically loaded. Sorry about that <g>. Examining its code, and that of other solutions for passing internal command output to an external program (https://stackoverflow.com/a/50359976), they all suffer from the same drawback that they use gdb.execute(cmd, to_string=True) and then pipe the output to the external tool. gdb.execute("thread 2", to_string=True) returns the output as a string, but also displays it to the screen. The fact that gdb.execute(<cmd>, to_string=True) does not always suppress screen output is a bug and should be fixed.created and fixed. However, thanks to your comment about InferiorThread.switch(), I believe we have a solution, even for gdb 8.2! In my case, when gdb opens my core, I want to iterate over all threads in it (i.e., the current inferior) without any screen output. To determine the number of threads in the current inferior: (gdb) python print(len(gdb.selected_inferior().threads())) 17 From the gdb command prompt, select each thread one at a time by specifying the target thread object and calling the switch() function: (gdb) python gdb.selected_inferior().threads()[0].switch() (gdb) thread [Current thread is 17 (LWP 631)] (gdb) python gdb.selected_inferior().threads()[1].switch() (gdb) thread [Current thread is 16 (LWP 630)] (gdb) python gdb.selected_inferior().threads()[2].switch() (gdb) thread [Current thread is 15 (LWP 629)] . . . (gdb) python gdb.selected_inferior().threads()[16].switch() (gdb) thread [Current thread is 1 (LWP 598)] (gdb) The main thing to note is the ability to switch/select a different thread with *no* screen output. Kudos and thanks to you, Tom, for suggesting this power user method.
I believe this is resolved.