Is there a way to grep on the output of print command in gdb? In my case, I am debugging a core dump using gdb and the object I am debugging contains hell lots of elements. I am finding it difficult to look for a matching attribute i.e:
(gdb) print *this | grep <attribute>
Thanks.
You can use pipe command
>>> pipe maintenance info sections | grep .text
[15] 0x5555555551c0->0x5555555554d5 at 0x000011c0: .text ...
>>> pipe maintenance info sections | grep .text | wc
1 10 100
(gdb) print *this | grep
The "standard" way to achieve this is to use Meta-X gdb in emacs.
An alternative:
(gdb) set logging on
(gdb) print *this
(gdb) set logging off
(gdb) shell grep attribute gdb.txt
The patch mentioned by cnicutar sure looks attractive compared to the above. I am guessing the reason it (or its equivalent) was never submitted is that most GDB maintainers use emacs, and so don't have this problem in the first place.
The simplest way is to exploit gdb python. One-liner:
gdb λ py ["attribute" in line and print(line) for line in gdb.execute("p *this", to_string=True).splitlines()]
Assuming you have enabled history of commands, you can type this just once, and later then press Ctrl+R b.exec to pull it out of history. Next simply change attribute and *this per your requirements.
You can also make this as simple as this:
gdb λ grep_cmd "p *this" attribute
For that just add the following to your .gdbinit file:
py
class GrepCmd (gdb.Command):
"""Execute command, but only show lines matching the pattern
Usage: grep_cmd <cmd> <pattern> """
def __init__ (_):
super ().__init__ ("grep_cmd", gdb.COMMAND_STATUS)
def invoke (_, args_raw, __):
args = gdb.string_to_argv(args_raw)
if len(args) != 2:
print("Wrong parameters number. Usage: grep_cmd <cmd> <pattern>")
else:
for line in gdb.execute(args[0], to_string=True).splitlines():
if args[1] in line:
print(line)
GrepCmd() # required to get it registered
end
I know this is an old post but since I found it looking to do the same thing I thought I would add to Hi-Angel's answer to say you can highlight the search term, in the python output, in a red colour by replacing the print line with the one below:
print(line.replace(args[1], "\033[91m"+args[1]+"\033[0m"))
This just uses ascii escape commands for the colour, so should work on Linux and Windows terminal, and you can easily change the colour.
Sorry, don't have enough rep to add this as a comment.
Related
For no justifiable reason at all, I have a pretty substantial Perl script embedded within a Bash function that is being invoked within an autoenv .env file.
It looks something like this:
perl='
$inverse = "\e[7m";
$invoff = "\e[27m";
$bold = "\e[1m";
⋮
'
perl -e "$perl" "$inputfile"
I understand that standalone Perl scripts and the PATH variable are a thing, and I understand that Term::ANSIColor is a thing. This is not about that.
My question is, if there's a syntax error in the embedded Perl code, how can I get Perl to report the actual line number within the parent shell script?
For example, say the perl= assignment occurs on line 120 within that file, but there's a syntax error on the 65th line of actual Perl code. I get this:
syntax error at -e line 65, near "s/(#.*)$/$comment\1$endcomment/"
Execution of -e aborted due to compilation errors.
…but I want to see this (the actual line number in the parent script) instead:
syntax error at -e line 185, near "s/(#.*)$/$comment\1$endcomment/"
Things I've tried (that didn't work):
assigning to __LINE__
don't even know why I thought that would work; it's not a variable, it's a constant, and you get an error stating the same
assigning to $. ($INPUT_LINE_NUMBER with use English)
I was pretty sure this wasn't going to work anyway, because this is like NR in Awk, and this clearly isn't what this is for
As described in perlsyn, you can use the following directive to set the line number and (optionally) the file name of the subsequent line:
#line 42 "file.pl"
This means that you could use
#!/bin/sh
perl="#line 4 \"$0\""'
warn("test");
'
perl -e "$perl"
Output:
$ ./a.sh
test at ./a.sh line 4.
There's no clean way to avoid hardcoding the line number when using sh, but it is possible.
#!/bin/sh
script_start=$( perl -ne'if (/^perl=/) { print $.+1; last }' -- "$0" )
perl="#line $script_start \"$0\""'
warn("test");
'
perl -e "$perl"
On the other hand, bash provides the current line number.
#!/bin/bash
script_start=$(( LINENO + 2 ))
perl="#line $script_start \"$0\""'
warn("test");
'
perl -e "$perl"
There is this useful tidbit in the perlrun man page, under the section for -x, which "tells Perl that the program is embedded in a larger chunk of unrelated text, such as in a mail message."
All references to line numbers by the program (warnings, errors, ...) will treat the #! line as the first line. Thus a warning on the 2nd line of the program, which is on the 100th line in the file will be reported as line 2, not as line 100. This can be overridden by using the #line directive. (See Plain Old Comments (Not!) in perlsyn)
Based on the bolded statement, adding #line NNN (where NNN is the actual line number of the parent script where that directive appears) achieves the desired effect:
perl='#line 120
$inverse = "\e[7m";
$invoff = "\e[27m";
$bold = "\e[1m";
⋮
'
⋮
I am trying to write my first perl "hello world" program on Mac OS X Yosemite and it shows this error when I try to run this using terminal:
Unrecognized character \xE2; marked by <-- HERE after
print <-- HERE
near column 7 at test.pl line 4.
I couldn't figure out what was wrong in this program. Please help me out here.
Code:
#!/usr/bin/perl
use strict;
use warnings;
print “Hello world”;
Change the “” character in the print statement to "
Example
print "Hello world";
Make sure syntax like this ' should be proper. Check your perl file for syntax errors
perl -c testfile.pl
While it is not directly connected to this case, there's also a different situation when \xE2 error can appear, which can seem not obvious. One can also have a zero-width space in their string, which can also raise this error.
I couldn't see this character in notepad or notepad++, but I could see it in vim as <200b>. This character can be placed next to { and } characters when copying stuff from for example Microsoft Teams.
This link appears as the first one when searching for this kind of problem, so I thought it might be a good idea to post the solution here.
When you type something, you often use bash autocompletion: you start writing a command, for example, and you type TAB to get the rest of the word.
As you have probably noticed, when multiple choices match your command, bash displays them like this :
foobar#myserv:~$ admin-
admin-addrsync admin-adduser admin-delrsync admin-deluser admin-listsvn
admin-addsvn admin-chmod admin-delsvn admin-listrsync
I'm looking for a solution to display each possible solution on a new line, similar to the last column on a ls -l. Ever better, it would be perfect if I could apply a rule like this: "if you find less than 10 suggestions, display them one by line, if more => actual display".
bash prior to version 4.2 doesn't allow any control over the output format of completions, unfortunately.
Bash 4.2+ allows switching to 1-suggestion-per-line output globally, as explained in Grisha Levit's helpful answer, which also links to a clever workaround to achieve a per-completion-function solution.
The following is a tricky workaround for a custom completion.
Solving this problem generically, for all defined completions, would be much harder (if there were a way to invoke readline functions directly, it might be easier, but I haven't found a way to do that).
To test the proof of concept below:
Save to a file and source it (. file) in your interactive shell - this will:
define a command named foo (a shell function)
whose arguments complete based on matching filenames in the current directory.
(When foo is actually invoked, it simply prints its argument in diagnostic form.)
Invoke as:
foo [fileNamePrefix], then press tab:
If between 2 and 9 files in the current directory match, you'll see the desired line-by-line display.
Otherwise (1 match or 10 or more matches), normal completion will occur.
Limitations:
Completion only works properly when applied to the LAST argument on the command line being edited.
When a completion is actually inserted in the command line (once the match is unambiguous), NO space is appended to it (this behavior is required for the workaround).
Redrawing the prompt the first time after printing custom-formatted output may not work properly: Redrawing the command line including the prompt must be simulated and since there is no direct way to obtain an expanded version of the prompt-definition string stored in $PS1, a workaround (inspired by https://stackoverflow.com/a/24006864/45375) is used, which should work in typical cases, but is not foolproof.
Approach:
Defines and assigns a custom completion shell function to the command of interest.
The custom function determines the matches and, if their count is in the desired range, bypasses the normal completion mechanism and creates custom-formatted output.
The custom-formatted output (each match on its own line) is sent directly to the terminal >/dev/tty, and then the prompt and command line are manually "redrawn" to mimic standard completion behavior.
See the comments in the source code for implementation details.
# Define the command (function) for which to establish custom command completion.
# The command simply prints out all its arguments in diagnostic form.
foo() { local a i=0; for a; do echo "\$$((i+=1))=[$a]"; done; }
# Define the completion function that will generate the set of completions
# when <tab> is pressed.
# CAVEAT:
# Only works properly if <tab> is pressed at the END of the command line,
# i.e., if completion is applied to the LAST argument.
_complete_foo() {
local currToken="${COMP_WORDS[COMP_CWORD]}" matches matchCount
# Collect matches, providing the current command-line token as input.
IFS=$'\n' read -d '' -ra matches <<<"$(compgen -A file "$currToken")"
# Count matches.
matchCount=${#matches[#]}
# Output in custom format, depending on the number of matches.
if (( matchCount > 1 && matchCount < 10 )); then
# Output matches in CUSTOM format:
# print the matches line by line, directly to the terminal.
printf '\n%s' "${matches[#]}" >/dev/tty
# !! We actually *must* pass out the current token as the result,
# !! as it will otherwise be *removed* from the redrawn line,
# !! even though $COMP_LINE *includes* that token.
# !! Also, by passing out a nonempty result, we avoid the bell
# !! signal that normally indicates a failed completion.
# !! However, by passing out a single result, a *space* will
# !! be appended to the last token - unless the compspec
# !! (mapping established via `complete`) was defined with
# !! `-o nospace`.
COMPREPLY=( "$currToken" )
# Finally, simulate redrawing the command line.
# Obtain an *expanded version* of `$PS1` using a trick
# inspired by https://stackoverflow.com/a/24006864/45375.
# !! This is NOT foolproof, but hopefully works in most cases.
expandedPrompt=$(PS1="$PS1" debian_chroot="$debian_chroot" "$BASH" --norc -i </dev/null 2>&1 | sed -n '${s/^\(.*\)exit$/\1/p;}')
printf '\n%s%s' "$expandedPrompt" "$COMP_LINE" >/dev/tty
else # Just 1 match or 10 or more matches?
# Perform NORMAL completion: let bash handle it by
# reporting matches via array variable `$COMPREPLY`.
COMPREPLY=( "${matches[#]}" )
fi
}
# Map the completion function (`_complete_foo`) to the command (`foo`).
# `-o nospace` ensures that no space is appended after a completion,
# which is needed for our workaround.
complete -o nospace -F _complete_foo -- foo
bash 4.2+ (and, more generally, applications using readline 6.2+) support this with the use of the completion-display-width variable.
The number of screen columns used to display possible matches when performing completion. The value is ignored if it is less than 0 or greater than the terminal screen width. A value of 0 will cause matches to be displayed one per line. The default value is -1.
Run the following to set the behavior for all completions1 for your current session:
bind 'set completion-display-width 0'
Or modify your ~/.inputrc2 file to have:
set completion-display-width 0
to change the behavior for all new shells.
1 See here for a method for controlling this behavior for individual custom completion functions.
2 The search path for the readline init file is $INPUTRC, ~/.inputrc, /etc/inputrc so modify the file appropriate for you.
I have a global variable that's name has multiple symbols and I want to print all of them. Example:
(gdb) info var g_reallocCount
All variables matching regular expression "g_reallocCount":
File sv.c:
long int g_reallocCount;
long int g_reallocCount;
long int g_reallocCount;
long int g_reallocCount;
when I try to use "print g_reallocCount" i get only one result, and it is not the one that I need.
I believe that the reason I have multiple symbols is that the static library I am changing is linked to multiple loaded modules. At this time I am not sure whether I can change that fact.
thanks
Edit: for some reason I failed to consider an easier way initally... assuming c linkage.
(gdb) shell nm /path/to/stuff | grep g_reallocCount | cut -d' ' -f1 >>foo
(gdb) shell cat foo | awk '{print "p *0x" $0}' >foo.gdb
(gdb) source foo.gdb
$4 = 0
$5 = 0
$6 = 0
original answer, similar premise:
For lack of a better idea, you can try copying the binary/library and stripping it of debug symbols with the strip command, gdb will then output the address of the symbol in 'info var'
and you can print it with print *0xaddr
I'll come up with a patch to print the address of the variable in 'info var', when debug symbols are available.
If you come up with a minimal testcase to reproduce this, please consider sending it to the gdb lists, or attaching it to a bug report.
Thanks!
I have this bit of code:
of = open("oldfile")
nf = open("newfile",'w')
for line in of:
if len(line) > 17:
nf.write(line)
of.close()
nf.close()
and instead of specifying 17, I want to be able to use a variable put it in my scripts directory and execute it directly. If there is no flag, it could print something like 'scriptname'. If there is a flag, as there is below, it would execute the code.
$ myscriptname -l 17 oldfile newfile
See the optparse module for checking the flag and setting the value, or the newer (and better) argparse if you're willing to use 2.7+. As for putting it in my scripts directory I don't quite understand what you want exactly.
If you just want quick and dirty access to the command line parameters:
import sys
print sys.argv # <-- this is an array containing all the command line parameters
If you want some more control, you can use the optparse module.