I'm trying to understand GDB and LLDB so that I can efficiently used it to debug my Programs at any point.
But it seem that I'm stuck I'm not sure how to print the output of C library function like pow, strnlen etc. If I ever want to explore there output.
Following are by LLDB and GDB output.
3 int main(int argc,char *argv[]) {
4 int a = pow(3,2);
-> 5 printf("the value of a is %d",a);
6 return 0;
7 }
(lldb) print pow(3,1)
warning: could not load any Objective-C class information. This will significantly reduce the quality of type information available.
error: 'pow' has unknown return type; cast the call to its declared return type
(lldb) print strlen("abc")
warning: could not load any Objective-C class information. This will significantly reduce the quality of type information available.
error: 'strlen' has unknown return type; cast the call to its declared return type
(lldb) expr int a = strlen("abc");
error: 'strlen' has unknown return type; cast the call to its declared return type
(lldb) expr int a = strlen("abc");
GDB output
Starting program: /Users/noobie/workspaces/myWork/pow
[New Thread 0x1903 of process 35243]
warning: unhandled dyld version (15)
Thread 2 hit Breakpoint 1, main (argc=1, argv=0x7fff5fbffb10) at pow.c:5
5 int a = pow(3,2);
(gdb) print pow(3,2)
No symbol "pow" in current context.
(gdb) set pow(3,2)
No symbol "pow" in current context.
(gdb) set pow(3,2);
No symbol "pow" in current context.
(gdb) print pow(3,2);
No symbol "pow" in current context.
(gdb) call pow(3,2)
No symbol "pow" in current context.
(gdb)
I have compiled the program using gcc with -g3 flag
i.e
gcc -g3 pow.c -o pow
The error you are getting from lldb, e.g.:
error: 'strlen' has unknown return type; cast the call to its declared return type
is just what it says. You need to cast the call to the proper return type:
(lldb) print (size_t) strlen("abc")
(size_t) $0 = 3
The reason the type information is missing from strlen and printf etc. is that to save space, the compiler only writes the signatures of functions into the debug information when it sees the definition of the function, not at every use site. Since you don't have the debug information for the standard C libraries, you don't have this information.
The reason the debugger requires this information before it will call the function is that if you call a function that returns a structure, but generate code as though the function returned a scalar value, calling the function will corrupt the stack of the thread on which the function was called, ruining your debug session. So lldb doesn't guess about this.
Note, on macOS, the system has "module maps" for most of the system libraries, which allow lldb to reconstruct types from the modules. To tell lldb to load a module when debugging a pure C program, run this command:
(lldb) expr -l objective-c -- #import Darwin
If you are debugging an ObjC program, you can leave off the language specification. After this expression runs, lldb will have loaded the module map and you can call most of the functions in the standard C libraries without casting.
If you look at disassemble you'll see it just contains raw resulting value with no call to pow function. gcc knows what pow is and calculates it during compilation. There is no need to link with libm which contains implementation of given function => no function is present at runtime so debugger don't have anything to call.
You can force link via e.g. adding -lm (can be overridden with --as-needed linker flag, though).
Related
I have used the C code from the following verbatim: https://wiki.tcl-lang.org/page/Hello+World+as+a+C+extension
/*
* hello.c -- A minimal Tcl C extension.
*/
#include <tcl.h>
static int
Hello_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Tcl_SetObjResult(interp, Tcl_NewStringObj("Hello, World!", -1));
return TCL_OK;
}
/*
* Hello_Init -- Called when Tcl loads your extension.
*/
int DLLEXPORT
Hello_Init(Tcl_Interp *interp)
{
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
/* changed this to check for an error - GPS */
if (Tcl_PkgProvide(interp, "Hello", "1.0") == TCL_ERROR) {
return TCL_ERROR;
}
Tcl_CreateObjCommand(interp, "hello", Hello_Cmd, NULL, NULL);
return TCL_OK;
}
My command for compiling is nearly verbatim except for the last character, indicating Tcl version 8.6 rather than 8.4, and it compiles without error:
gcc -shared -o hello.dll -DUSE_TCL_STUBS -I$TCLINC -L$TCLLIB -ltclstub86
Then I created the following Tcl program:
load hello.dll Hello
puts "got here"
But when running it with tclsh get the following error:
cannot find symbol "Hello_Init"
while executing
"load ./hello.dll Hello"
(file "hello.tcl" line 1)
So I am essentially following a couple of suggestions from Donal Fellows answer here: cannot find symbol "Embeddedrcall_Init" The OP there however commented that, like me, the suggestion(s) hadn't resolved their issue. One thing that I didn't try from that answer was "You should have an exported (extern "C") function symbol in your library" -- could that be the difference maker? Shouldn't it have been in the example all along then?
At the suggestion of somebody on comp.lang.tcl I found "DLL Export Viewer" but when I run it against the DLL it reports 0 functions found :( What am I doing wrong?
Could it be an issue with MinGW/gcc on Windows, and I need to bite the bullet and do this with Visual Studio? That's overkill I'd like to avoid if possible.
The core of the problem is that your function Hello_Init is not ending up in the global symbol table exported by the resulting DLL. (Some linkers would put such things in as _Hello_Init instead of Hello_Init; Tcl adapts to them transparently.) The symbol must be there for Tcl's load command to work: without it, there's simply no consistent way to tell your extension code what the Tcl_Interp context handle is (which allows it to make commands, variables, etc.)
(If you'd been working with C++, one of the possible problem is a missing extern "C" whose actual meaning is to turn off name mangling. That's probably not the problem here.)
Since you are on Windows — going by the symbols in your DLL, such as EnterCriticalSection and GetLastError — the problem is probably linked to exactly how you are linking. I'm guessing that Tcl is defining your function to have __declspec(dllexport) (assuming you've not defined STATIC_BUILD, which absolutely should not be used when building a DLL) and yet that's not getting respected. Assuming you're using a modern-enough version of GCC… which you probably are.
I'm also going through the process of how to build tcl extensions in C and had exactly the same problem when working though this same example using tcl 8.6.
i.e. I was compiling using MinGW GCC (64-bit), and used the following:
gcc -shared -o hello.dll -DUSE_TCL_STUBS "-IC:\\ActiveTcl\\include" "-LC:\\ActiveTcl\\lib" -ltclstub86
And like the OP I got no compile error, but when loading the dll at a tclsh prompt tcl complained :
'cannot find symbol "Hello_Init"'
I can't say that I understand, but I was able to find a solution that works thanks to some trial and error, and some information on the tcl wiki here
https://wiki.tcl-lang.org/page/Building+Tcl+DLL%27s+for+Windows
In my case I had to adjust the compiler statement to the following
gcc -shared -o hello.dll hello.c "-IC:\\ActiveTcl\\include" "-LC:\\ActiveTcl\\bin" -ltcl86t
Obviously those file paths are specific to my system, but basically
I had to add an explicit reference to the .c file
I had to include the tcl86t dll library from the tcl bin directory
I had to remove the -DUSE_TCL_STUBS flag ( meaning that the references -LC:\\ActiveTcl\\lib and -ltclstub86 could also be removed)
(attempting to use the -DUSE_TCL_STUBS flag caused the compiler to complain with C:\ActiveTcl\lib/tclstub86.lib: error adding symbols: File format not recognized )
This successfully compiled a dll that I could load, and then call the hello function to print my 'Hello World' message.
Something else I stumbled over, and which wasn't immediately obvious:
reading https://www.tcl.tk/man/tcl8.6/TclCmd/load.htm, tcl epxects to find an 'init' function based on a certain naming convention.
if the C extension does not define a package name then the name of that init function will be derived from the dll filename.
This caused a few problems for me (when compiling via Eclipse IDE), as the dll name was being automatically determined from the eclipse projet name.
For example, if I recompile the same example, but call the .dll something else, eg.
gcc -shared -o helloWorldExenstion.dll hello.c "-IC:\\ActiveTcl\\include" "-LC:\\ActiveTcl\\bin" -ltcl86t
Then at tclsh prompt:
% load helloWorldExtension
cannot find symbol "Helloworldextension_Init"
I am trying to modify pthread_create. To be specific, in create_thread, I want to remove CLONE_FILES flag. I also have functions requires normal pthread_create. So I duplicate code of pthread_create and create_thread, rename them into pthread_create_no_clone_files and create_thread_no_clone_files. And in create_thread_no_clone_files, I removed CLONE_FILES flag. Then I compile them, get a new libpthread.a. The following is the output of nm libpthread.a | grep pthread_create
0000000000002190 W pthread_create
0000000000002190 T __pthread_create_2_1
00000000000026a0 T pthread_create_no_clone_files
U __pthread_create
U __pthread_create
So I have my pthread_create_no_clone_files here. But when I try to build my test program using g++ pthread_test.c -static libpthread.a -o pthread_test, I had the following link error
pthread_test.c:(.text+0x82): undefined reference to `pthread_create_no_clone_files(unsigned long*, pthread_attr_t const*, void* (*)(void*), void*)'
pthread_create_no_clone_files is forward declared in my program. I feel I need to declare my function pthread_create_no_clone_files somewhere in libpthread, but my knowledge tells me if I have the entrance in my static library, then I should be able to link it. What is wrong with my understanding?
Also I welcome other better methods for creating a pthread without CLONE_FILES flag. Thank you.
Your program is using C++ and you are trying to access a C function. Your forward declaration of this function has to be wrapped in an extern "C" block.
This, among other things, disables name mangling, so that the types of arguments do not appear in the actual symbol name. In fact, the argument types appearing in the error message from the linker is why I think this is the problem.
I'm trying to achieve something similar as in this quesition. I'm compiling a firmware file written in C, and the code needs to call a function in the bootloader.
My firmware file looks like this:
void callback(void);
int main(void){
__asm__("nop; ");
callback();
__asm__("nop; ");
return(0)
}
The firmware function compiles without error using gcc firmware.c but the function body only contains the two nop instruction with nothing in-between them (which makes sense, the function is undefined).
I made a script that runs the bootloader and prints out the address &callback, which i can use in the firmware to define a function pointer in my main():
void (*call_this)(void) = (void (*)(void )) 0x555555554abd;
call_this();
That makes the callback work, but I don't want to have to run the bootloader to compile the firmware.
I've tried fumbling around with linker scripts, but I'm new to those.
I tried supplying
PROVIDE(callback = 0x0000000000000969);
or
PROVIDE(callback = 0x555555554abd);
to the linker by compiling the firmware with:
gcc -Xlinker -T linkerscript firmware.c
The first address is from nm firmware.out | grep callback, the other from running the bootloader in gdb. Compiling with the linker script gives this error:
/usr/bin/ld: firmware.out: Not enough room for program headers, try linking with -N
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
After some more reading, I think I should to use the -R flag of ld to accomplish this.
Read symbol names and their addresses from filename, but do not relocate it or include it in the output. This allows your output file to refer symbolically to absolute locations of memory defined in other programs. You may use this option more than once.
Just haven't made it work quite right yet.
Use the --no-dynamic-linker linking option, as done by U-Boot to solve this issue. Note that if you invoke the linker trough gcc the option must be set using -Wl,--no-dynamic-linker.
I have errornously forgotten to put the parameter List after the call to a function, and the gcc did not intercept (because he believes it is a TRUTH-value). Is there a gcc warning/error switch, which helps me to locate those places? example:
short function(short arg);
main() {
if (function) { // I wanted to write function(arg)
//do something
}
}
The Version of the gcc I am using is 3.2.1.
Looking at the GCC man page, it seems that what you need is -Waddress.
-Waddress
Warn about suspicious uses of memory addresses. These include using the address of a function in a conditional
expression, such as "void func(void); if (func)", and comparisons against the memory address of a string literal, such as
"if (x == "abc")". Such uses typically indicate a programmer error: the address of a function always evaluates to true,
so their use in a conditional usually indicate that the programmer forgot the parentheses in a function call; and
comparisons against string literals result in unspecified behavior and are not portable in C, so they usually indicate
that the programmer intended to use "strcmp". This warning is enabled by -Wall.
As stated there, you can enable this flag with -Wall too.
Use "-Wall" option with gcc. This option force gcc to show all kinds of warnings at compilation.
You may get following warning when you compile your code by 'gcc -Wall' command.
`function' undeclared (first use in this function)
here is some C++ test code:
__attribute__((visibility("hidden"))) void foo()
{
int fd = fopen("data1", "rb");
printf ("%d", fd);
}
And all other code don't call function 'foo' and function 'fopen'
Then I use gcc option -ffunction-sections to compile the code to a so file.
As I think, the function foo symbol and foo binary code has't inlcuded in the so file.
But The problem is, I think the symbol 'fopen' should not be symbol table.
ps:I can make sure that only function 'foo' has use 'fopen'.
And it actually is not, when I use command nm, I found 'U' type symbol of 'fopen'.
How is the gcc work?
And has gcc other compile option to found that, symbol 'fopen' is not use, and remove 'fopen' symbol.
The problem is, that the compiler does not know, wheter the symbols are used later.
You can tell at compile time that you gave him the whole program, so that if your program isnt calling the function, nobody would.
The compiling option is -fwhole-program.