access shadowed global variable in C via dlsym not work - c++

int myvar=100;
main()
{
pid_t (*f) (void );
int *ip;
int myvar=10;
f = (pid_t(*) (void)) dlsym(RTLD_NEXT, "getpid");
ip = (int *) dlsym(RTLD_NEXT, "errno");
if (ip)
printf("%d \r\n", *ip);
ip = (int *) dlsym(RTLD_NEXT, "myvar");
if (ip)
printf("%d \r\n", *ip); //not work where is i am wrong
}

The getpid and errno symbols are exported by the libc.
myvvar symbols is in your executable and is probably not exported.
Objdump -T will help you to check if the symbol is exported or not.
$ objdump -T /lib/libc.so.6 | grep -w getpid
00c9c570 g DF .text 00000036 GLIBC_2.0 getpid

myvar will not be generally exported into the dynamic symbol table, unless you use a linker flag like -rdynamic when linking it.

Why don't you use the C++ scope operator:
::myvar = myvar + 1;
and then namespaces.

Related

dlopen() - Is this undefined symbol error related to dependencies?

The background of the issue is in an already answered question, here
I have a symbol that I want to use in a shared library but despite being listed as a T defined symbol via nm, F (function) via objdump, when I try to access it using dlopen() or via Python (ctypes.CDLL), it seemingly does not exist or is not defined.
I was reading here that this could be related to dependencies.
Output of ldd:
linux#host:~$ ldd ./compiled_program
linux-vdso.so.1 (0x00007ffde1fdf000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3381e7c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f338246f000)
Output of dn -DC:
linux#host:~$ nm -DC ./compiled_program
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w __cxa_finalize
w __gmon_start__
U __libc_start_main
U __stack_chk_fail
U printf
U putchar
U puts
U rand
U srand
U time
With my limited knowlege of C, I am unable to tell if any of these might be unresolved dependencies and where to look for which libraries to load, as the answer suggests, to include them. Is it as simple as finding the library and adding an #include <...> or do I have to locate the library and load it with dlopen()? The answer seems to suggest the latter. I appreciate that I am completely flailing in the dark here!
My current dlopen code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
int main(int argc, char** argv) {
void *handle;
void (*func_in_question)(const char*);
handle = dlopen("./compiled_program", RTLD_LAZY);
if (!handle) {
/* fail to load the library */
fprintf(stderr, "Error: %s\n", dlerror());
return EXIT_FAILURE;
}
*(void**)(&func_in_question) = dlsym(handle, "function_I_would_like_to_use");
if (!func_in_question) {
/* no such symbol */
fprintf(stderr, "Error: %s\n", dlerror());
dlclose(handle);
return EXIT_FAILURE;
}
func_in_question(argv[1]);
dlclose(handle);
return EXIT_SUCCESS;
}
comes back with the undefined symbol error.
I would be grateful for any pointers on, a) any other reasons why I might not be able to access this symbol?
and b) if my half-baked suspicion about dependencies is anywhere near to making sense!
EDIT: copying error message from original question linked above:
Error: ./compiled_program: undefined symbol: function_I_would_like_to_use
and the output of nm --defined-only ./compiled_program from original
question:
0000000000200d98 d _DYNAMIC
0000000000200f88 d _GLOBAL_OFFSET_TABLE_
0000000000000ba0 R _IO_stdin_used
0000000000000d64 r __FRAME_END__
0000000000000bfc r __GNU_EH_FRAME_HDR
0000000000201010 D __TMC_END__
0000000000201010 B __bss_start
0000000000201000 D __data_start
00000000000007d0 t __do_global_dtors_aux
0000000000200d90 t __do_global_dtors_aux_fini_array_entry
0000000000201008 D __dso_handle
0000000000200d88 t __frame_dummy_init_array_entry
0000000000200d90 t __init_array_end
0000000000200d88 t __init_array_start
0000000000000b90 T __libc_csu_fini
0000000000000b20 T __libc_csu_init
0000000000201010 D _edata
0000000000201018 B _end
0000000000000b94 T _fini
0000000000000660 T _init
0000000000000710 T _start
0000000000201010 b completed.7696
0000000000201000 W data_start
0000000000000740 t deregister_tm_clones
0000000000000810 t frame_dummy
0000000000000a92 T main
000000000000081a T function_I_would_like_to_use \\ << this one
0000000000000780 t register_tm_clones

Why does dlsym fail to find a function in a dynamically loaded library?

Following this answer to the question about compiling additional code at runtime in C or C++ I prepared this main program
#include <dlfcn.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
int main()
{
// create library
system ( "/usr/bin/gcc -fPIC -shared test.cpp -o libtest.so" );
// load library
void* fLib = dlopen ( "./libtest.so", RTLD_LAZY );
if ( !fLib ) {
cerr << "Cannot open library: " << dlerror() << '\n';
}
if ( fLib ) {
void ( *fn ) () = reinterpret_cast<void (*)()>(dlsym(fLib, "test"));
if ( fn ) {
fn();
}
dlclose ( fLib );
}
return 0;
}
That is supposed to compile "test.cpp" into a dynamic library libtest.so in the current directory, load the library, find the test function in the library and call this funciton, but it seems that dlsym can't find the function, even though it's there.
Here's the test.cpp file:
#include <iostream>
void test()
{
std::cout << "TEST" << std::endl;
}
The main.cpp is compiled with
g++ -ldl main.cpp -o main
and when I execute it, nothing happens: the library is loaded but the fn pointer is not available, meaning the function hasn't been found in libtest.so.
If I look at the symbols in libtest.so with nm -gD, I see the test function:
nm -gD libtest.so
U __cxa_atexit##GLIBC_2.2.5
w __cxa_finalize##GLIBC_2.2.5
w __gmon_start__
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000001139 T _Z4testv
U _ZNSolsEPFRSoS_E
U _ZNSt8ios_base4InitC1Ev
U _ZNSt8ios_base4InitD1Ev
U _ZSt4cout
U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
and
c++filt _Z4testv
test()
Why doesn't dlsym find test()? How can I make it find the test function?
The solution is rather simple: Use C language linkage for exported symbols. Then they won't be mangled:
extern "C" void test()
{
std::cout << "TEST" << std::endl;
}

dlsym() returns 'symbol not found'

I'm using OS X 10.7 (Lion), XCode 4.6.3 and libstdc++ as the C++ Standard Library.
I have this code in my main project:
shared.cpp:
extern "C" int sharedFun()
{
return 5;
}
And this in my side project, that needs to dynamically load the main one:
loader.cpp:
#include <dlfcn.h>
int main(int argc, const char * argv[])
{
void* mainApp = dlopen("mainApp.dylib", RTLD_LAZY);
char* error;
dlsym(mainApp, "sharedFun");
if ((error = dlerror()) != nullptr)
{
....
}
}
nm output:
nm -gU mainApp.dylib | grep sharedFun
002a3a10 - 01 0000 FUN _sharedFun
002a3a10 T _sharedFun
dlopen loads the library just fine, but dlsym returns "symbol not found".
Any ideas?
Thanks.

How to check what shared libraries are loaded at run time for a given process?

Is there a way to check which libraries is a running process using?
To be more specific, if a program loads some shared libraries using dlopen, then readelf or ldd is not going to show it.
Is it possible at all to get that information from a running process? If yes, how?
Other people are on the right track. Here are a couple ways.
cat /proc/NNNN/maps | awk '{print $6}' | grep '\.so' | sort | uniq
Or, with strace:
strace CMD.... 2>&1 | grep -E '^open(at)?\(.*\.so'
Both of these assume that shared libraries have ".so" somewhere in their paths, but you can modify that. The first one gives fairly pretty output as just a list of libraries, one per line. The second one will keep on listing libraries as they are opened, so that's nice.
And of course lsof...
lsof -p NNNN | awk '{print $9}' | grep '\.so'
May be lsof - the swiss army knife of linux will help?
edit: to run, lsof -p <pid>, lists all sorts of useful information, for example, if the process is java, lists all the open jars - very cool...
Actually, you can do this in your code in the following way:
#include <link.h>
using UnknownStruct = struct unknown_struct {
void* pointers[3];
struct unknown_struct* ptr;
};
using LinkMap = struct link_map;
auto* handle = dlopen(NULL, RTLD_NOW);
auto* p = reinterpret_cast<UnknownStruct*>(handle)->ptr;
auto* map = reinterpret_cast<LinkMap*>(p->ptr);
while (map) {
std::cout << map->l_name << std::endl;
// do something with |map| like with handle, returned by |dlopen()|.
map = map->l_next;
}
The link_map structure contains at least the base address and the absolute file name. It's the structure that is actually returned by dlopen() with non-NULL first argument. For more details see here.
ltrace seems to be your friend.
From ltrace manual:
ltrace is a program that simply
runs the specified command until it
exits. It intercepts and records the dynamic library calls
which are
called by the executed process and the signals which are
received by
that process. It can also intercept and print the system calls
exe‐
cuted by the program.
Its use is very similar to strace(1).
On Linux, /proc/<processid>/maps contains a list of all the files mapped into memory, which I believe should include any loaded by dlopen().
On solaris there is also the pldd command.
You can do so programmatically on Linux. You can use the function dl_iterate_phdr.
Here is a small example taken from the man page :
#define _GNU_SOURCE
#include <link.h>
#include <stdlib.h>
#include <stdio.h>
static int
callback(struct dl_phdr_info *info, size_t size, void *data)
{
int j;
printf("name=%s (%d segments)\n", info->dlpi_name,
info->dlpi_phnum);
for (j = 0; j < info->dlpi_phnum; j++)
printf("\t\t header %2d: address=%10p\n", j,
(void *) (info->dlpi_addr + info->dlpi_phdr[j].p_vaddr));
return 0;
}
int
main(int argc, char *argv[])
{
dl_iterate_phdr(callback, NULL);
exit(EXIT_SUCCESS);
}
Would strace trace the library file being opened?
The question is whether you want to know it about a foreign process:
$ sleep 1h&p=$!;sleep 0.1;gdb -p $p -batch -ex 'info shared'
[1] 637756
...
From To Syms Read Shared Object Library
0x00007f795ffc4700 0x00007f7960135aed Yes /lib64/libc.so.6
0x00007f79601cc0a0 0x00007f79601f2d35 Yes /lib64/ld-linux-x86-64.so.2
[Inferior 1 (process 637756) detached]
Or about your own process:
#include <iostream>
#include <link.h>
#include <cassert>
#include <dlfcn.h>
int main() {
// prevent R_X86_64_COPY and r_state inconsistency if we accessed "_r_debug" directly.
r_debug *debug = (r_debug *) dlsym(RTLD_DEFAULT, "_r_debug");
assert(debug);
assert(debug->r_version == 1);
assert(debug->r_state == r_debug::RT_CONSISTENT);
link_map *prev = NULL;
for (link_map *map = debug->r_map; map; prev = map, map = map->l_next) {
assert(map->l_prev == prev);
std::cout << map << " " << (!map->l_name[0] ? "<empty>" : map->l_name) << std::endl;
}
}

Examining mmaped addresses using GDB

I'm using the driver I posted at Direct Memory Access in Linux to mmap some physical ram into a userspace address. However, I can't use GDB to look at any of the address; i.e., x 0x12345678 (where 0x12345678 is the return value of mmap) fails with an error "Cannot access memory at address 0x12345678".
Is there any way to tell GDB that this memory can be viewed? Alternatively, is there something different I can do in the mmap (either the call or the implementation of foo_mmap there) that will allow it to access this memory?
Note that I'm not asking about /dev/mem (as in the first snippet there) but about a mmap to memory acquired via ioremap(), virt_to_phys() and remap_pfn_range()
I believe Linux does not make I/O memory accessible via ptrace(). You could write a function that simply reads the mmap'ed address and have gdb invoke it. Here's a slightly modified version of your foo-user.c program along with the output from a gdb session.
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
char *mptr;
char peek(int offset)
{
return mptr[offset];
}
int main(void)
{
int fd;
fd = open("/dev/foo", O_RDWR | O_SYNC);
if (fd == -1) {
printf("open error...\n");
return 1;
}
mptr = mmap(0, 1 * 1024 * 1024, PROT_READ | PROT_WRITE,
MAP_FILE | MAP_SHARED, fd, 4096);
printf("On start, mptr points to 0x%lX.\n", (unsigned long) mptr);
printf("mptr points to 0x%lX. *mptr = 0x%X\n", (unsigned long) mptr,
*mptr);
mptr[0] = 'a';
mptr[1] = 'b';
printf("mptr points to 0x%lX. *mptr = 0x%X\n", (unsigned long) mptr,
*mptr);
close(fd);
return 0;
}
$ make foo-user CFLAGS=-g
$ gdb -q foo-user
(gdb) break 27
Breakpoint 1 at 0x804855f: file foo-user.c, line 27.
(gdb) run
Starting program: /home/me/foo/foo-user
On start, mptr points to 0xB7E1E000.
mptr points to 0xB7E1E000. *mptr = 0x61
Breakpoint 1, main () at foo-user.c:27
27 mptr[0] = 'a';
(gdb) n
28 mptr[1] = 'b';
(gdb) print peek(0)
$1 = 97 'a'
(gdb) print peek(1)
$2 = 98 'b'
I have the answer to your conundrum :) I've searched everywhere online without much help and finally debugged it myself.
This post was a good starting point for me. I wanted to achieve something in similar lines, I had implemented a char driver with MMAP to map my custom managed memory to a userspace process. When using GDB, ptrace PEEK calls access_process_vm() to access any memory in your VMA. This causes a EIO error since the generic access cannot get the PA of your memory. It turns out, you have to implement an access function for this memory by implementing .access of your VMA's vm_operations_struct. Below is an example:
//Below code needs to be implemented by your driver:
static struct vm_operations_struct custom_vm_ops = {
.access = custom_vma_access,
};
static inline int custom_vma_access(struct vm_area_struct *vma, unsigned long addr,
void *buf, int len, int write)
{
return custom_generic_access_phys(vma, addr, buf, len, write);
}
static int custom_generic_access_phys(struct vm_area_struct *vma, unsigned long addr,
void *buf, int len, int write)
{
void __iomem *maddr;
//int offset = (addr & (PAGE_SIZE-1)) - vma->vm_start;
int offset = (addr) - vma->vm_start;
maddr = phys_to_virt(__pa(custom_mem_VA));
if (write)
memcpy_toio(maddr + offset, buf, len);
else
memcpy_fromio(buf, maddr + offset, len);
return len;
}
To access the mmapped memory, GDB will call ptrace, which will then call __access_remote_vm() to access the mmapped memory. If the memory is mapped with flags such as VMIO | VM_PFNMAP (for example, remap_pfn_range() sets them), GDB will access the memory though vm's access method defined by users.
Instead of writing our own implementation for access(), kernel already provides a generic version called generic_access_phys(), and this method could be easily linked via vm_operations_struct as the /dev/mem device did:
static const struct vm_operations_struct mmap_mem_ops = {
.access = generic_access_phys };
int mmap_mem()
{
.... ....
vma->vm_ops = &mmap_mem_ops;
.... ....
}
It is my understanding that GDB will be using ptrace to poke around in your process's memory. Perhaps you should write a simple program that just attaches to your process and uses ptrace to read from that memory. This might help narrow down what the underlying problem is. If that has no issues, then you know either I'm wrong :), or something else fishy is happening with GDB.
you go "info files"
(gdb) help info files
Names of targets and files being debugged.
Shows the entire stack of targets currently in use (including the exec-file,
core-file, and process, if any), as well as the symbol file name.
(gdb) info files
Symbols from "/bin/ls".
Unix child process:
Using the running image of child Thread 4160418656 (LWP 10729).
While running this, GDB does not access memory from...
Local exec file:
`/bin/ls', file type elf32-powerpc.
Entry point: 0x10002a10
0x10000134 - 0x10000141 is .interp
0x10000144 - 0x10000164 is .note.ABI-tag
0x10000164 - 0x100008f8 is .gnu.hash
0x100008f8 - 0x10001728 is .dynsym
0x10001728 - 0x100021f3 is .dynstr
0x100021f4 - 0x100023ba is .gnu.version
...
0x0ffa8300 - 0x0ffad8c0 is .text in /lib/libacl.so.1
0x0ffad8c0 - 0x0ffad8f8 is .fini in /lib/libacl.so.1
0x0ffad8f8 - 0x0ffadbac is .rodata in /lib/libacl.so.1
0x0ffadbac - 0x0ffadd58 is .eh_frame_hdr in /lib/libacl.so.1
0x0ffadd58 - 0x0ffae4d8 is .eh_frame in /lib/libacl.so.1
0x0ffbe4d8 - 0x0ffbe4e0 is .ctors in /lib/libacl.so.1
0x0ffbe4e0 - 0x0ffbe4e8 is .dtors in /lib/libacl.so.1
...
(gdb) info sh
From To Syms Read Shared Object Library
0xf7fcf960 0xf7fe81a0 Yes /lib/ld.so.1
0x0ffd0820 0x0ffd5d10 Yes /lib/librt.so.1
0x0ffa8300 0x0ffad8c0 Yes /lib/libacl.so.1
0x0ff6a840 0x0ff7f4f0 Yes /lib/libselinux.so.1
0x0fdfe920 0x0ff1ae70 Yes /lib/libc.so.6
0x0fda23d0 0x0fdb0db0 Yes /lib/libpthread.so.0
Failing this, you can use "mem" to configure memory ranges.
(gdb) mem 1 1414
(gdb) info mem
Num Enb Low Addr High Addr Attrs
1 y 0x00000001 0x00000586 rw nocache
(gdb) disable mem 1
(gdb) info mem
Num Enb Low Addr High Addr Attrs
1 n 0x00000001 0x00000586 rw nocache
I think that if that memory is not accessible by GDB then it is not mapped into your process address space and so you get "Cannot access memory at addresss 0x12345678". If that application were run normally you would get a segmentation fault. Also, maybe your driver is screwed and you should check you actually can access the memory from within the kernel. Try with example here:
#include <cstdio>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
int main() {
int fd = open("/dev/zero", O_RDONLY);
void* addr = mmap(NULL, 1024, PROT_READ, MAP_PRIVATE, fd, 0);
for (int x = 0; x < 10; x++) {
printf("%X\n", ((char*)addr)[x]);
}
close(fd);
return 0;
}
If you open an AF_PACKET socket and mmap it, gdb can't access this memory. So there isn't a problem with your driver. It's either a problem with ptrace or with gdb.