How to get my program name in GDB when writting a "define" script? - gdb

I found it's very annoying to get the program name when defining a GDB script. I can't find any corresponding "info" command, and we can't use argv[0] either, because of multi-process/thread and frame-choosing.
So, what should I do?

If you are using a recent gdb (7 and above) you can play around with the Python support which is quite extensive (and probably where you want to go when defining gdb-scripts in general). I'm no expert at it but for a test-program /tmp/xyz I could use:
(gdb) python print gdb.current_progspace().filename
/tmp/xyz
See http://sourceware.org/gdb/current/onlinedocs/gdb/Python.html for more info on the Python support.
In "normal" gdb you could get the process name with "info proc" and "info target", but I guess you wanted it not just printed but being able to use it further in scripts? Don't know how to get the value out of the python runtime into a gdb variable other than the extremely ugly "using log files and sourcing it and hope for the best". This is how this could be done:
define set-program-name
set logging file tmp.gdb
set logging overwrite on
set logging redirect on
set logging on
python print "set $programname = \"%s\"" % gdb.current_progspace().filename
set logging off
set logging redirect off
set logging overwrite off
source tmp.gdb
end
and in your own function doing:
define your-own-func
set-program-name
printf "The program name is %s\n", $programname
end
I would suggest "going all in" on the python support, and scrap gdb-scripting. I believe it is worth the effort.

Related

Receiving back string of lenght 0 from os.popen('cmd').read()

I am working with a command line tool called 'ideviceinfo' (see https://github.com/libimobiledevice) to help me to quickly get back serial, IMEI and battery health information from the iOS device I work with daily. It executes much quicker than Apple's own 'cfgutil' tools.
Up to know I have been able to develop a more complicated script than the one shown below in PyCharm (my main IDE) to assign specific values etc to individual variables and then to use something like to pyclip and pyautogui to help automatically paste these into the fields of the database app we work with. I have also been able to use the simplified version of the script both in Mac OS X terminal and in the python shell without any hiccups.
I am looking to use AppleScript to help make running the script as easy as possible.
When I try to use Applescript's "do shell script 'python script.py'" I just get back a string of lenght zero when I call 'ideviceinfo'. The exact same thing happens when I try to build an Automator app with a 'Run Shell Script' component for "python script.py".
I have tried my best to isolate the problem down. When other more basic commands such as 'date' are called within the script they return valid strings.
#!/usr/bin/python
import os
ideviceinfoOutput = os.popen('ideviceinfo').read()
print ideviceinfoOutput
print len (ideviceinfoOutput)
boringExample = os.popen('date').read()
print boringExample
print len (boringExample)
I am running Mac OS X 10.11 and am on Python 2.7
Thanks.
I think I've managed to fix it on my own. I just need to be far more explicit about where the 'ideviceinfo' binary (I hope that's the correct term) was stored on the computer.
Changed one line of code to
ideviceinfoOutput = os.popen('/usr/local/bin/ideviceinfo').read()
and all seems to be OK again.

lldb command if statement

Hi I need to write a lldb breakpoint command that evaluates a value and prints out a value.
In gdb I could do it like this:
if ($value==2)
printf "Value is 2\n"
end
But in lldb the 'if-statement' is invalid it seems:
failed with error: 'if' is not a valid command.
error: Unrecognized command 'if'.
Can anyone tell me how to write this comparison inside my breakpoint command? Thanks!
You can use the expression parser to achieve this effect in some cases, and you can use the lldb Python interpreter for whatever complex work you want to do in response to a breakpoint hit. Given the fairly deep level of Python support, we felt if you don't know Python, you time would be better spent learning a little bit of that so you could really script lldb, rather than learning whatever little micro-language we would come up with.
Anyway, so using the interpreter, you could for instance do:
expr if ($value == 2) { (int) printf("Value is 2\n"); }
And using the python interpreter you can write a callback like:
def myCallback (frame, breakpoint_location, dict):
value = frame.FindValue("$value", lldb.eValueTypeConstResult)
if (value.unsigned == 10):
print "Value is 10"
put that in a file called myModule.py, do:
(lldb) command script import myModule.py
and then assign the command to your breakpoint with:
(lldb) breakpoint command add -F myModule.myCallback <BREAKPOINT_NUMBER>
That python example was a little more complex than normal because you were looking up lldb's equivalent of gdb's "convenience variable". If you were looking up a local, you could use frame.FindVariable.
More details on this at:
http://lldb.llvm.org/python-reference.html

How to evaluate an expression to be used for a gdb monitor command?

Inside a scripted gdb session I want to use monitor <cmd> where cmd should contain the address of a symbol. For example:
monitor foobar &myVariable
should become to:
monitor foobar 0x00004711
Because the remote side cannot evaluate the expression. Whatever I tried, the string "&myVariable" gets sent instead of the address.
I played around with convenience variables and stuff, but this is the only workaround I found:
# write the command into a file and execute this file
# didn't find a direct way to include the address into the monitor command
set logging overwrite on
set logging on command.tmp
printf "monitor foobar 0x%08x\n", &myVariable
set logging off
source command.tmp
Any ideas to solve this in a more elegant way?
The simplest way to do this is to use the gdb eval command, which was introduced for exactly this purpose. It works a bit like printf:
(gdb) eval "monitor foobar %p", &myVariable
(I didn't actually try this, so caution.)
If your gdb doesn't have eval, then it is on the old side. I would suggest upgrading.
If you can't upgrade, then you can also script this using Python.
If your gdb doesn't have Python, then it is either very old (upgrade!) or compiled without Python support (recompile!).
If you can't manage to get either of these features, then I am afraid the "write out a script and source it" approach is all that is left.

GDB python script for bounded instruction tracing

I'm trying to write a GDB script to do instruction tracing in a bounded maner (i.e start addr and stop addr). Perhaps I'm failing at google but I cant seem to find this in existence already.
Here is my stab at it:
python
def start_logging():
gdb.execute("set logging on")
gdb.execute("while $eip != 0xBA10012E9")
gdb.execute("x/1i $eip")
gdb.execute("stepi")
gdb.execute(" end")
gdb.execute("set logging off")
gdb.execute("set pagination off")
gdb.execute("break *0xBA19912CF")
gdb.execute("command 1 $(start_logging())")
gdb.execute("continue")
In my mind this should set up a breakpoint then set the command to run when it hits. When the breakpoint hits it should single step through the code until the end address is hit and then it will turn off logging.
When I run this with gdb the application will break at the correct point but no commands are run.
What am I doing wrong? Sorry if this is the wrong way to go about this please let me know. I'm new to gdb scripting
I see a few odd things in here.
First, it looks like you are trying to split multi-line gdb commands across multiple calls to gdb.execute. I don't believe this will work. Certainly it isn't intended to work.
Second, there's no reason to try to do a "while" loop via gdb.execute. It's better to just do it directly in Python.
Third, I think the "command" line seems pretty wrong as well. I don't really get what it is trying to do, I guess call start_logging when the breakpoint is hit? And then continue? Well, it won't work as written.
What I would suggest is something like:
gdb.execute('break ...')
gdb.execute('run')
while gdb.parse_and_eval('$eip') != 0x...:
gdb.execute('stepi')
If you really want logging, either do the 'set logging' business or just instruct gdb.execute to return a string and log it from Python.

Dumping memory in gdb - how to choose the file name at run time

I'm running a program that does processing on a file.
I want to be able to supply the program with several files, and by attaching to it with gdb, I want to get a memory dump at a certain point in the code for each of the files. I want the dump for each file to go to a file with the same filename as the input file (maybe after formatting it a little, say adding a suffix)
So suppose I have a function called HereIsTheFileName(char* filename), and another function called DumpThisMemoryRegion(void* startAddr, void* endAddr), I want to do something like the following:
To get the file name to an environment variable:
break HereIsTheFileName
commands 1
set $filename = malloc(strlen(filename) + 1)
call memcpy($filename, filename, strlen(filename) + 1)
end
Then to dump the memory to the filename I saved earlier:
break DumpThisMemoryRegion
commands 2
append binary memory "%s.memory"%$filename startAddr endAddr
end
(I would even settle for the filename as it is, without formatting, if that turns out to be the difficult part)
However, I couldn't get gdb to accept anything except an exlicit file name for the append/dump commands. when I ran "append binary memory $filename ..." I got the output in the file "/workdir/$filename".
Is there any way to make gdb choose the file name at runtime?
Thanks!
I don't know how to make append accept a runtime filename, but you can always cheat a bit by writing the whole thing to a file and then sourcing that file, using logging.
By putting this in your ~/.gdbinit
define reallyappend
printf "using gdbtmp.log to dump memory to file %s\n", $arg0
set logging file gdbtmp.log
set logging overwrite on
set logging redirect on
set logging on
printf "append binary memory %s 0x%x 0x%x", $arg0, $arg1, $arg2
set logging off
set logging redirect off
set logging overwrite off
source gdbtmp.log
end
you can use the function reallyappend instead, for example with
(gdb) set $filename = "somethingruntimegenerated"
(gdb) reallyappend $filename startAddr endAddr
I don't know if logging works ok in an "commands" environment, but you can give it a shot at least.
Yeah, you can't use a variable here for the filename argument.
The best suggestion I can offer is to write a script that will
set all the breakpoints and set up the "append" commands, and
use text editing or awk and sed to set up the filenames in the
script.