I want to use a personal "pthread_self" function. I want to rewrite the "pthread_self()" and, at the final, call to the real "pthread_self".
is it possible in C/C++?
Example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
pthread_t pthread_self(void)
{
// Do something else.....
// ...
// And finally call to de real pthread_self():
return ::pthread_self(); // This doesn't work
}
main()
{
printf("\nThis is my main thread: %lu\n", pthread_self());
}
the code seems to be C89 without a return type for main. So I suggest you remove the :: operator infront of pthread_self() in the function pthread_self(void) and recompile.
Also call your pthread_self() by some other name such as pthread_self_2(void)
Will it be allowed to overload pthread_self() with a dummy variable (never used)?
pthread_t pthread_self( bool )
{
// Do something else.....
// ...
// And finally call to de real pthread_self():
printf( "%s\n", __PRETTY_FUNCTION__ );
return ::pthread_self(); // This doesn't work
}
int main()
{
printf( "%s\n", __PRETTY_FUNCTION__ );
pthread_self( false );
printf( "%s\n", __PRETTY_FUNCTION__ );
}
produces
$ g++ test.cpp -lpthread
$ ./a.out
int main()
pthread_t pthread_self(bool)
int main()
$
Two other approaches might be:
Write a function my_pthread_self(), use it everywhere, and have it call real pthread_self()
Have a macro PTHREAD_SELF which calls your wrapper which internally calls real pthread_self()
The following is a bit hacky but should work in C. Put the following in a header which you would have to include before or instead of <pthread.h> (but never after pthread.h):
pthread_t _pthread_self(void);
#define pthread_self _pthread_self
And in the corresponding .c file:
#include <pthread>
#include "wrapper.h"
#undef pthread_self // undo the hack locally
pthread_t _pthread_self(void)
{
// Do something else.....
// ...
// And finally call to the real pthread_self():
return pthread_self();
}
Now, when you write pthread_self in some other file than that .c file, it expands to your wrapper function. Within the .c file above, since this hack is not done, the call within the wrapper will call the library function.
This should give you some ideas. If you control the linking of your executable, you don't need to use LD_PRELOAD.
Thanks to all of you.
Based mainly on these two links Intercepting Arbitrary Functions on... and Tutorial: Function Interposition in Linux show by #Carl Norum and #Arkadyi, I show you a possible solution:
I have two source files and a Makefile:
mipthread_self.C:
#include <stdio.h>
#include <pthread.h>
#if defined (__STDC__) || defined (__cplusplus) || defined (c__plusplus)
#if defined (__cplusplus) || defined (c__plusplus)
extern "C" {
#endif
pthread_t __real_pthread_self();
pthread_t __wrap_pthread_self(void)
{
printf("This is mipthread_self %lu\n", __real_pthread_self());
return __real_pthread_self();
}
#if defined (__cplusplus) || defined (c__plusplus)
}
#endif
#endif
test.C:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
void* start_function(void* value)
{
printf("Thread start function is running for: %u\n", (unsigned int)pthread_self());
sleep(5);
pthread_exit(value);
}
int main()
{
int res;
pthread_t thread1, thread2;
void* threadReturnValue;
res = pthread_create(&thread1, NULL, start_function, (void*)"thread-one");
if (res != 0) {
perror("Creation of thread failed");
exit(EXIT_FAILURE);
}
printf("Thread1 created with id: %u\n", (unsigned int)thread1);
res = pthread_create(&thread2, NULL, start_function, (void*)"thread-two");
if (res != 0) {
perror("Creation of thread failed");
exit(EXIT_FAILURE);
}
printf("Thread2 created with id: %u\n", (unsigned int)thread2);
res = pthread_join(thread1, &threadReturnValue);
if (res != 0) {
perror("Joining of thread failed");
exit(EXIT_FAILURE);
}
printf("%s joined.\n", (char*)threadReturnValue);
res = pthread_join(thread2, &threadReturnValue);
if (res != 0) {
perror("Joining of thread failed");
exit(EXIT_FAILURE);
}
printf("%s joined.\n", (char*)threadReturnValue);
return 0;
}
And the Makefile:
BIN=test
CFLAGS=-g -m32 -fPIC -Wall $(DEFINES)
TIPO=-m32
PWD=`pwd`
DIR_OBJ=$(PWD)
DIR_BIN=$(DIR_OBJ)
INCLUDES=
LD_LIBRARIES=-L$(DIR_OBJ) -lmipthread -Xlinker --wrap -Xlinker pthread_self -lpthread -lstdc++
$(BIN): libmipthread.a
#echo ""
#echo "Se va a generar el binario $#"
#echo ""
gcc $(CFLAGS) test.C -o $(DIR_BIN)/$# $(LD_LIBRARIES)
libmipthread.a: mipthread_self.o
ar crv $(DIR_OBJ)/$# $(DIR_OBJ)/$<
mipthread_self.o: mipthread_self.C
gcc $(CFLAGS) -c ${PWD}/$< -o $(DIR_OBJ)/$# $(INCLUDES)
clean:
rm $(DIR_OBJ)/*.o
rm $(DIR_OBJ)/*.a
rm $(DIR_OBJ)/test
Related
I'm working with a device that provides conio.h, conio.c. In my c++ code, whenever I call getch(), I get these errors
/usr/bin/ld: CMakeFiles/hello.dir/main.cpp.o: undefined reference to symbol '_Z5getchv'
//usr/lib/libPhantomIOLib42.so: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
CMakeFiles/hello.dir/build.make:96: recipe for target 'hello' failed
make[2]: *** [hello] Error 1
CMakeFiles/Makefile2:82: recipe for target 'CMakeFiles/hello.dir/all' failed
make[1]: *** [CMakeFiles/hello.dir/all] Error 2
Makefile:90: recipe for target 'all' failed
make: *** [all] Error 2
I know conio is not standard but it seems the company addresses the OS issue by
#if defined(WIN32)
#include <windows.h>
#include <conio.h>
#else
#include "conio.h"
#include <string.h"
#endif
where conio.h is
#ifndef __CONIO_H_
#define __CONIO_H_
#ifdef _cplusplus
extern "C" {
#endif // _cplusplus
int _kbhit();
int getch();
#ifdef _cplusplus
}
#endif // _cplusplus
#endif // __CONIO_H
and conio.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
#include <termios.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
static struct termios term_attribs, term_attribs_old;
static void restore_term(void)
{
if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &term_attribs_old) < 0)
{
perror("tcsetattr: ");
exit(-1);
}
}
int _kbhit()
{
static int initialized;
fd_set rfds;
struct timeval tv;
int retcode;
if(!initialized)
{
if(tcgetattr(STDIN_FILENO, &term_attribs) < 0)
{
perror("tcgetattr: ");
exit(-1);
}
term_attribs_old = term_attribs;
if(atexit(restore_term))
{
perror("atexit: ");
exit(-1);
}
term_attribs.c_lflag &= ~(ECHO | ICANON | ISIG | IEXTEN);
term_attribs.c_iflag &= ~(IXON | BRKINT | INPCK | ICRNL | ISTRIP);
term_attribs.c_cflag &= ~(CSIZE | PARENB);
term_attribs.c_cflag |= CS8;
term_attribs.c_cc[VTIME] = 0;
term_attribs.c_cc[VMIN] = 0;
if(tcsetattr(STDIN_FILENO, TCSANOW, &term_attribs) < 0)
{
perror("tcsetattr: ");
exit(-1);
}
initialized = 1;
}
FD_ZERO(&rfds);
FD_SET(STDIN_FILENO, &rfds);
memset(&tv, 0, sizeof(tv));
retcode = select(1, &rfds, NULL, NULL, &tv);
if(retcode == -1 && errno == EINTR)
{
return 0;
}
else if(retcode < 0)
{
perror("select: ");
exit(-1);
}
else if(FD_ISSET(STDIN_FILENO, &rfds))
{
return retcode;
}
return 0;
}
int getch()
{
fd_set rfds;
int retcode;
FD_ZERO(&rfds);
FD_SET(STDIN_FILENO, &rfds);
retcode = select(1, &rfds, NULL, NULL, NULL);
if(retcode == -1 && errno == EINTR)
{
return 0;
}
else if(retcode < 0)
{
perror("select: ");
exit(-1);
}
return getchar();
}
My CMakeLists.txt is
cmake_minimum_required(VERSION 3.10)
project(project2 VERSION 0.1.0 LANGUAGES CXX)
set(CMAKE_CXX_FLAGS "-W -O2 -DNDEBUG -Dlinux")
add_executable(hello main.cpp conio.c conio.h)
target_link_libraries(hello HDU HD rt ncurses stdc++ m)
From the conio., I see _cplusplus which should address the c++ code. Why there an error and to fix it? My OS is ubuntu 18.04. One of the Makefiles provided by the company is
CXX=g++
CXXFLAGS+=-W -fexceptions -O2 -DNDEBUG -Dlinux -Iinclude
LIBS = -lHDU -lHD -lrt -lncurses -lstdc++ -lm
TARGET=ServoLoopDutyCycle
HDRS=include/StatsSampler.h
SRCS=src/ServoLoopDutyCycle.cpp \
src/StatsSampler.cpp \
src/conio.c
OBJS=$(patsubst %.cpp,%.o,$(patsubst %.c,%.o,$(SRCS)))
.PHONY: all
all: $(TARGET)
$(TARGET): $(SRCS)
$(CXX) $(CXXFLAGS) -o $# $(SRCS) $(LIBS)
.PHONY: clean
clean:
-rm -f $(OBJS) $(TARGET)
I'm trying to hook some ncurses functions but they don't have any effect.
ncurses isn't statically linked, so I don't see why it wouldn't work.
test.cpp
#include <cstdio>
#include <cstdlib>
#include <curses.h>
int main() {
initscr();
cbreak();
noecho();
getch();
endwin();
return 0;
}
Compiled with: gcc test.cpp -o test -std=c++11 -lncurses
hook.cpp
#include <dlfcn.h>
#include <cstdio>
#include <cstdlib>
int getch() {
typedef int getch ();
getch* old_getch = (getch*) dlsym(RTLD_NEXT, "getch");
int result = old_getch();
fprintf(stderr, "getch() = %i\n", result);
return result;
}
int noecho() {
typedef int noecho ();
noecho* old_noecho = (noecho*) dlsym(RTLD_NEXT, "noecho");
int result = old_noecho();
fprintf(stderr, "noecho() = %i\n", result);
return result;
}
int endwin() {
typedef int endwin ();
endwin* old_endwin = (endwin*) dlsym(RTLD_NEXT, "endwin");
int result = old_endwin();
printf("endwin called");
return result;
}
Compiled with: gcc hook.cpp -o hook.so -shared -ldl -fPIC -std=c++11
It sadly outputs nothing, and I'm completely stumped.
The specification doesn't state getch has to be a function (not a macro). Actually, in ncurses-6.1, getch defined as
#define getch() wgetch(stdscr)
Nonetheless, there is a getch function in libncurses (which simply calls wgetch(stdscr)), so dlsym(libncurses_handle,"getch") does work.
I am trying to dynamically load stat function using dlopen and dlsym.
Functions from stat family are wrapped in corresponding functions __xstat, __xstat64 itp.
Following sniped of code, compiles and works when compiled in 32bit mode (sys/stat.h is included to get stat structure for sake of example)
#include <iostream>
#include <dlfcn.h>
#include <sys/stat.h>
typedef int (*xstat_f) (int __ver, const char *__filename, struct stat *__stat_buf);
int main()
{
auto* h = dlopen("libc.so.6", RTLD_LAZY);
if(!h)
{
return 1; // invalid handle
}
auto f = (xstat_f)dlsym(h, "__xstat");
if(!f)
{
return 1; // invalid handle
}
struct stat s = {};
const auto r = f(3, "/tmp", &s);
if (r != 0)
{
perror("stat");
return errno;
}
return 0;
}
g++ main.cpp -o main -ldl -m32
Executable compiled without -m32 switch on 64bit machine returns EINVAL (Invalid argument).
What is the reason?
Also I've made a minimal test
#include <iostream>
#include <sys/stat.h>
int main(){
struct stat s;
const auto x = stat("/tmp", &s);
if(x != 0) return errno;
return 0;
}
and using objdump -T, on both executables, 32bits and 64bits, shows that stat is resolved as __xstat, so I am using correct symbol. Also I've tried combination of __xstat/__xstat64, struct stat/stat64, same result.
__xstat declarations follows:
int __xstat(int ver, const char *path, (struct stat *stat_buf))
in documentation parameter ver is described like, ver shall be 3 or the behavior of these functions is undefined, which is not entirely true, because in source code, definition of _STAT_VER_LINUX follows:
#ifndef __x86_64__
# define _STAT_VER_LINUX 3
#else
# define _STAT_VER_LINUX 1
#endif
That's why __xstat call on 64bits was failling, parameter ver should have been set to 1, and 3 on 32bits compilation.
I have following code which use dlopen and dlsym.
main.cpp
#include <stdio.h>
#include <dlfcn.h>
int main(int argc,char** argv) {
void* handler;
handler = dlopen("./libsql.so",RTLD_LAZY);
if(handler){
int (*insert)(const char*);
char* error=NULL;
dlerror(); /* Clear any existing error */
*(void **) (&insert) = dlsym(handler, "openAndInsert");
if ((error = dlerror()) == NULL) {
(*insert)(argv[1]);
}
else {
printf("Error in dlsym\n");
}
}
else {
printf("dlopen error\n");
}
return 0;
}
Compile command:g++ main.cpp -ldl
libsql.cpp
#include <sqlite3.h>
#include <string.h>
#include <stdio.h>
#include "libsql.h"
int openAndInsert(const char* sql) {
sqlite3 *db;
sqlite3_stmt *stmt;
sqlite3_initialize();
int rc = sqlite3_open("./database.db", &db);
if(rc==0){
rc = sqlite3_prepare(db, sql, strlen(sql), &stmt, NULL);
if(rc==0) {
if(sqlite3_step(stmt)){
printf("Done\n");
}
else {
printf("execute error\n");
}
sqlite3_finalize(stmt);
}
else {
printf("prepare error\n");
}
sqlite3_close(db);
}
else {
printf("open error\n");
}
sqlite3_shutdown();
}
libsql.h
#ifndef LIBSQL_H_
#define LIBSQL_H_
#ifdef __cplusplus
extern "C" {
#endif
int openAndInsert(const char* sql);
#ifdef __cplusplus
}
#endif
#endif
compile command:g++ -fPIC -shared -o libsql.so libsql.cpp
Now when I run application I get error as below.
./a.out: symbol lookup error: ./libsql.so: undefined symbol: sqlite3_initialize
But libsqlite3 already installed and works fine with other programm.
When I used below command to generate my *.so file Its works fine.
g++ -fPIC -shared -o libsql.so libsql.cpp -lsqlite3
I have a small C++ program that pings other machines on a network and send status information out over another network. The program runs as a daemon, so the startup process forks off a child and then calls exit. This program is cross-compiled to run on two different architectures: x86 and ARM. The GCC versions are 4.4 and 3.5 respectively. I can compile and run the program on x86 and it works flawlessly. However, when I run the program on the ARM, it hangs any time I call exit, not just after the fork. I have no functions registered with atexit or on_exit. The following are my includes:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#include <set>
#include <vector>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include "telnet_client.h"
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <netdb.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <syslog.h>
#include <customlib1.h>
#include <customlib2.h>
The following are my GCC commands:
arm-none-linux-gnueabi-g++ -Wall -DBUILDSTAMP="\"`date '+%F %T'`\"" -g -ggdb -O0 -I/usr/local/arm/arm-2007q1/arm-none-linux-gnueabi/libc/usr/include -DEMBEST_ARM -I/usr/local/share/arm/boost/src -I../include/ -I../include_rms -c can_wifid.cpp -o can_wifid.o
arm-none-linux-gnueabi-g++ -Wall -DBUILDSTAMP="\"`date '+%F %T'`\"" -g -ggdb -O0 -I/usr/local/arm/arm-2007q1/arm-none-linux-gnueabi/libc/usr/include -DEMBEST_ARM -I/usr/local/share/arm/boost/src -I../include/ -I../include_rms -c telnet_client.cpp -o telnet_client.o
arm-none-linux-gnueabi-g++ -Wall -DBUILDSTAMP="\"`date '+%F %T'`\"" -g -ggdb -O0 -I/usr/local/arm/arm-2007q1/arm-none-linux-gnueabi/libc/usr/include -DEMBEST_ARM -I/usr/local/share/arm/boost/src can_wifid.o telnet_client.o -L/usr/local/arm/arm-2007q1/arm-none-linux-gnueabi/libc/usr/lib -L../lib_embest_arm -L../lib_rms_embest_arm -Wl,-Bdynamic -lutilities -lboost_system -lboost_thread -lcanprovider -lembestcan -o can_wifid
Even just parsing my command line parameters with getopt then calling exit after a version message causes this problem (simplest case in my program). Has anybody ever experienced anything like this where exit just hangs ?
EDIT: Added code for the first part of the main function:
struct canwifid_options
{
public:
bool daemon_mode;
int verbosity;
canwifid_options()
{
this->daemon_mode = false;
this->verbosity = LOG_NOTICE;
}
};
static canwifid_options options;
int main(int argc, char * argv[])
{
int LoggingOptions = LOG_CONS|LOG_NDELAY|LOG_PID;
pid_t Pid;
ParseCommandLine(argc, argv);
if (!options.daemon_mode)
{
LoggingOptions |= LOG_PERROR;
}
openlog("can_wifid", LoggingOptions, LOG_USER);
setlogmask(LOG_UPTO(options.verbosity));
if (options.daemon_mode)
{
Pid = fork();
if (Pid < 0)
{
// couldn't fork off and create a child process
// log it, %m is a special syslog flag
syslog(LOG_CRIT, "Unable to create daemon [Error: %m]");
exit(ESRCH);
}
else if (Pid > 0)
{
// we're the parent, so we're done and out of here
exit(EXIT_SUCCESS);
}
else
{
// we're the child, take control of the session.
setsid();
// change to the root directory so we don't retain unnecessary control
// of any mounted volumes
chdir("/");
// clear our file mode creation mask
umask(0000);
}
}
else
{
// get our process ID
Pid = getpid();
}
syslog(LOG_INFO, "Running as %s", options.daemon_mode ? "daemon" : "standalone");
// Network code here, snipped for clarity
}
And there ParseCommandLine function:
static void ParseCommandLine(int argc, char *argv[])
{
int c;
while ((c = getopt(argc, argv, "dhqvDV?")) > 0)
{
switch (c)
{
case 'd':
options.daemon_mode = true;
break;
case 'V':
VersionMessage(argv);
exit(EXIT_SUCCESS);
break;
case 'q':
options.verbosity = LOG_WARNING;
break;
case 'v':
options.verbosity = LOG_INFO;
break;
case 'D':
options.verbosity = LOG_DEBUG;
break;
case 'h':
case '?':
default:
HelpMessage(argv);
exit(EXIT_SUCCESS);
break;
}
}
return; //done
}
An issue I ran into once is that calling exit attempts to exit and calls global destructors WITHOUT trying to unwind the stack or call any destructors for local objects on the stack. This can easily manifest if you have any sort of locks that might be required for global destructors. For example, this program deadlocks in exit (actually in the global dtor):
#include <iostream>
#include <mutex>
std::mutex lock;
class A {
public:
A() {
std::lock_guard<std::mutex> acquire(lock);
std::cout << "ctor A" << std::endl;
}
~A() {
std::lock_guard<std::mutex> acquire(lock);
std::cout << "dtor A" << std::endl;
}
};
A a;
int main()
{
std::lock_guard<std::mutex> acquire(lock);
exit(0);
}
Now your problem may be something completely different, but there's a strong possibility its related to something in a global destructor that is misbehaving because some object on the stack has not been destroyed properly.
If you want to exit while unwinding the stack properly (which is required for RAII structured code), you can't call exit. Instead you need to throw an exception which is caught (only) in main and causes main to return.