Setup: GDB running the internal python interpreter with a script. The content of the script runs the disas on some memory.
I need the output of this command in a python string. How can I do this?
Thought about logging, but it turned out that only the first line of the command is logged:
Dump of assembler code from 0x8000 to 0x8030:
The expected result of the disas is on the screen, but NOT in the logfile.
0x00008000: fsw fa0,24(a5)
0x00008002: fsd fs6,16(sp)
0x00008004: addi s1,sp,920
...
Is it possible to redirect stdout into a stream or to get the info on somehow other way?
EDIT: I've connected GDB to an openOCD server. On my target are the assembler commands. There is no elf-file ore so on, where I get the source code from. It's just pure machine instructions residing on the controllers program memory and I need to get this printed.
The simplest way to get the output of disassemble into a string is to give gdb.execute a to_string=Trueargument.
(gdb) start
...
(gdb) pi
>>> import pprint
>>> pp=pprint.PrettyPrinter()
>>> pp.pprint(gdb.execute("disassemble main",to_string=True))
('Dump of assembler code for function main:\n'
' 0x00005555555546a4 <+0>:\tpush %rbp\n'
' 0x00005555555546a5 <+1>:\tmov %rsp,%rbp\n'
'=> 0x00005555555546a8 <+4>:\tcallq 0x555555554560 <pause#plt>\n'
' 0x00005555555546ad <+9>:\tmov $0x0,%eax\n'
' 0x00005555555546b2 <+14>:\tpop %rbp\n'
' 0x00005555555546b3 <+15>:\tretq \n'
'End of assembler dump.\n')
>>>
(I'm using pprint here so that it displays nicely in a terminal session.)
You can write this to a file:
>>> with open("logfile","w") as log:
... log.write(gdb.execute("disassemble main",to_string=True))
...
335
It's not too hard to parse this, but as long as you're using gdb's python extensions, you might want to use the gdb.Architecture.disassemble method, which does most of the work for you:
>>> frame=gdb.selected_frame()
>>> hex(frame.block().start)
'0x5555555546a4'
>>> hex(frame.block().end) # doc says this is "one past the last address that appears in the block"
'0x5555555546b4'
>>> arch=frame.architecture()
>>> arch.name()
'i386:x86-64'
>>> pp.pprint(arch.disassemble(frame.block().start, frame.block().end - 1))
[{'addr': 93824992233124, 'asm': 'push %rbp', 'length': 1},
{'addr': 93824992233125, 'asm': 'mov %rsp,%rbp', 'length': 3},
{'addr': 93824992233128, 'asm': 'callq 0x555555554560 <pause#plt>', 'length': 5},
{'addr': 93824992233133, 'asm': 'mov $0x0,%eax', 'length': 5},
{'addr': 93824992233138, 'asm': 'pop %rbp', 'length': 1},
{'addr': 93824992233139, 'asm': 'retq ', 'length': 1}]
>>>
If there's no debug info for your program, frame.block() will fail with RuntimeError: Cannot locate block for frame.. You can still successfully call arch.disassemble or the gdb disassemble command; just use numeric arguments.
Related
I am attempting to understand; and resolve, why the following happens:
$ python
>>> import struct
>>> list(struct.pack('hh', *(50,50)))
['2', '\x00', '2', '\x00']
>>> exit()
$ python3
>>> import struct
>>> list(struct.pack('hh', *(50, 50)))
[50, 0, 50, 0]
I understand that hh stands for 2 shorts. I understand that struct.pack is converting the two integers (shorts) to a c style struct. But why does the output in 2.7 differ so much from 3.5?
Unfortunately I am stuck with python 2.7 for right now on this project and I need the output to be similar to one from python 3.5
In response to comment from Some Programmer Dude
$ python
>>> import struct
>>> a = list(struct.pack('hh', *(50, 50)))
>>> [int(_) for _ in a]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: ''
in python 2, struct.pack('hh', *(50,50)) returns a str object.
This has changed in python 3, where it returns a bytes object (difference between binary and string is a very important difference between both versions, even if bytes exists in python 2, it is the same as str).
To emulate this behaviour in python 2, you could get ASCII code of the characters by appling ord to each char of the result:
map(ord,struct.pack('hh', *(50,50)))
is there eval function? I've read "help" and I didnt find
I want to make eval("gdb command")
because I want to create my own function for grepping using this method
How to grep on gdb print.
I want to make eval($arg1)
There is an eval command, but it doesn't really do what you want. It provides a limited form of substitution of values into commands.
For a command along the lines of grep, I would suggest writing it in Python. This would be relatively easy to do. The idea would be to use gdb.execute to capture the output of a command into a string, and then use Python to search the string however you like. If done from Python you have complete control of how to parse the command-line, something that's not true if you use the gdb define command.
Oddly enough, I wrote a grep python gdb function earlier today for another question. These couple of files make a new command that checks if the call stack contains _malloc. This should be a pretty good start for other string searching and evaluation functions.
Here is a script for gdb
# gdb script: pygdb-logg.gdb
# easier interface for pygdb-logg.py stuff
# from within gdb: (gdb) source -v pygdb-logg.gdb
# from cdmline: gdb -x pygdb-logg.gdb -se test.exe
# first, "include" the python file:
source -v pygdb-logg.py
# define shorthand for inMalloc():
define inMalloc
python inMalloc()
end
Here is the python file:
#!/usr/bin/python
# gdb will 'recognize' this as python
# upon 'source pygdb-logg.py'
# however, from gdb functions still have
# to be called like:
# (gdb) python print logExecCapture("bt")
import sys
import gdb
import os
def logExecCapture(instr):
# /dev/shm - save file in RAM
ltxname="/dev/shm/c.log"
gdb.execute("set logging file "+ltxname) # lpfname
gdb.execute("set logging redirect on")
gdb.execute("set logging overwrite on")
gdb.execute("set logging on")
gdb.execute("bt")
gdb.execute("set logging off")
replyContents = open(ltxname, 'r').read() # read entire file
return replyContents
# in malloc?
def inMalloc():
isInMalloc = -1;
# as long as we don't find "Breakpoint" in report:
while isInMalloc == -1:
REP=logExecCapture("n")
#Look for calls that have '_malloc' in them
isInMalloc = REP.find("_malloc")
if(isInMalloc != -1):
# print ("Malloc:: ", isInMalloc, "\n", REP)
gdb.execute("set $inMalloc=1")
return True
else:
# print ("No Malloc:: ", isInMalloc, "\n", REP)
gdb.execute("set $inMalloc=0")
return False
I have the following piece of code copied from book programming collective intelligence page 118, chapter "Document Filtering". This function breaks up the text into words by dividing the text on any character that isn't a letter. This leaves only actual words,all converted to lower-case.
import re
import math
def getwords(doc):
splitter=re.compile('\\W*')
words=[s.lower() for s in splitter.split(doc)
if len(s)>2 and len(s)<20]
return dict([(w,1) for w in words])
I implemented the function and got the following error:
>>> import docclas
>>> t=docclass.getwords(s)
Traceback (most recent call last):
File "<pyshell#15>", line 1, in <module>
t=docclass.getwords(s)
File "docclass.py", line 6, in getwords
words=[s.lower() for s in splitter.split(doc)
NameError: global name 'splitter' is not defined
It works here
>>> import re
>>>
>>> def getwords(doc):
... splitter=re.compile('\\W*')
... words=[s.lower() for s in splitter.split(doc)
... if len(s)>2 and len(s)<20]
... return dict([(w,1) for w in words])
...
>>> getwords ("He's fallen in the water!");
{'water': 1, 'the': 1, 'fallen': 1}
I'm gueesing you made a typo in your code, but got it right when you pasted it here.
I've got one more novice question:
I've got numerous links to external files and some of the directorate names are quite long (due to original folder structure). I've tried numerous methods for breaking a line, but most of them fails while using it with conjunction with pyodbc module.
So far I've got:
SIMD = xlrd.open_workbook(r'P:\Costing and Income\Projects & Planning\HRG, '\
'IRF, Programme Budgeting\__2008-11\Developments\SIMD\PI_upload (08.05.2012).xls')
Which works OK for xlrd module
Tried some simple stuff directly in the IDLE:
>>> a = 'some text'\
'more stuff'
>>> a
'some textmore stuff'
>>> b = r'some stuff'\
' even more'
>>> b
'some stuff even more'
>>> c = r'one' r'two'
>>> c
'onetwo'
>>>
And now the part that fails me:
PCPath1 = r'Z:\IRF\Data\Primary Care Hospitals\PI\_'\
'2008-11 (final)\2012.08.15 - 2008-11_PCH_v4.mdb'
PCConn1 = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)}; DBQ='+PCPath1)
I've got following error:
Traceback (most recent call last):
File "Z:/IRF/Python/Production/S3_PC1_0811.py", line 7, in <module>
PCConn1 = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)}; DBQ='+PCPath1)
UnicodeDecodeError: 'ascii' codec can't decode byte 0x81 in position 100: ordinal not in range(128)
It works OK when PCPath1 is not broken down.
One could ask why I'm trying to do it, well mostly is for the code readibility.
Any help with above would be greatly appreciated!
You need to put an r in front of the second line as well, otherwise the \ will be combined with the 201 to produce the non-ascii character \x81.
In [5]: r'Z:\IRF\Data\Primary Care Hospitals\PI\_'\
'2008-11 (final)\2012.08.15 - 2008-11_PCH_v4.mdb'
Out[5]: 'Z:\\IRF\\Data\\Primary Care Hospitals\\PI\\_2008-11 (final)\x812.08.15 - 2008-11_PCH_v4.mdb'
In [6]: r'Z:\IRF\Data\Primary Care Hospitals\PI\_'\
r'2008-11 (final)\2012.08.15 - 2008-11_PCH_v4.mdb'
Out[6]: 'Z:\\IRF\\Data\\Primary Care Hospitals\\PI\\_2008-11 (final)\\2012.08.15 - 2008-11_PCH_v4.mdb'
I'm studying Python using Sublime Text 2.
I typed just the following two statements:
usr = raw_input('input any letters: ')
print usr
After pressing CMD+B, the following error message occurred.
input any letters: Traceback (most recent call last):
File "/Users/jun/Documents/workspace/studyPython/test.py", line 1, in <module>
usr = raw_input('input any letters: ')
EOFError: EOF when reading a line
[Finished in 0.3s with exit code 1]
How can I fix it? (I'm using Python 2.7.3 in OS X 10.8.2)
The problem is that raw_input isn't getting any input when you run the file in Sublime Text 2, so Python is throwing an error.
In the console that appears (where you see the error), there isn't anywhere for you to type in your arguments. You need to run the script at the command line to make it work. At a shell prompt (in OS X, probably Terminal, found in /Applications/Utilities/Terminal.app), type the following line:
python /path/to/script/test.py
The following line then appears:
input any letters:
with a cursor at the end of the line. This is prompting you to enter your raw_input, which allows it to set the use variable. You then type some text, for example:
input any letters: this is some text
and Python will print what you just typed:
this is some text
This doesn't work in SL2, because SL2 (afaik) doesn't have a way to offer you that prompt for raw_input.