In GDB how do I resolve duplicate symbols - debugging

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!

Related

Octal dump in Linux shell without od or hd

I'm trying to control a Kasa Smartplug from an Axis embedded Linux product by following what George Georgovassilis has done here: https://blog.georgovassilis.com/2016/05/07/controlling-the-tp-link-hs100-wi-fi-smart-plug/
I've managed to switch the plug on and off from the Axis box but I've come unstuck trying to query the on/off status of the Smartplug because I don't have od (or hd, hexdump or xxd) and the Smartplug output is binary. The snippet of George's code which does this is:
decode(){
code=171
input_num=`od $ODOPTS`
IFS=' ' read -r -a array <<< "$input_num"
args_for_printf=""
for element in "${array[#]}"
do
output=$(( $element ^ $code ))
args_for_printf="$args_for_printf\x$(printf %x $output)"
code=$element
done
printf "$args_for_printf"
}
Is there a way I can do this using basic shell commands instead of using od please?
The Axis box says it's Linux 2.6.29 on a crisv32
I used to use Unix about 30 years ago so I'm struggling...
Octal dump in Linux shell without od or hd
Seems simple enough with awk. Borrowing code from this answer and splitting from this answer it's simple to:
awk -v ORS='' -v OFS='' 'BEGIN{ for(n=0;n<256;n++)ord[sprintf("%c",n)]=n }
{ split($0, chars, "");
chars[length($0)+1]=RS; # add the newline to output. One could check if RS is empty.
# and print
for (i=1;i<=length($0)+1;++i) printf("%o\n", ord[chars[i]]) }'
I managed to solve this in the end:
I couldn't work out how to replicate od using just the shell commands available on the target machine, so I created a very simple C program to read each byte from the binary and print it out as a readable character. That included replicating the weird XOR, which seems to be something to do with rudimentary encryption (probably). I then pulled out the value which I needed using sed. Cross-compiling this C on my Lubuntu machine for the target CRIS architecture wasn't too difficult for a simple program.
Everything was much easier once I'd reduced the model code to a minimal reproducible example for myself. Thanks all.

awk and sed command Special Character in matching pattern for range [duplicate]

NOTE: I am a noob at bash scripts and the awk command - please excuse any dumb mistakes I make.
I am unable to substitute shell variables into my awk pattern. I am trying to scan through a file, find the first occurence of a specific string in the file, and print each line that succeed it in order until it hits an empty string/line.
I don't know the string I am searching for in advance, and I would like to substitute in that variable.
When I run this with the string directly specified (e.g "< main>:"), it works perfectly. I've already searched on how awk patterns work, and how to substitute in variables. I've tried using the -v flag for awk, directly using the shell variable - nothing works.
funcName="<${2}>:"
awk=`awk -v FN="$funcName" '/FN/,/^$/' "$ofile"`
rfile=search.txt
echo -e "$awk" > "$rfile"
The error is just that nothing prints. I want to print all the lines between my desired string and the next empty line.
Could you please try following, haven't tested it because no clear samples but should work.
funcName="<${2}>:"
awk_result=$(awk -v FN="$funcName" 'index($0,FN){found=1} found; /^$/{found=""}' "$ofile")
rfile=search.txt
echo -e "$awk_result" > "$rfile"
Things fixed in OP's attempt:
NEVER keep same name of a variable as a binary's name or on a keyword's name so changed awk variable name to awk_result.
Use of backticks is depreciated now, so always wrap your variable for having values in var=$(......your commands....) fixed it for awk_result variable.
Now let us talk about awk code fix, I have used index method which checks if value of variable FN is present in a line then make a FLAG(a variable TRUE) and make it false till line is empty as per OP's ask.

Counting char in word with different delimiter

I am writing a shell script, in which I get the location of java via which java. As response I get (for example)
/usr/pi/java7_32/jre/bin/java.
I need the path to be cut so it ends with /jre/, more specificly
/usr/pi/java7_32/jre/
as the programm this information is provided to can not handle the longe path to work.
I have used cut with the / as delimiter and as I thought that the directory of the Java installation is always the same, therfore a
cut -d'/' -f1-5
worked just fine to get this result:
/usr/pi/java7_32/jre/
But as the java could be installed somewhere else aswell, for example at
/usr/java8_64/jre/
the statement would not work correctly.
I need tried sed, awk, cut and different combinations of them but found no answer I liked.
As the title says I would count the number of appereance of the car / until the substing jre/ is found under the premisse that the shell counts from the left to the right.
The incremented number would be the the field I want to see by cutting with the delimiter.
path=$(which java) # example: /usr/pi/java7_32/jre/bin/java
i=0
#while loop with a statment which would go through path
while substring != jre/ {
if (char = '/')
i++
}
#cut the path
path=$path | cut -d'/' -f 1-i
#/usr/pi/java7_32/jre result
Problem is the eventual difference in the path before and after
/java7_64/jre/, like */java*/jre/
I am open for any ideas and solutions, thanks a lot!
Greets
Jan
You can use the shell's built-in parameter operations to get what you need. (This will save the need to create other processes to extract the information you need).
jpath="$(which java)"
# jpath now /usr/pi/java7_32/jre/bin/java
echo ${jpath%jre*}jre
produces
/usr/pi/java7_32/jre
The same works for
jpath=/usr/java8_64/jre/
The % indicates remove from the right side of the string the matching shell reg-ex pattern. Then we just put back jre to have your required path.
You can overwrite the value from which java
jpath=${jpath%jre*}jre
IHTH
You can get the results with grep:
path=$(echo $path | grep -o ".*/jre/")

Update var in ini file using bash

I am attempting to write a bash script to configure various aspects of a server. The context here is replacing a value of a variable in a conf file (ini format) with another value.
The context is
[ssh-iptables]
enabled = false
And I simply need to change false to true.
Typically I'd just do this with a simple bit of sed
sed -i 's/^enabled = false/enabled = true/g' /etc/fail2ban/jail.conf
But enabled = false exists in multiple places.
I've tried using awk with no success
awk -F ":| " -v v1="true" -v opt="enabled" '$1 == "[ssh-iptables]" && !f {f=1}f && $1 == opt{sub("=.*","= "v1);f=0}1' /etc/fail2ban/jail.conf
The above was sourced from this forum thread but I don't really have enough understanding of how to use it in scripts to make it work. All it seems to do is the equivalent of cat /etc/fail2ban/jail.conf
I have found a few other scripts which are considerably longer which isn't ideal as this will happen to loads of ini files so I'm hoping someone can help me correct the above code or point me in the right direction.
Apologies if this belongs on ServerFault, but as it's scripting rather than the intricacies of server configuration itself I figured here might be more apt.
Assuming your format is that there are no square-bracket lines (like [ssh-iptables]) within sections, I would use your solution above (with sed) but restrict the query to within that block like so:
sed -i '/^\[ssh-iptables\]$/,/^\[/ s/^enabled = false/enabled = true/' /etc/fail2ban/jail.conf
The extra part at the beginning tells the following substitution statement to only run between the line that is [ssh-iptables] and the next one that starts with a [. It uses two regular expressions separated by a comma which indicate the bounds.
If you are open to use external applications, you could be interested into the use of crudini.
Example:
[oauth2provider]
module = SippoServiceOAuth2Provider
backend[] = none
wiface = public
; [calldirection]
; module = SippoServiceCallDirection
; backend[] = none
; wiface = internal
A standard grep will not filter commented exceptions.
With crudini things for consulting, setting and modify are easier:
$ crudini --get /myproject/config/main.ini oauth2provider wiface
public
$ crudini --get /myproject/config/main.ini calldirection wiface
Section not found: calldirection
I was on a bash-only app and moved to this approach. Just a suggestion.
Regards,
You might consider using m4 instead of sed in this case. This uses variable replacement and I think keeps the file looking readable. Your m4 template might look like this:
[ssh-iptables]
enabled=SSH_IPTABLES_ENABLED
Now, you call m4 with the following parameters (which can be called from a bash script):
m4 -DSSH_IPTABLES_ENABLED=true input.m4 > output.ini
or:
m4 -DSSH_IPTABLES_ENABLED=false input.m4 > output.ini
This is an overly simple way of using m4, if you read about it you'll find you can do some really nifty things (this is the infrastructure upon which autoconf/automake was initially designed).
awk '/^[ssh-iptables/ {ok=1}
ok==1 && $0="enabled = false" {print " enabled = true"; ok=0 ; next}
{print $0} ' infile > tmp
mv tmp infile

How to grep on gdb print

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.

Resources