I'd like to know how can I match the external functions called by a binary with their linked shared library.
For example, I can see the functions looking at the .plt section of a disassembled file, and I can find out the used libraries using ldd (or looking at the ELF dynamic section); but how can I match each function with its library?
I followed the Laszio hint and I've created a little python function which get a binary file name and by mixing ldd and nm, returns a dictionary which contains the external functions with their shared libraries.
Maybe it is a little confusing, but it works :)
Here it is the code
def get_dynamicOBJ(filename):
p_nm = subprocess.Popen(["nm", "-D", filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
result_nm = p_nm.stdout.readlines()
p_ldd = subprocess.Popen(["ldd", filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
result_ldd = p_ldd.stdout.readlines()
dyn = {}
for nm_out in result_nm:
sym_entry = nm_out.split()
if len(sym_entry) >= 2 and sym_entry[0 if len(sym_entry) == 2 else 1] == "U":
sym = sym_entry[1 if len(sym_entry) == 2 else 2]
for lld_out in result_ldd:
lib_entry = lld_out.split()
if "=>" in lld_out and len(lib_entry) > 3: # virtual library
lib = lib_entry[2]
ls_nm = subprocess.Popen(["nm", "-D", lib], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
result_lsnm = ls_nm.stdout.readlines()
for ls_nm_out in result_lsnm:
lib_symbol = ls_nm_out.split()
if len(lib_symbol) >= 2 and lib_symbol[0 if len(lib_symbol) == 2 else 1] == "T":
if sym == lib_symbol[1 if len(lib_symbol) == 2 else 2]:
dyn[sym] = lib
return dyn
Related
I want to pass my file to C function.
I have problem with this. I saw "Segmentation fault"
My C code:
// cc -fPIC -shared -o w.so w.c
#include <stdio.h>
void my_writer(FILE *fp, int num) {
fprintf(fp, "%d\n", num);
}
My python code:
#!/usr/bin/python3
#
from ctypes import *
so_file = "./w.so"
my_c_writer = CDLL(so_file)
my_num = 2022
try:
convert_file = pythonapi.PyObject_AsFileDescriptor
convert_file.argtypes = [py_object]
convert_file.restype = c_int
# fp = open('path').fp there is no .fp attribute!
fp = open('num.txt', 'w')
c_file = convert_file(fp)
my_c_writer.my_writer(c_file, c_int(my_num))
fp.close()
except Exception as e:
print(e)
I searched a lot but I found nothing.
The C code file is unchangeable.
I would very appreciate if you help me.
As Mark mentioned, c_file in your Python module is a file descriptor and not FILE*. I was able to get the code to work after I wrote a wrapper function in C.
void my_writer_wrapper(int fildes, int num) {
FILE *fp = fdopen(fildes, "w");
my_writer(fp, num);
fflush(fp);
}
Instead of using my_writer directly, you can use the wrapper:
...
fp = open('num.txt', 'w')
c_file = convert_file(fp)
my_c_writer.my_writer_wrapper(c_file, c_int(my_num))
fp.close()
...
I would like to increment the values based on assert results :
def a = 1
def b = 1
def c = 0
def d = 0
(assert a==b, "Mismatch") ? (c++) : (d++)
Is it possible?
You misunderstood one important part - assert is not a function and it does not return any value. It is a Groovy's (and Java) keyword (statement) that throws an exception if the expression on the right side evaluates to false, but it does not return any result. However, you can achieve expected result using ternary operator in the way it was designed to use:
def a = 1
def b = 1
def c = 0
def d = 0
a == b ? (c++) : (d++)
println "c = ${c}, d = ${d}"
Output:
c = 1, d = 0
You can read more about using assertions in Groovy's official "Testing Guide, chapter 2.1 Power Assertions".
If you really want to "ignore" the assert and continue, you can catch the exception it throws. E.g.
def a = 1
def b = 1
def c = 0
def d = 0
try {
assert a==b, 'Mismatch'
c++
}
catch (AssertionError e) {
d++
}
println([a,b,c,d])
I'd only use tactics like that, if some foreign code dictates that on me. This is very convoluted code unless you want to abuse the power-assert to generate a nice "warning" log message for you.
I cannot figure this one out. When I remove let size = s.readInt64() from the following proc, the .exe seems to terminate before it reaches the end. It is declared but not used! Its gotta go!
proc load(fn: string): Alternating =
var s = newFileStream(fn, fmRead)
let size = s.readInt64() #WITHOUT THIS LINE THE .exe doesn't execute ExitTerminal()
result = newSeq[(float, int)]()
while not s.atEnd:
let element = (s.readFloat64.float, s.readInt64.int)
result.add(element)
s.close()
Below is the entire program. The file type is .dat and I suppose it is binary. It is created in the program. I compiled with -d:release Nim version 0.18.0 and minGW compiler
import streams
type
Alternating = seq[(float, int)]
proc store(fn: string, data: Alternating) =
var s = newFileStream(fn, fmWrite)
s.write(data.len)
for x in data:
s.write(x[0])
s.write(x[1])
s.close()
proc load(fn: string): Alternating =
var s = newFileStream(fn, fmRead)
let size = s.readInt64() #WITHOUT THIS LINE THE .exe doesn't execute ExitTerminal()
result = newSeq[(float, int)]()
while not s.atEnd:
let element = (s.readFloat64.float, s.readInt64.int)
result.add(element)
s.close()
let data = #[(1.0, 1), (2.0, 2)]
store("tmp.dat", data)
let dataLoaded = load("tmp.dat")
echo dataLoaded
### EXIT PROCEDURE FROM TERMINAL PROGRAM
proc ExitTerminal: bool =
echo "Exit Application"
echo "(y/n)"
while true:
case readline(stdin)
of "y", "Y", "yes", "Yes": return true
of "n", "N", "no", "No": return false
else: echo "Please be clear: yes or no"
if ExitTerminal() == false: discard ExitTerminal()
It is hard to tell because we know nothing about the file format you're reading. But generally you can't remove s.readInt64() just because it is unused, because apart from reading this proc advances your stream cursor. If you need to ignore the value just use discard s.readInt64() # Ignore size
I want to check in Scons that my compiler support some option (for example
-fcilkplus). The only way I manage to do it is the following sequence of
operations:
env.Prepend(CXXFLAGS = ['-fcilkplus'], LIBS = ['cilkrts'])
Then I launch my custom checker:
def CheckCilkPlusCompiler(context):
test = """
#include <cilk/cilk.h>
#include <assert.h>
int fib(int n) {
if (n < 2) return n;
int a = cilk_spawn fib(n-1);
int b = fib(n-2);
cilk_sync;
return a + b;
}
int main() {
int result = fib(30);
assert(result == 832040);
return 0;
}
"""
context.Message('Checking Cilk++ compiler ... ')
result = context.TryRun(test, '.cpp')
context.Result(result[0])
return result[0]
Now if it fails, I have to remove the two options extra flags -fcilkplus
cilkrts from the environment variables. Is there a better way to do that ?
The problem is that I can't manage to access to the env from the context and
therefore I can't make a clone of it.
You can use check the availability of a library with SCons as follows:
env = Environment()
conf = Configure(env)
if not conf.CheckLib('cilkrts'):
print 'Did not find libcilkrts.a, exiting!'
Exit(1)
else:
env.Prepend(CXXFLAGS = ['-fcilkplus'], LIBS = ['cilkrts'])
env = conf.Finish()
You could also check the availability of a header as follows:
env = Environment()
conf = Configure(env)
if conf.CheckCHeader('cilk/cilk.h'):
env.Prepend(CXXFLAGS = ['-fcilkplus'], LIBS = ['cilkrts'])
env = conf.Finish()
Update:
I just realized, you can access the environment on the Configure object as follows:
conf.env.Append(...)
I was writing an AI solution to the TJ Wriggler problem and I'm having an issue that's causing my program to hang. I'm not exactly sure what it is since I should have more than enough memory to run the code. Rather, I think I'm changing a reference somewhere that I shouldn't be but I can't seem to figure out the exact place.
I'll run through execution up to the point where the program hangs:
First, the search function:
def BFTS(the_frontier):
index = 0
frontier = [the_frontier]
while(True):
if (not frontier):
return None
leaf = frontier.pop(0)
if (leaf.GoalTest()):
return leaf
index = index + 1
moves_list = leaf.FindMoves(index)
while(len(moves_list) > 0):
frontier.append(moves_list.pop(0))
This calls the FindMoves() function:
def FindMoves(self, current_index):
moves_list = []
for wriggler in self.State.Wrigglers:
for seg in [wriggler.Head(), wriggler.Tail()]:
is_head = {
wriggler.Head() : True,
wriggler.Tail() : False}[seg]
for move in self.State.FindEmptySpaces(seg):
if (move is not None):
moves_list.append(self.Move(wriggler.Index,
is_head, move['x'], move['y'], current_index))
return moves_list
FindEmptySpaces() finds all spaces that can be moved into and returns a list of dictionaries represent Cartesian coordinates. The FindMoves() function then calls the Move() function:
def Move(self, wriggler_id, is_head, new_x, new_y, current_index):
head_or_tail = {True : 0, False : 1}[is_head]
# Find action
new_action = ("%s %s %s %s" % (wriggler_id, head_or_tail, new_x, new_y))
new_node = self.CopyNode()
new_index = current_index
new_node.State.MoveWriggler(wriggler_id, new_y, new_x, is_head)
return Node(new_node.State, new_action, new_index, self.Cost + Node.Step_Cost)
This function calls the CopyNode() function:
def CopyNode(self):
# Create new Spaces List-of-List
new_spaces = DataStructures.CopyListOfLists(self.State.Spaces)
new_state = Board(new_spaces)
# Create new List of Actions
new_action = []
for action in self.Action:
new_action.append(action)
# Create new Node
return Node(new_state, new_action, self.Parent, self.Cost)
The CopyNode() function calls the CopyListOfLists() function:
def CopyListOfLists(the_list_of_list):
new_list = []
for lists in the_list_of_list:
temp_list = []
for items in lists:
temp_list.append(items)
new_list.append(temp_list)
return new_list
As far as I can tell, the program hangs in the function CopyNode() but the strange thing is that it only does this on the second pass through Search_BFTS(). As I say, I probably changed a reference somewhere but I'm not experienced enough in Python to know for sure if this is the actual problem.
Any help that could be offered would be great.
Thanks,