que - punteros c++
¿Cómo obtener el nombre de la función del puntero de la función en C? (11)
Usa
kallsyms_lookup_name()
para encontrar la dirección dekallsyms_lookup
.Use un puntero de función que apunta a
kallsyms_lookup
, para llamarlo.
¿Cómo obtener el nombre de la función del puntero de la función en C?
Editar: El caso real es: estoy escribiendo un módulo de kernel de Linux y estoy llamando a las funciones del kernel. Algunas de estas funciones son punteros y deseo inspeccionar el código de esa función en la fuente del kernel. Pero no sé a qué función apunta. Pensé que podría hacerse porque, cuando el sistema falla (kernel panic), imprime en la pantalla la pila de llamadas actual con los nombres de las funciones. Pero, creo que estaba equivocado ... ¿verdad?
Consulte Visual Detector de fugas para ver cómo funcionan sus impresiones de llamada. Sin embargo, esto supone que estás usando Windows.
En el kernel de Linux, puede usar directamente el formato "% pF" de printk!
void *func = &foo;
printk("func: %pF at address: %p/n", func, func);
Eso no es directamente posible sin asistencia adicional.
Tú podrías:
mantener una tabla en los punteros a los nombres de la función de mapeo del programa
examina la tabla de símbolos del ejecutable, si tiene una.
El último, sin embargo, es difícil y no es portátil. El método dependerá del formato binario del sistema operativo (ELF, a.out, .exe, etc.) y también de cualquier reubicación realizada por el vinculador.
EDITAR: Como ahora has explicado cuál es tu caso de uso real, la respuesta no es tan difícil. La tabla de símbolos del kernel está disponible en /proc/kallsyms
, y hay una API para acceder a ella:
#include <linux/kallsyms.h>
const char *kallsyms_lookup(unsigned long addr, unsigned long *symbolsize,
unsigned long *ofset, char **modname, char *namebuf)
void print_symbol(const char *fmt, unsigned long addr)
Para fines simples de depuración, es probable que este último haga exactamente lo que necesita: toma la dirección, la formatea y la envía a printk
.
Lo siguiente me funciona en Linux:
- imprima la dirección de la función usando
%p
- A continuación, haz un
nm <program_path> | grep <address>
nm <program_path> | grep <address>
(sin el prefijo0x
) - Debería mostrarle el nombre de la función.
Funciona solo si la función en cuestión está en el mismo programa (no en una biblioteca vinculada dinámicamente o algo así).
Si puede encontrar las direcciones de carga de las bibliotecas compartidas cargadas, puede restar la dirección del número impreso y usar nm en la biblioteca para averiguar el nombre de la función.
Me sorprende que todos digan que no es posible. Es posible en Linux para funciones no estáticas.
Sé al menos dos formas de lograr esto.
Hay funciones de GNU para la impresión de traza inversa: backtrace()
y backtrace_symbols()
(Ver man
). En su caso, no necesita backtrace()
ya que tiene puntero de función, simplemente lo pasa a backtrace_symbols()
.
Ejemplo (código de trabajo):
#include <stdio.h>
#include <execinfo.h>
void foo(void) {
printf("foo/n");
}
int main(int argc, char *argv[]) {
void *funptr = &foo;
backtrace_symbols_fd(&funptr, 1, 1);
return 0;
}
Compilar con gcc test.c -rdynamic
Salida: ./a.out(foo+0x0)[0x8048634]
Le da nombre binario, nombre de función, desplazamiento del puntero desde el inicio de la función y el valor del puntero para que pueda analizarlo.
Otra forma es usar dladdr()
(otra extensión), supongo que print_backtrace()
usa dladdr()
. dladdr()
devuelve la estructura Dl_info
que tiene el nombre de la función en el campo dli_sname
. No proporciono el ejemplo de código aquí, pero es obvio: consulte el man dladdr
de man dladdr
para más detalles.
¡NÓTESE BIEN! ¡Ambos enfoques requieren que la función no sea estática!
Bueno, hay una forma más: usar información de depuración usando libdwarf
pero requeriría un binario sin libdwarf
y no es muy fácil de hacer, así que no lo recomiendo.
No hay forma de cómo hacerlo en general.
Si compila el código correspondiente en una biblioteca DLL / Shared, debería poder incluir todos los puntos de entrada y compararlos con el puntero que tiene. Todavía no lo he probado, pero tengo algo de experiencia con DLL / Shared Libs y espero que funcione. Esto incluso podría implementarse para trabajar en forma cruzada.
Alguien más mencionó ya que compilar con símbolos de depuración, entonces podrías tratar de encontrar una manera de analizarlos desde la aplicación en ejecución, de forma similar a lo que haría un depurador. Pero esto es absolutamente patentado y no portátil.
No puedes. El nombre de la función no está asociado a la función para el momento en que se compila y vincula. Todo se basa en la dirección de memoria en ese punto, no en el nombre.
No sabrías cómo te ves sin un espejo reflector. Deberá usar un lenguaje con capacidad de reflexión como C #.
No se puede morir pero puedes implementar un enfoque diferente a este problema si quieres. Puede hacer que un puntero de estructura apunte a una función, así como una cadena descriptiva que puede establecer a lo que desee. También agregué una actitud de depuración ya que probablemente no quieres que estos vars sean printet para siempre.
// Define it like this
typedef struct
{
char *dec_text;
#ifdef _DEBUG_FUNC
void (*action)(char);
#endif
} func_Struct;
// Initialize it like this
func_Struct func[3]= {
#ifdef _DEBUG_FUNC
{"my_Set(char input)",&my_Set}};
{"my_Get(char input)",&my_Get}};
{"my_Clr(char input)",&my_Clr}};
#else
{&my_Set}};
{&my_Get}};
{&my_Clr}};
#endif
// And finally you can use it like this
func[0].action( 0x45 );
#ifdef _DEBUG_FUNC
printf("%s",func.dec_text);
#endif
Si la lista de funciones que se pueden señalar no es demasiado grande o si ya sospecha de un pequeño grupo de funciones, puede imprimir las direcciones y compararlas con la utilizada durante la ejecución. Ex:
typedef void (*simpleFP)();
typedef struct functionMETA {
simpleFP funcPtr;
char * funcName;
} functionMETA;
void f1() {/*do something*/}
void f2() {/*do something*/}
void f3() {/*do something*/}
int main()
{
void (*funPointer)() = f2; // you ignore this
funPointer(); // this is all you see
printf("f1 %p/n", f1);
printf("f2 %p/n", f2);
printf("f3 %p/n", f3);
printf("%p/n", funPointer);
// if you want to print the name
struct functionMETA arrFuncPtrs[3] = {{f1, "f1"}, {f2, "f2"} , {f3, "f3"}};
int i;
for(i=0; i<3; i++) {
if( funPointer == arrFuncPtrs[i].funcPtr )
printf("function name: %s/n", arrFuncPtrs[i].funcName);
}
}
Salida:
f1 0x40051b
f2 0x400521
f3 0x400527
0x400521
function name: f2
Este enfoque funcionará también para funciones estáticas.