Search the symbol table of a child process

Hi,

I am a newbie in Linux land, and I have a question about programming parent/child process interaction:

How do I search the value of a symbol in the child process? Is it possible?

I am doing a fork() and execve() to spawn any child possible, and I need something on the parent side to give me the value of any given symbol in the child, ie. "main".

In AmigaOS (my home country) this is very simple. Maybe there is a reason for it not to be so simple in UNIX land?

Best /Alpha

You have to use an IPC (interprocess communication) mechanism, some listed here:

  1. use a file
  2. use pipes
  3. use shared memory
  4. semaphores / mutexes

tldp.org link for IPC
6 Linux Interprocess Communications Documentation

Unless you are using shared memory, there is normally no direct access to memory-only objects by the parent into a child process memory. Debuggers may use kernel mode memory access to get around this restriction -- a security issue otherwise.

2 Likes

Thanks.

I still don't understand, though: If my child executes something like this:

int pid = fork();
if(pid == 0) {
    //where exactly do I set up the IPC? Before this point, I do not know any symbol values of 'processName', and after this point, I can no longer do any child specific symbol manipulation.
    execve(processName, 0, 0); //processName can be any process. Like 'ls'.
} else {
    //what to do here?
}

... where is the space, from where the child should conduct its part of the IPC? Can I somehow set up a handler function on the child side, or what exactly am I supposed to do?

Sorry, this is so alien to me, and probably I am trying something, that is not very 'Unix', because of my background in another operating system. Any help is very much appreciated.

Where you set up IPC depends on which one you select. If you were to read the link, you would see a pipe example like this (from forgeeks.org):

// C program to demonstrate use of fork() and pipe() 
#include<stdio.h> 
#include<stdlib.h> 
#include<unistd.h> 
#include<sys/types.h> 
#include<string.h> 
#include<sys/wait.h> 
  
int main() 
{ 
    // We use two pipes 
    // First pipe to send input string from parent 
    // Second pipe to send concatenated string from child 
  
    int fd1[2];  // Used to store two ends of first pipe 
    int fd2[2];  // Used to store two ends of second pipe 
  
    char fixed_str[] = "forgeeks.org"; 
    char input_str[100]; 
    pid_t p; 
  
    if (pipe(fd1)==-1) 
   { 
        fprintf(stderr, "Pipe Failed" ); 
        return 1; 
    } 
    if (pipe(fd2)==-1) 
    { 
        fprintf(stderr, "Pipe Failed" ); 
        return 1; 
    } 
  
    scanf("%s", input_str); 
    p = fork(); 
  
    if (p < 0) 
    { 
        fprintf(stderr, "fork Failed" ); 
        return 1; 
    } 
  
    // Parent process 
    else if (p > 0) 
    { 
        char concat_str[100]; 
  
        close(fd1[0]);  // Close reading end of first pipe 
  
        // Write input string and close writing end of first 
        // pipe. 
        write(fd1[1], input_str, strlen(input_str)+1); 
        close(fd1[1]); 
        // Wait for child to send a string 
        wait(NULL); 
  
        close(fd2[1]); // Close writing end of second pipe 
  
        // Read string from child, print it and close 
        // reading end. 
        read(fd2[0], concat_str, 100); 
        printf("Concatenated string %s\n", concat_str); 
        close(fd2[0]); 
    } 
  
    // child process 
    else
    { 
        close(fd1[1]);  // Close writing end of first pipe 
  
        // Read a string using first pipe 
        char concat_str[100]; 
        read(fd1[0], concat_str, 100); 
  
        // Concatenate a fixed string with it 
        int k = strlen(concat_str); 
        int i; 
        for (i=0; i<strlen(fixed_str); i++) 
            concat_str[k++] = fixed_str; 
  
        concat_str[k] = '\0';   // string ends with '\0' 
  
        // Close both reading ends 
        close(fd1[0]); 
        close(fd2[0]); 
  
        // Write concatenated string and close writing end 
        write(fd2[1], concat_str, strlen(concat_str)+1); 
        close(fd2[1]); 
  
        exit(0); 
    } 
} 
1 Like

Piping enables me to read the console output of a process. I did a fair bit of piping, back when I ported CMake to the Amiga platform.

Now, I simply do not get: How does that give me access to the symbols of the execve process? AFAICS there is no way, that a random process like 'ls' is going to come up with a generalized form of submitting a symbol value (ie. "main = 0xbeefdeaf") to either the stdin, stdout or stderr. I guess, if I *could* interrerupt the child process and execute something like

// ** child code
//int parentPipeFd = something sensible
void interrupt_handler() {
    void *main__symbol = dlsym(RTLD_DEFAULT, "main");
    fprintf(parentPipeFd, "0x%x", main__symbol);
}

But then how do I actually run a piece of code on the child side without having to write it in the actual code of the execve process?

Sorry, I am being really thick headed on this point, I can see. Please bear with me, I am so new to all of this ;).

EDIT: Could this be what I am looking for? EDIT EDIT: I am too new to post links. I think, I figured it out, thanks for the help :).

Well, in fact it seems, that I was wrong - I haven't solved the problem. What I was trying to do was to setup a signal handler, that would drive the interchange of information between the parent and the child. According to an answer to a similar question on another forum (I still cannot post links due to my status as initiate), this is indeed not possible at all. So I am about to give the answer to my own question, that what I am trying to do is actually impossible. I would love nothing more than to be proven wrong :).

It doesn't. The child is supposed to print its own symbols.

Either that, or you go whole-hog and attach a debugger. Probably much easier to use gdb than build it yourself.

1 Like

If you need a direct read from a symbol table, use shared memory. The reader is the parent. The child has to do some minimal work. No worK? The Corona's approach is all there is left. If your UNIX supports the /proc filesystem then you can get information from there because it exposes process kernel memory - depending on what you want, which you did not specify.

proc(5) - Linux manual page

Even better - consider the ptrace system call: ptrace(2) - Linux manual page
You can directly read child process memory.

Well, I was hoping, I could cook up something simple. Apparently UNIX is a bigger monster, than I expected. I wish everything was as simple as AmigaOS. But that's off topic.

Anyway, I guess the thread is closed...?

We don't even know your goal, architecture, or programming language here. Your question hasn't come across very far. Ask vague questions, get vague answers.

What is your goal? Don't say "to look up a symbol table". Why are you looking up symbols? That sounds like something the debugger would do in any OS, the OS not being one giant do-everything program. You might be asking how to use the GNU debugger. Maybe. Explain further and we'll maybe figure out what you need.

1 Like

Well, essentially I wanted to expand my debugger for AmigaOS to work on other platforms. I could do just a libgdb wrapper, but I thought it would be more interesting to do it manually and figure out, how these things work on other OS'es. Which means mainly linux at the time.

Obviously I got stuck just trying to find the address of a simple symbol. I came across this: GitHub - TartanLlama/minidbg: A mini x86 linux debugger for teaching purposes But he has the same problem: There is no symbol relocation done, so he doesn't know the actual placement of the symbols in the executable.

I am going to look into if shared memory of the /proc handler can help me. If not, I am probably going to do some libgdb wrapper for my app and focus on getting that to work and other platforms.

You can access raw memory contents that way, but /proc/ won't tell you a thing about the symbols in it, just what address space the process owns.

Shared libraries and symbol lookup have changed a lot in Linux due to 64-bit growing pains and modern security concerns; Linux mutates very fast. They've gone through several models. Best to use GDB.

1 Like

Ok. Maybe I'll dig in just a bit to see, how much I can learn. I very much doubt, that my project would have any large impact anyway, so if I can just use it for leverage to some kind of understanding, then that is probably good. Thanks for the pointers, I am still scratching the surface, but it is very interesting indeed.