I would suggest using gdb as the simplest approach. You can even do it as a one-liner, like:
gdb -batch -ex 'file /bin/ls' -ex 'disassemble main'
Pregunta
I've got a binary installed on my system, and would like to look at the disassembly of a given function. Preferrably using objdump
, but other solutions would be acceptable as well.
From this questions I've learned that I might be able to disassemble part of the code if I only know the boundary addresses. From this answer I've learned how to turn my split debug symbols back into a single file.
But even operating on that single file, and even disassembling all the code (i.e. without start or stop address, but plain -d
parameter to objdump
), I still don't see that symbol anywhere. Which makes sense insofar as the function in question is static, so it isn't exported. Nevertheless, valgrind
will report the function name, so it has to be stored somewhere.
Looking at the details of the debug sections, I find that name mentioned in the .debug_str
section, but I don't know a tool which can turn this into an address range.
Solución
I would suggest using gdb as the simplest approach. You can even do it as a one-liner, like:
gdb -batch -ex 'file /bin/ls' -ex 'disassemble main'
Otros consejos
disassemble/rs
to show source and raw bytes as wellWith this format, it gets really close to objdump -S
output:
gdb -batch -ex "disassemble/rs $FUNCTION" "$EXECUTABLE"
main.c
#include <assert.h>
int myfunc(int i) {
i = i + 2;
i = i * 2;
return i;
}
int main(void) {
assert(myfunc(1) == 6);
assert(myfunc(2) == 8);
return 0;
}
Compile and disassemble
gcc -O0 -ggdb3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
gdb -batch -ex "disassemble/rs myfunc" main.out
Disassembly:
Dump of assembler code for function myfunc:
main.c:
3 int myfunc(int i) {
0x0000000000001135 <+0>: 55 push %rbp
0x0000000000001136 <+1>: 48 89 e5 mov %rsp,%rbp
0x0000000000001139 <+4>: 89 7d fc mov %edi,-0x4(%rbp)
4 i = i + 2;
0x000000000000113c <+7>: 83 45 fc 02 addl $0x2,-0x4(%rbp)
5 i = i * 2;
0x0000000000001140 <+11>: d1 65 fc shll -0x4(%rbp)
6 return i;
0x0000000000001143 <+14>: 8b 45 fc mov -0x4(%rbp),%eax
7 }
0x0000000000001146 <+17>: 5d pop %rbp
0x0000000000001147 <+18>: c3 retq
End of assembler dump.
Tested on Ubuntu 16.04, GDB 7.11.1.
Print the paragraph as mentioned at: https://unix.stackexchange.com/questions/82944/how-to-grep-for-text-in-a-file-and-display-the-paragraph-that-has-the-text
objdump -d main.out | awk -v RS= '/^[[:xdigit:]]+ <FUNCTION>/'
e.g.:
objdump -d main.out | awk -v RS= '/^[[:xdigit:]]+ <myfunc>/'
gives just:
0000000000001135 <myfunc>:
1135: 55 push %rbp
1136: 48 89 e5 mov %rsp,%rbp
1139: 89 7d fc mov %edi,-0x4(%rbp)
113c: 83 45 fc 02 addl $0x2,-0x4(%rbp)
1140: d1 65 fc shll -0x4(%rbp)
1143: 8b 45 fc mov -0x4(%rbp),%eax
1146: 5d pop %rbp
1147: c3 retq
When using -S
, I don't think there is a fail-proof way, as the code comments could contain any possible sequence... But the following works almost all the time:
objdump -S main.out | awk '/^[[:xdigit:]]+ <FUNCTION>:$/{flag=1;next}/^[[:xdigit:]]+ <.*>:$/{flag=0}flag'
adapted from: How to select lines between two marker patterns which may occur multiple times with awk/sed
There is a 2010 thread on the mailing list which says it is not possible: https://sourceware.org/ml/binutils/2010-04/msg00445.html
Besides the gdb
workaround proposed by Tom, they also comment on another (worse) workaround of compiling with -ffunction-section
which puts one function per section and then dumping the section.
Nicolas Clifton gave it a WONTFIX https://sourceware.org/ml/binutils/2015-07/msg00004.html , likely because the GDB workaround covers that use case.
If you have a very recent binutils (2.32+), this is very simple.
Passing --disassemble=SYMBOL
to objdump will disassemble only the specified function. No need to pass the start address and the end address.
LLVM objdump also has a similar option (--disassemble-symbols
).
I have two solutions:
This method works perfectly and additional a simple one. I use objdump with the -d flag and pipe it through awk. The disassembled output looks like
000000000000068a <main>:
68a: 55 push %rbp
68b: 48 89 e5 mov %rsp,%rbp
68e: 48 83 ec 20 sub $0x20,%rsp
To start with, I begin with the description of the objdump output. A section or function is separated by an empty line. Therefore changing the FS (Field Separator) to newline and the RS (Record Separator) to twice newline let you easily search for your recommended function, since it is simply to find within the $1 field!
objdump -d name_of_your_obj_file | awk -F"\n" -v RS="\n\n" '$1 ~ /main/'
Of course you can replace main with any other function you would like to print.
I have written a small bash script for this issue. Paste and copy it and save it as e.g. dasm file.
#!/bin/bash
# Author: abu
# filename: dasm
# Description: puts disassembled objectfile to std-out
if [ $# = 2 ]; then
sstrg="^[[:xdigit:]]{2,}+.*<$2>:$"
objdump -d $1 | awk -F"\n" -v RS="\n\n" '$1 ~ /'"$sstrg"'/'
elif [ $# = 1 ]; then
objdump -d $1 | awk -F"\n" -v RS="\n\n" '{ print $1 }'
else
echo "You have to add argument(s)"
echo "Usage: "$0 " arg1 arg2"
echo "Description: print disassembled label to std-out"
echo " arg1: name of object file"
echo " arg2: name of function to be disassembled"
echo " "$0 " arg1 ... print labels and their rel. addresses"
fi
Change the x-access and invoke it with e.g.:
chmod +x dasm
./dasm test main
This is much faster than invoking gdb with a script. Beside the way using objdump will not load the libraries into memory and is therefore safer!
Vitaly Fadeev programmed an auto-completion to this script, which is really a nice feature and speeds up typing.
The script can be found here.
To simplify the usage of awk for parsing objdump's output relative to other answers:
objdump -d filename | sed '/<functionName>:/,/^$/!d'
This works just like the gdb solution (in that that it shifts the offsets towards zero) except that it's not laggy (gets the job done in about 5ms on my PC whereas the gdb solution takes about 150ms):
objdump_func:
#!/bin/sh
# $1 -- function name; rest -- object files
fn=$1; shift 1
exec objdump -d "$@" |
awk " /^[[:xdigit:]].*<$fn>/,/^\$/ { print \$0 }" |
awk -F: -F' ' 'NR==1 { offset=strtonum("0x"$1); print $0; }
NR!=1 { split($0,a,":"); rhs=a[2]; n=strtonum("0x"$1); $1=sprintf("%x", n-offset); printf "%4s:%s\n", $1,rhs }'
./dasm
Complete symbol names to this solution (D lang version):
dasm test
and then pressing TabTab, you will get a list of all functions. dasm test m
and then pressing TabTab all functions starting with m will be shown, or in case only one function exists, it will be autocompleted.File /etc/bash_completion.d/dasm
:
# bash completion for dasm
_dasm()
{
local cur=${COMP_WORDS[COMP_CWORD]}
if [[ $COMP_CWORD -eq 1 ]] ; then
# files
COMPREPLY=( $( command ls *.o -F 2>/dev/null | grep "^$cur" ) )
elif [[ $COMP_CWORD -eq 2 ]] ; then
# functions
OBJFILE=${COMP_WORDS[COMP_CWORD-1]}
COMPREPLY=( $( command nm --demangle=dlang $OBJFILE | grep " W " | cut -d " " -f 3 | tr "()" " " | grep "$cur" ) )
else
COMPREPLY=($(compgen -W "" -- "$cur"));
fi
}
complete -F _dasm dasm
Not exactly what you asked, but if you are compiling a C or C++ program from source with GCC, you can add a function attribute to put it in a custom named section of the binary:
extern __attribute__((noinline, section("disasm"))) void foo() {}
Then you can ask objdump
to show only functions in that named section with -jdisasm
.
maybe this is easy to do:
objdump -d libxxx.so | grep -A 50 func_name_to_be_searched
Just use objdump -d filename | awk '/<funcname>/,/^$/'
For those who want to look at the assembly of a binary with debug symbols. As per the man
page:
objdump -d <binary> --disassemble=<symbol>
should do the trick. No need to use gdb
or any other utilities.
In gcc-objdump,it can be objdump -C --disassemble="funcName" -j.text procName