Using ellipsis in cuda device function - c

I am trying to port some C code to a cuda kernel. The code I am porting uses ellipsis prevalently. When I try to use an ellipsis in a device function like below, I get an error saying that ellipsis are not allowed in device functions.
__device__ int add(int a, ...){}
However, cuda supports using printf in both host and device functions and uses ellipsis in their own code as below in common_functions.h.
extern "C"
{
extern _CRTIMP __host__ __device__ __device_builtin__ __cudart_builtin__ int __cdecl printf(const char*, ...);
extern _CRTIMP __host__ __device__ __device_builtin__ __cudart_builtin__ int __cdecl fprintf(FILE*, const char*, ...);
extern _CRTIMP __host__ __device__ __cudart_builtin__ void* __cdecl malloc(size_t) __THROW;
extern _CRTIMP __host__ __device__ __cudart_builtin__ void __cdecl free(void*) __THROW;
}
Is there a way to use ellipsis in a device function?
I would not like to hard code a max number of parameters and then change all the calls.
I also would not like to code a custom variadic function method.
I also tried creating a PTX file that I could use to replace the ellipsis usage as the ISA PTX documentation appears to have facilities for handling variable parameters (Note that the documentation says it does not support them and then provides a paragraph with supporting functions and examples. Perhaps, there is a typo?). I got a simple PTX file all the way through the process defined below but got stuck on the executable question in the last comment. I plan to read the nvcc compiler document to try and understand that.
How can I call a ptx function from CUDA C?
I am using a GTX660 which I believe is level 3.0 and cuda 5.0 toolkit on Ubuntu 12.04.
Update regarding the "magic" referred to below:
It looks to me like there must be something special happening in the compiler to restrict ellipsis usage and do something special. When I call printf as below:
printf("The result = %i from adding %i numbers.", result, 2);
I was surprised to find this in the ptx:
.extern .func (.param .b32 func_retval0) vprintf
(
.param .b64 vprintf_param_0,
.param .b64 vprintf_param_1
)
and later
add.u64 %rd2, %SP, 0;
st.u32 [%SP+0], %r5;
mov.u32 %r6, 2;
st.u32 [%SP+4], %r6;
// Callseq Start 1
{
.reg .b32 temp_param_reg;
.param .b64 param0;
st.param.b64 [param0+0], %rd1;
.param .b64 param1;
st.param.b64 [param1+0], %rd2;
.param .b32 retval0;
call.uni (retval0),
vprintf,
(
param0,
param1
);
It appears to me that the compiler accepts ellipsis for printf but then swaps a call to vprintf and creates a va_list on the fly manually. va_list is a valid type in device functions.

As #JaredHoberock stated (I think he will not mind if I create an answer):
__device__ functions cannot have ellipsis parameters; that is why you are receiving the compiler error message.
The built-in printf function is a special case, and does not indicate general support for ellipsis.
There are some alternatives that could be mentioned, but none that I am aware of allow truly general variable arguments support. For example, as Jared stated you could simply define a number of parameters, some/most of which have default values specified, so they do not need to be passed explicitly.
You could also play games with templating as is done in the cuPrintf sample code to try and simulate variable arguments, but this will also not be arbitrarily extensible, I don't think.

Related

Figure out function parameter count at compile time

I have a C library (with C headers) which exists in two different versions.
One of them has a function that looks like this:
int test(char * a, char * b, char * c, bool d, int e);
And the other version looks like this:
int test(char * a, char * b, char * c, bool d)
(for which e is not given as function parameter but it's hard-coded in the function itself).
The library or its headers do not define / include any way to check for the library version so I can't just use an #if or #ifdef to check for a version number.
Is there any way I can write a C program that can be compiled with both versions of this library, depending on which one is installed when the program is compiled? That way contributors that want to compile my program are free to use either version of the library and the tool would be able to be compiled with either.
So, to clarify, I'm looking for something like this (or similar):
#if HAS_ARGUMENT_COUNT(test, 5)
test("a", "b", "c", true, 20);
#elif HAS_ARGUMENT_COUNT(test, 4)
test("a", "b", "c", true);
#else
#error "wrong argument count"
#endif
Is there any way to do that in C? I was unable to figure out a way.
The library would be libogc ( https://github.com/devkitPro/libogc ) which changed its definition of if_config a while ago, and I'd like to make my program work with both the old and the new version. I was unable to find any version identifier in the library. At the moment I'm using a modified version of GCC 8.3.
This should be done at the configure stage, using an Autoconf (or CMake, or whatever) test step -- basically, attempting to compile a small program which uses the five-parameter signature, and seeing if it compiles successfully -- to determine which version of the library is in use. That can be used to set a preprocessor macro which you can use in an #if block in your code.
I think there's no way to do this at the preprocesing stage (at least not without some external scripts). On the other hand, there is a way to detect a function's signature at compiling time if you're using C11: _Generic. But remember: you can't use this in a macro like #if because primary expressions aren't evaluated at the preprocessing stage, so you can't dynamically choose to call the function with signature 1 or 2 in that stage.
#define WEIRD_LIB_FUNC_TYPE(T) _Generic(&(T), \
int (*)(char *, char *, char *, bool, int): 1, \
int (*)(char *, char *, char *, bool): 2, \
default: 0)
printf("test's signature: %d\n", WEIRD_LIB_FUNC_TYPE(test));
// will print 1 if 'test' expects the extra argument, or 2 otherwise
I'm sorry if this does not answer your question. If you really can't detect the version from the "stock" library header file, there are workarounds where you can #ifdef something that's only present in a specific version of that library.
This is just a horrible library design.
Update: after reading the comments, I should clarify for future readers that it isn't possible in the preprocessing stage but it is possible at compile time still. You'd just have to conditionally cast the function call based on my snippet above.
typedef int (*TYPE_A)(char *, char *, char *, bool, int);
typedef int (*TYPE_B)(char *, char *, char *, bool);
int newtest(char *a, char *b, char *c, bool d, int e) {
void (*func)(void) = (void (*)(void))&test;
if (_Generic(&test, TYPE_A: 1, TYPE_B: 2, default: 0) == 1) {
return ((TYPE_A)func)(a, b, c, d, e);
}
return ((TYPE_B)func)(a, b, c, d);
}
This indeed works although it might be controversial to cast a function this way. The upside is, as #pizzapants184 said, the condition will be optimized away because the _Generic call will be evaluated at compile-time.
I don't see any way to do that with standard C, if you are compiling with gcc a very very ugly way can be using gcc aux-info in a command and passing the number of parameters with -D:
#!/bin/sh
gcc -aux-info output.info demo.c
COUNT=`grep "extern int foo" output.info | tr -dc "," | wc -m`
rm output.info
gcc -o demo demo.c -DCOUNT="$COUNT + 1"
./demo
This snippet
#include <stdio.h>
int foo(int a, int b, int c);
#ifndef COUNT
#define COUNT 0
#endif
int main(void)
{
printf("foo has %d parameters\n", COUNT);
return 0;
}
outputs
foo has 3 parameters
Attempting to support compiling code with multiple versions of a static library serves no useful purpose. Update your code to use the latest release and stop making life more difficult than it needs to be.
In Dennis Ritchie's original C language, a function could be passed any number of arguments, regardless of the number of parameters it expected, provided that the function didn't access any parameters beyond those that were passed to it. Even on platforms whose normal calling convention wouldn't be able to accommodate this flexibility, C compilers would generally used a different calling convention that could support it unless functions were marked with qualifiers like pascal to indicate that they should use the ordinary calling convention.
Thus, something like the following would have had fully defined behavior in Ritchie's original C language:
int addTwoOrThree(count, x, y, z)
int count, x, y, z;
{
if (count == 3)
return x+y+z;
else
return x+y;
}
int test()
{
return count(2, 10,20) + count(3, 1,2,3);
}
Because there are some platforms where it would be impractical to support such flexibility by default, the C Standard does not require that compilers meaningfully process any calls to functions which have more or fewer arguments than expected, except that functions which have been declared with a ... parameter will "expect" any number of arguments that is at least as large as the number of actual specified parameters. It is thus rare for code to be written that would exploit the flexibility that was present in Ritchie's language. Nonetheless, many implementations will still accept code written to support that pattern if the function being called is in a separate compilation unit from the callers, and it is declared but not prototyped within the compilation units that call it.
you don't.
the tools you're working with are statically linked and don't support versioning.
you can get around it using all kind of tricks and tips that have been mentioned, but at the end of the day they are ugly patch works of something you're trying to do that makes no sense in this context(toolkit/code environment).
you design your code for the version of the toolkit you have installed. its a hard requirement. i also don't understand why you would want to design your gamecube/wii code to allow building on different versions.
the toolkit is constantly changing to fix bugs, assumptions etc etc.
if you want your code to use an old version that potentially have bugs or do things wrong, that is on you.
i think you should realize what kind of botch work you're dealing with here if you need or want to do this with an constantly evolving toolkit..
I also think, but this is because i know you and your relationship with DevKitPro, i assume you ask this because you have an older version installed and your CI builds won't work because they use a newer version (from docker). its either this, or you have multiple versions installed on your machine for a different project you build (but won't update source for some odd reason).
If your compiler is a recent GCC, e.g. some GCC 10 in November 2020, you might write your own GCC plugin to check the signature in your header files (and emit appropriate and related C preprocessor #define-s and/or #ifdef, à la GNU autoconf). Your plugin could (for example) fill some sqlite database and you would later generate some #include-d header file.
You then would set up your build automation (e.g. your Makefile) to use that GCC plugin and the data it has computed when needed.
For a single function, such an approach is overkill.
For some large project, it could make sense, in particular if you also decide to also code some project-specific coding rules validator in your GCC plugin.
Writing a GCC plugin could take weeks of your time, and you may need to patch your plugin source code when you would switch to a future GCC 11.
See also this draft report and the European CHARIOT and DECODER projects (funding the work described in that report).
BTW, you might ask the authors of that library to add some versioning metadata. Inspiration might come from libonion or Glib or libgccjit.
BTW, as rightly commented in this issue, you should not use an unmaintained old version of some opensource library. Use the one that is worked on.
I'd like to make my program work with both the old and the new version.
Why?
making your program work with the old (unmaintained) version of libogc is adding burden to both you and them. I don't understand why you would depend upon some old unmaintained library, if you can avoid doing that.
PS. You could of course write a plugin for GCC 8. I do recommend switching to GCC 10: it did improve.
I'm not sure this solves your specific problem, or helps you at all, but here's a preprocessor contraption, due to Laurent Deniau, that counts the number of arguments passed to a function at compile time.
Meaning, something like args_count(a,b,c) evaluates (at compile time) to the constant literal constant 3, and something like args_count(__VA_ARGS__) (within a variadic macro) evaluates (at compile time) to the number of arguments passed to the macro.
This allows you, for instance, to call variadic functions without specifying the number of arguments, because the preprocessor does it for you.
So, if you have a variadic function
void function_backend(int N, ...){
// do stuff
}
where you (typically) HAVE to pass the number of arguments N, you can automate that process by writing a "frontend" variadic macro
#define function_frontend(...) function_backend(args_count(__VA_ARGS__), __VA_ARGS__)
And now you call function_frontend() with as many arguments as you want:
I made you Youtube tutorial about this.
#include <stdint.h>
#include <stdarg.h>
#include <stdio.h>
#define m_args_idim__get_arg100( \
arg00,arg01,arg02,arg03,arg04,arg05,arg06,arg07,arg08,arg09,arg0a,arg0b,arg0c,arg0d,arg0e,arg0f, \
arg10,arg11,arg12,arg13,arg14,arg15,arg16,arg17,arg18,arg19,arg1a,arg1b,arg1c,arg1d,arg1e,arg1f, \
arg20,arg21,arg22,arg23,arg24,arg25,arg26,arg27,arg28,arg29,arg2a,arg2b,arg2c,arg2d,arg2e,arg2f, \
arg30,arg31,arg32,arg33,arg34,arg35,arg36,arg37,arg38,arg39,arg3a,arg3b,arg3c,arg3d,arg3e,arg3f, \
arg40,arg41,arg42,arg43,arg44,arg45,arg46,arg47,arg48,arg49,arg4a,arg4b,arg4c,arg4d,arg4e,arg4f, \
arg50,arg51,arg52,arg53,arg54,arg55,arg56,arg57,arg58,arg59,arg5a,arg5b,arg5c,arg5d,arg5e,arg5f, \
arg60,arg61,arg62,arg63,arg64,arg65,arg66,arg67,arg68,arg69,arg6a,arg6b,arg6c,arg6d,arg6e,arg6f, \
arg70,arg71,arg72,arg73,arg74,arg75,arg76,arg77,arg78,arg79,arg7a,arg7b,arg7c,arg7d,arg7e,arg7f, \
arg80,arg81,arg82,arg83,arg84,arg85,arg86,arg87,arg88,arg89,arg8a,arg8b,arg8c,arg8d,arg8e,arg8f, \
arg90,arg91,arg92,arg93,arg94,arg95,arg96,arg97,arg98,arg99,arg9a,arg9b,arg9c,arg9d,arg9e,arg9f, \
arga0,arga1,arga2,arga3,arga4,arga5,arga6,arga7,arga8,arga9,argaa,argab,argac,argad,argae,argaf, \
argb0,argb1,argb2,argb3,argb4,argb5,argb6,argb7,argb8,argb9,argba,argbb,argbc,argbd,argbe,argbf, \
argc0,argc1,argc2,argc3,argc4,argc5,argc6,argc7,argc8,argc9,argca,argcb,argcc,argcd,argce,argcf, \
argd0,argd1,argd2,argd3,argd4,argd5,argd6,argd7,argd8,argd9,argda,argdb,argdc,argdd,argde,argdf, \
arge0,arge1,arge2,arge3,arge4,arge5,arge6,arge7,arge8,arge9,argea,argeb,argec,arged,argee,argef, \
argf0,argf1,argf2,argf3,argf4,argf5,argf6,argf7,argf8,argf9,argfa,argfb,argfc,argfd,argfe,argff, \
arg100, ...) arg100
#define m_args_idim(...) m_args_idim__get_arg100(, ##__VA_ARGS__, \
0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6,0xf5,0xf4,0xf3,0xf2,0xf1,0xf0, \
0xef,0xee,0xed,0xec,0xeb,0xea,0xe9,0xe8,0xe7,0xe6,0xe5,0xe4,0xe3,0xe2,0xe1,0xe0, \
0xdf,0xde,0xdd,0xdc,0xdb,0xda,0xd9,0xd8,0xd7,0xd6,0xd5,0xd4,0xd3,0xd2,0xd1,0xd0, \
0xcf,0xce,0xcd,0xcc,0xcb,0xca,0xc9,0xc8,0xc7,0xc6,0xc5,0xc4,0xc3,0xc2,0xc1,0xc0, \
0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8,0xb7,0xb6,0xb5,0xb4,0xb3,0xb2,0xb1,0xb0, \
0xaf,0xae,0xad,0xac,0xab,0xaa,0xa9,0xa8,0xa7,0xa6,0xa5,0xa4,0xa3,0xa2,0xa1,0xa0, \
0x9f,0x9e,0x9d,0x9c,0x9b,0x9a,0x99,0x98,0x97,0x96,0x95,0x94,0x93,0x92,0x91,0x90, \
0x8f,0x8e,0x8d,0x8c,0x8b,0x8a,0x89,0x88,0x87,0x86,0x85,0x84,0x83,0x82,0x81,0x80, \
0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,0x77,0x76,0x75,0x74,0x73,0x72,0x71,0x70, \
0x6f,0x6e,0x6d,0x6c,0x6b,0x6a,0x69,0x68,0x67,0x66,0x65,0x64,0x63,0x62,0x61,0x60, \
0x5f,0x5e,0x5d,0x5c,0x5b,0x5a,0x59,0x58,0x57,0x56,0x55,0x54,0x53,0x52,0x51,0x50, \
0x4f,0x4e,0x4d,0x4c,0x4b,0x4a,0x49,0x48,0x47,0x46,0x45,0x44,0x43,0x42,0x41,0x40, \
0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, \
0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, \
0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, \
0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, \
)
typedef struct{
int32_t x0,x1;
}ivec2;
int32_t max0__ivec2(int32_t nelems, ...){ // The largest component 0 in a list of 2D integer vectors
int32_t max = ~(1ll<<31) + 1; // Assuming two's complement
va_list args;
va_start(args, nelems);
for(int i=0; i<nelems; ++i){
ivec2 a = va_arg(args, ivec2);
max = max > a.x0 ? max : a.x0;
}
va_end(args);
return max;
}
#define max0_ivec2(...) max0__ivec2(m_args_idim(__VA_ARGS__), __VA_ARGS__)
int main(){
int32_t max = max0_ivec2(((ivec2){0,1}), ((ivec2){2,3}, ((ivec2){4,5}), ((ivec2){6,7})));
printf("%d\n", max);
}

use gcc compile a project that shows "undefined reference to `abort'"

I wrote a printf myselef that use va_list/va_arg/va_start/va_end/va_arg.
typedef char *va_list;
#define _AUPBND (sizeof (acpi_native_int) - 1)
#define _ADNBND (sizeof (acpi_native_int) - 1)
#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd)))
#define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
#define va_end(ap) (void) 0
#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))
At first,I copy these macros from linux kernel and the printf can print 32-bit integer correct but cannot print 64-bit integer and print double/float may fail or collapse.Then I check the code and I guess the va_* may have errors,so I use __builtin_va_* instead of kernel's va_*.
typedef __builtin_va_list va_list;
#define va_start(v,l) __builtin_va_start(v,l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v,l) __builtin_va_arg(v,l)
But gcc prompt "undefined reference to `abort'",so I write a empty abort() and myprintf works corretly.
My questions are:
Why linux kernel's va_list/va_arg/va_start/va_end/va_arg can not used for printf 64-bit integer and double/float?
When I used __builtin_va_start/__builtin_va_arg/__builtin_va_end/__builtin_va_list, why gcc prompt "undefined reference to abort'"? But I can not find the definition of__builtin_va_*`, where're their definition?
Don't cut and paste things from the Linux headers. Instead, put this at the top of your source file:
#include <stdarg.h>
This will give you everything you need in order to use va_list and va_arg. However, it won't pull in printf or any of the standard I/O stuff (which lives in <stdio.h>).
gcc's __builtin_va_arg() apparently will call abort() (at least on some platforms or situations) if it's invoked with a type argument cannot have been passed in the ... part of the argument list for a function call.
For example, due to promotions a char or float passed as such an argument will have been promoted to int or double. Accessing those arguments as va_arg(ap,char) or va_arg(ap,float) is undefined behavior and gcc may call abort() in that situation - or it may do something else (my MinGW compiler will execute an invalid instruction to cause a crash).
You might see something like this when compiled:
In file included from D:\temp\test.c:2:0:
D:\temp\test.c: In function 'foo':
D:\temp\test.c:12:16: warning: 'char' is promoted to 'int' when passed through '...' [enabled by default]
c = va_arg(ap,char);
^
D:\temp\test.c:12:16: note: (so you should pass 'int' not 'char' to 'va_arg')
D:\temp\test.c:12:16: note: if this code is reached, the program will abort
The 'definition' of __builtin_va_* is compiled into the compiler (that's why 'builtin' is part of the name).
As far as the Linux macros for varargs access: while the definitions you took from a linux kernel header do exist in include/acpi/platform/acenv.h, if you look carefully at the conditional compilation in effect, you'll see that those macros aren't used when building the linux kernel. I'm not exactly sure when those macros are in effect, but they won't work with x64/x86-64/amd64 builds because the ABI on that platform isn't entirely stack-based. See section 3.5.6 of the "System V Application Binary Interface - AMD64 Architecture Processor Supplement" for details.

How to EXPORT_SYMBOL uniquely with the function's arguments?

As we all know when using EXPORT_SYMBOL("function name") we get into the symbol list in System.map the function name as symbol.
c041bc90 b packet_sklist
c041bc94 b packet_sklist_lock
c041bc94 b packet_socks_nr
c041bc98 A __bss_stop
c041bc98 A _end
c041c000 A pg0
ffffe400 A __kernel_vsyscall
My question is: is there any compile option, hacking, macro or anything in the world enables you to include also the arguments of the function ?
i.e
c041bc90 b packet_sklist (list of arguments...)
two reasons for these:
you can export do_something(int a) and export do_something(int a,int b) .
you won't have bugs when using extern functions in kernel modules
which have mismatch in the arguments.
The no 1 reason you've shown, even if EXPORT_SYMBOL supports argument, it won't support variable argument, cause Linux uses C.

How to compile glibc for use without an operating system

I would like to compile the functions of glibc to an object file which will then be linked to a program which I am running on a computer without any operating system. Some functions, such as open, I want to just fail with ENOSYS. Other functions I will write myself, such as putchar, and then have glibc use those functions in it's own (like printf). I also want to use functions that don't need a file system or process management system or anything like that, such as strlen. How can I do this?
Most C libraries rely on the kernel heavily, so it's not reasonable to port 'em. But since most of it doesn't need to be implemented, you can get away easily with a few prototypes for stubs and gcc builtins.
You can implement stubs easily using weak symbols:
#define STUB __attribute__((weak, alias("__stub"))) int
#define STUB_PTR __attribute__((weak, alias("__stub0"))) void *
int __stub();
void *__stub0();
Then defining the prototypes becomes trivial:
STUB read(int, void*, int);
STUB printf(const char *, ...);
STUB_PTR mmap(void*, int, int, int, int, int);
And the actual functions could be:
int __stub()
{
errno = ENOSYS;
return -1;
}
void *__stub0()
{
errno = ENOSYS;
return NULL;
}
If you need some non-trivial function, like printf, take it from uClibc instead of glibc (or some other smaller implementation).

How to get function's name from function's pointer in Linux kernel?

How to get function's name from function's pointer in C?
Edit: The real case is: I'm writing a linux kernel module and I'm calling kernel functions. Some of these functions are pointers and I want to inspect the code of that function in the kernel source. But I don't know which function it is pointing to. I thought it could be done because, when the system fails (kernel panic) it prints out in the screen the current callstack with function's names. But, I guess I was wrong... am I?
I'm surprised why everybody says it is not possible. It is possible on Linux for non-static functions.
I know at least two ways to achieve this.
There are GNU functions for backtrace printing: backtrace() and backtrace_symbols() (See man). In your case you don't need backtrace() as you already have function pointer, you just pass it to backtrace_symbols().
Example (working code):
#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;
}
Compile with gcc test.c -rdynamic
Output: ./a.out(foo+0x0)[0x8048634]
It gives you binary name, function name, pointer offset from function start and pointer value so you can parse it.
Another way is to use dladdr() (another extension), I guess print_backtrace() uses dladdr(). dladdr() returns Dl_info structure that has function name in dli_sname field. I don't provide code example here but it is obvious - see man dladdr for details.
NB! Both approaches require function to be non-static!
Well, there is one more way - use debug information using libdwarf but it would require unstripped binary and not very easy to do so I don't recommend it.
That's not directly possible without additional assistance.
You could:
maintain a table in your program mapping function pointers to names
examine the executable's symbol table, if it has one.
The latter, however, is hard, and is not portable. The method will depend on the operating system's binary format (ELF, a.out, .exe, etc), and also on any relocation done by the linker.
EDIT: Since you've now explained what your real use case is, the answer is actually not that hard. The kernel symbol table is available in /proc/kallsyms, and there's an API for accessing it:
#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)
For simple debug purposes the latter will probably do exactly what you need - it takes the address, formats it, and sends it to printk, or you can use printk with the %pF format specifier.
In the Linux kernel, you can use directly "%pF" format of printk !
void *func = &foo;
printk("func: %pF at address: %p\n", func, func);
The following works me on Linux:
printf the address of the function using %p
Then do an nm <program_path> | grep <address> (without the 0x prefix)
It should show you the function name.
It works only if the function in question is in the same program (not in a dynamically linked library or something).
If you can find out the load addresses of the loaded shared libraries, you can subtract the address from the printed number, and use nm on the library to find out the function name.
You can't diectly but you can implement a different approach to this problem if you want. You can make a struct pointer instead pointing to a function as well as a descriptive string you can set to whatever you want.
I also added a debugging posebilety since you problably do not want these vars to be printet forever.
// 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
There is no way how to do it in general.
If you compile the corresponding code into a DLL/Shared Library, you should be able to enlist all entry points and compare with the pointer you've got. Haven't tried it yet, but I've got some experience with DLLs/Shared Libs and would expect it to work. This could even be implemented to work cross-plarform.
Someone else mentioned already to compile with debug symbols, then you could try to find a way to analyse these from the running application, similiar to what a debugger would do.
But this is absolutely proprietary and not portable.
If the list of functions that can be pointed to is not too big or if you already suspect of a small group of functions you can print the addresses and compare them to the one used during execution. 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);
}
}
Output:
f1 0x40051b
f2 0x400521
f3 0x400527
0x400521
function name: f2
This approach will work for static functions too.
Use kallsyms_lookup_name() to find the address of kallsyms_lookup.
Use a function pointer that points to kallsyms_lookup, to call it.
Check out Visual Leak Detector to see how they get their callstack printing working. This assumes you are using Windows, though.
Alnitak's answer is very helpful to me when I was looking for a workaround to print out function's name in kernel module. But there is one thing I want to supplyment, which is that you might want to use %pS instead of %pF to print function's name, becasue %pF not works anymore at some newer verions of kernel, for example 5.10.x.
Not exactly what the question is asking for but after reading the answers here
I though of this solution to a similar problem of mine:
/**
* search methods */
static int starts(const char *str, const char *c);
static int fuzzy(const char *str, const char *c);
int (*search_method)(const char *, const char *);
/* asign the search_method and do other stuff */
[...]
printf("The search method is %s\n", search_method == starts ? "starts" : "fuzzy")
If your program needs this a lot you could define the method names along with a string in an XMacro and use #define X(name, str) ... #undef X in the code to get the corresponding string from the function name.
You can't. The function name isn't attached to the function by the time it's compiled and linked. It's all by memory address at that point, not name.
You wouldn't know how you look like without a reflecting mirror. You'll have to use a reflection-capable language like C#.

Resources