web-dev-qa-db-fra.com

liste les fonctions exportées de dll avec des ctypes

Existe-t-il un moyen de savoir quelles fonctions sont exportées de la bibliothèque de fonctions étrangères dll à python ctypes?

Et, si possible, connaître les détails des fonctions exportées via ctypes.

Si oui, quelqu'un pourrait-il fournir un extrait de code?

32
Tom

Je ne pense pas que ctypes offre cette fonctionnalité. Sous Windows avec Visual Studio:

DUMPBIN -EXPORTS XXX.DLL

Ou pour les fenêtres:

objdump -p XXX.dll
15
Mark

Si vous êtes sous Linux, il existe un utilitaire pratique nm permettant de répertorier le contenu d'une bibliothèque partagée (il existe toujours un utilitaire pratique sous Linux, en particulier pour les éléments C).

Voici la question à ce sujet.

Vous l'utilisez avec l'indicateur -D: nm -D ./libMyLib.so

9
xealits

En général, cela n’est pas possible car, toujours en général, les bibliothèques à chargement dynamique ne contiennent pas les méta-informations requises. Il est peut-être possible d'obtenir ces informations dans certains cas particuliers par des moyens spécifiques au système, mais ctypes ne lui-même ne les récupère pas. Vous pouvez enregistrer ces informations via ctypes (voir, par exemple, les attributs restype et argtypes des pointeurs de fonction), mais seulement après que vous les ayez obtenues par différents moyens.

7
Alex Martelli

La réponse de @ Mark utilise les outils Visual Studio.

Sous Windows, vous pouvez également utiliser Dependency Walker pour obtenir les noms de fonction des exportations de DLL.

Parfois, les noms sont mutilés et ne peuvent pas être utilisés comme nom de fonction python valide.

Vous pouvez utiliser getattr pour obtenir un descripteur des fonctions modifiées, par exemple:

mylib = ctypes.cdll('mylib.dll')
my_func = getattr(mylib, '_my_func@0')

my_func()
5
Peter Wood

Si vous avez également le code source de ladite bibliothèque et que vous recherchez une méthode entièrement automatisée entièrement en python, vous pouvez utiliser pycparser

pour le fichier: prog.c

typedef short int ret_t;
typedef short int param_t;

ret_t add(param_t a, param_t b) {
    return (ret_t)(a + b);
}

ret_t passthrough(ret_t (* func)(param_t a, param_t b), param_t a, param_t b) {
    // parameter intentionally altered.
    // if this isn't done, compiler will deem entire function redundant
    return func(a, b + 1);
}

compiler avec gcc

gcc -I. -E ./prog.c > prog-preproc.c

nous donne le fichier c prétraité: prog-preproc.c puis en python:

import pycparser
parser = pycparser.c_parser.CParser()

with open('prog-preproc.c', 'r') as fh:
    ast = parser.parse(fh.read())

class FunctionVisitor(pycparser.c_ast.NodeVisitor):
    def visit_FuncDef(self, node):
        print("found function: %s" % node.decl.name)
        #node.show()

FunctionVisitor().visit(ast)

les rendements

found function: add
found function: passthrough

Pour continuer à creuser, vous pouvez également obtenir les types de paramètre et de retour. Annuler le commentaire node.show() pour plus d'informations à partir de l'arbre de syntaxe abstraite (AST)

Je publierai bientôt une bibliothèque pour cela (je vais essayer de me rappeler de revenir et de déposer un lien)

1
FraggaMuffin

OUI! il existe une méthode native très intelligente pour le faire. 

disons que vous utilisez des types Python. mettez quelque chose comme ceci dans votre code C:

1) dans votre code C:

#define PYEXPORT extern "C" __declspec(dllexport)

placez maintenant PYEXPORT au-dessus de la fonction que vous souhaitez exporter:

PYEXPORT
int myfunc(params){

2) Après la compilation, retournez dans Python et ouvrez votre fichier .c, puis analysez-le comme suit:

source1_ = open(cfile_name + '.c')
source1 = source1_.read()
source1_.close()
fn = source1.split('PYEXPORT')[-1].split('(')[0].split(' ')[1]

Entrée shell: fn 

Sortie du shell: 'myfunc' 

3) Maintenant, voici la partie intelligente: définissez une nouvelle fonction dans une chaîne:

a1 = """
global get_c_fn
def get_c_fn(dll):
     func = dll."""
a2 = """
return func"""
a3 = a1 + fn + a2

print(a3)
global get_c_fn
def get_c_fn(dll):
    func = dll.myfunc
    return func

MAINTENANT exécutez exec (a3) ​​et il transformera cette chaîne en une fonction que vous pouvez utiliser. 

4) faire comme d'habitude: 

mydll = ctypes.CDLL(cfile_name + '.dll')
c_fn = get_cuda_fn(mydll)
c_fn.argtypes =  func_params (an array of C-converted inputs you need)
c_fn( *[params] )

et là vous avez un wrapper Python pour un script C sans avoir à modifier dix choses différentes à chaque fois que quelque chose change. 

0
Chant

En interne, ctypes utilise les fonctions fournies par la bibliothèque de liens dynamiques (dlopen/dlsym sous unix, LoadLibrary/GetProcAddress sous windows) pour charger la bibliothèque et trouver l’adresse de la fonction spécifiée par le nom de la fonction; puis utilisez la bibliothèque cffi pour passer le paramètre de manière dynamique.

Le problème est que la bibliothèque de liens dynamiques dont dépend ctypes n'inclut pas la fonction permettant de répertorier le symbole de la bibliothèque partagée. C'est pourquoi vous ne pouvez pas répertorier symbole par ctypes.

Pour ce faire, vous devez utiliser des outils spécifiques pour dump le fichier elf (readelf sous unix) et le fichier pe pour dll (dumpbin sous windows).

0
Sam Liao