How to get environment of a program while debugging it in GDB - c++

I am debugging a program in GDB on linux. I am using getenv and setenv calls to read and set environment variables. For example I am calling setenv("TZ", "UTC", 1); to set the TZ environment variable for timezone.
To check if the env variable is set I am using GDB command show environment. This prints all the environment variables and their values. But it dose not show TZ being set.
Even command show environment TZ says Environment variable "TZ" not defined.
Is their another way to check the environment of the debugged program?
p *(char *) getenv("TZ") reuturns correct value UTC.

The gdb command show environment shows an environment which belongs to gdb [see note], not the environment of the program being debugged.
Calling getenv seems like a totally reasonable approach to printing the running program's environment.
Note
Gdb maintains an environment array, initially copied from its own environment, which it uses to start each new child process. show environment and set environment work on this environment, so set environment will change an environment variable for the next time you start the program being debugged. Once the program is started, the loader will have copied the environment into the program's address space, and any changes made with setenv apply to that array, not the one maintained by gdb.
Addendum: How to print the debugged program's entire environment
On Linux, every process's environment is available through the pseudofile /proc/PID/environ, where PID is replaced by the pid of the process. The value of that file is a list of null-terminated strings, so printing it out takes a small amount of work.
Inside gdb, once you've started running the program to be debugged, you can get its pid with info proc and then use that to print the entire environment:
(gdb) info proc
process 6074
...
(gdb) shell xargs -0 printf %s\\n < /proc/6074/environ
XDG_VTNR=7
KDE_MULTIHEAD=false
...
Of course, I could have done that just as easily outside of gdb, from a different terminal.

You can alter GDB's view of the environment with set environment TZ =UTC but that doesn't affect a running program, only the environment that will be used next time an inferior process is started.
You can inspect a running inferior process' current environment via the global variable environ

Related

system() doesn't work for modifying the command line prompt

I'm using C++ in Ubuntu and want to modify the command prompt. If I enter PS1=abc in the command line, the prompt becomes abc.
However, if I execute a program that calls to system("PS1=ABC"), the prompt doesn't change.
On the other hand, system() appears to work fine with different commands and the command line obeys.
PS1 is an environment variable. Every process has its own set of environment variables.
When you start a new process, it inherits a copy of its parent's environment. Any changes to a process's environment will not affect the environment of its parent process.
The system function starts a new child process. That means that system("PS1=ABC") launches a child process that sets its own PS1 variable and then exits.
To modify an environment variable in your own process, use putenv (Linux and other Unix-likes) or SetEnvironmentVariable (Windows). Note that this still won't affect your parent process (likely the shell from which your program was launched), so setting PS1 still won't have any affect unless you then subsequently launch another shell as a child.
system(command) starts a sub process. Whenever it finishes, its whole environment is gone.
If you want to pass environment variables to the subprocess, look up fork() and exec().
Or, if your're using Windows, CreateProcess.

How to fix number of threads in gdb run of an OpenMP program

I am trying to debug an OpenMP C++ program with gdb on a Mac OSX machine. (OK, using "ggdb" technically.) No matter what I set OMP_NUM_THREADS to, gdb tries to run the code on 8 threads. Why is this? Is there a way for me to tell it myself the number of threads the code will run on?
Well, I guess I'm showing my ignorance, but I set it just before I
start up the debugger. Am I supposed to do it within the debugger?
You should set environment variable OMP_NUM_THREADS inside gdb:
(gdb) set environment OMP_NUM_THREADS 2
See also builtin help:
(gdb) help set environment
Set environment variable value to give the program.
Arguments are VAR VALUE where VAR is variable name and VALUE is value.
VALUES of environment variables are uninterpreted strings.
This does not affect the program until the next "run" command.

Permanently setting environment variables from a C++ program after exit

I am writing a bash script that runs a C++ program multiple times. I use getenv() and putenv() to create, get, and update environment variables in the C++ program. After the C++ program ends, the bash script needs to grab these variables and perform some basic logic. The problem is that when the C++ program exits, the environment variables disappear. Is there any way to permanently store these variables after the program's termination so that the bash script can use them? If not, what is the best way to share variables between a bash script and a C++ program? The only solution I can think of is writing output to files. I do not want to print this data in the console. Any help would be greatly appreciated.
Each process has its own copy of the environment variables, which are initialised by copying them from the parent process when the new process is launched. When you change an environment variable in your process, the parent process has no knowledge of this.
In order to pass back information from a child to a parent, you will need to set up some other kind of communications channel. It could be files on disk, or a pipe, or (depending on the capabilities of your parent, bash might not be able to do all this) shared memory or some other IPC mechanism. The parent program would then be responsible for changing its own environment variables based on information received from the child.
I personally have only ever been able to do this in 16-bit DOS assembler, by tracing the pointer to the previous process until it points at itself, which means that you've reached the first instance of COMMAND.COM, and then altered its environment manually.
If your program returned the variables via standard output as string, like this:
FOO=23; BAR=45;
Then, bash could call it like this:
eval `./your_program`
end $FOO and $BAR will be accessible to bash.
To test this try:
eval `echo "FOO=23; BAR=45;"`
echo "$FOO $BAR"
Of course, in this method the program does not change environment variables of calling process (which is not possible), but just returns a string that is then evaluated by bash and the evaluation sets the variables.
Do not use this method if your program processes input from not trusted source. If someone tricked your program to print "rm -rf /" to the standard output you would be doomed.
As far as i know under a "standard" GNU/Linux environment you can set environment variables in 3 ways:
using command line utilities like export
editing files like ~/.profile or ~/.bashrc for an user or the equivalent files under /etc for system
feeding temporary values to a command like this CXX=g++ CUSTOM_VERSION=2.5 command
the last one is usually used to customize builds and it's good because doesn't harm the system and does not interfere with any system settings or values or files and everything is back to normal after the execution of the command. It's the best way if you like to have a temporary modification for a particular set of variables.
There is no way for a program to set environment variables in its parent. Or, well, no legitimate way. Hacking into its process with ptrace does not count. :-)
What you should do is output the environment variables on standard output. Have the shell script read them and set them. If the environment variables are all that you output the call is very simple:
`program`
The back-ticks will capture the output of the program. Then it will replace the back-ticks with the output. Which will be commands to set shell variables. Then later in your shell script be sure to do:
export VAR1
export VAR2
You need the export commands in order to move them into the environment that is passed to programs launched from the shell.
You cannot set environment variables which survive the life-time of your process, so the easiest solution is to write to output files as you suggested or write to specific filehandles handed down from Bash:
C++:
int main (int argc, char* argv[])
{
// missing error handling
int fd = atoi(argv[1]);
const char* env = "BLAH=SMURF";
write(5, env, strlen(env));
return 0;
}
Bash:
# discard stdout and stderr, redirect 5 to stdout so that it can be captured
# and tell the process that it should write to 5 (the first 5)
VARIABLES=`./command 5 2>&1 1>/dev/null 5>&1`
This is probably a crack-pot idea but it should work :)

In Linux C++, how do you read an environment variable of a specified user?

I know that getenv() returns a value of specified environment variable of the current user, but my code requires root privileges so getenv() would only use the sudo environment variables. I also know that SUDO_USER tells which user is invoking sudo, which is the user environment I want use for getenv().
char* gnome_env_var = getenv("GDMSESSION"); //returns null as not found in sudo env
char* usr = getenv("SUDO_USER");
Is there a way I can get the value of an environment variable for the logged in user, not the sudo environment?
EDIT
Okay, so what I'm hearing is that the set of environment variables are unique to each process, not user and using sudo to invoke a process with root privileges calls execve which can create an entirely new set of environment variables for that process. So to rephrase, is there a way besides messing with the sudoers file, and within the current process, of finding the calling process's environment variables?
I particularly need the GDMSession environment variable.
getenv doesn't tell you about the environment variables of the current user, but the current process. Users are free to have as many environments as they want(and can create processes), for example with the export shell built-in. In every call to execve, the calling program is free to create an entirely new environment for the executed process.
Therefore, there is no way to get the environment variables of the user, or even those of the process executing sudo. Why do you want that anyways?
You can, however, configure sudo to keep some or all environment variables, via the keep_env and reset_env directives in /etc/sudoers.
There isn't a "user environment." Every process has its own copy of the environment variables. They don't even automatically inherit -- that they appear to is an illusion maintained by the shell and the C library. It is more accurate to think of them as a second set of command line arguments to every program.
So before we can answer your question, you need to clear up what you mean! There are possibilities - none of them are elegant, mind, but they do exist - but they depend crucially on which environment variable you want to get at in which process's state and why.

C++ getenv always returns null value

I have just added the environment variable "DataDir", but the getenv function still returns null value.
Here is my code:
const char *ret = getenv("DataDir");
I restarted my computer and it done.
did you remember to export the variable before running the program? If you are using bash shell on linux, for example, you generally should use export DataDir="..."
On windows, if you set the environment variables using the system settings window, it will not immediately propagate to all of the running programs. If "I restarted my computer and it done." means "restarting the computer resolved the issue", then I believe that explains the problem. After changing the environment variable, try closing all programs and then start a CMD session (or visual studio) and run the program again
Are you running on Windows? Did you set the environment variable through the control panel? If so, that only affects processes that you start (programs that you launch) after you changed the setting. If you're running from a command prompt, and the command prompt didn't inherit the new environment variable, then your program won't inherit it either.
After rebooting, all new processes inherit the new environment variable.
On the other hand, if you set the variable and then run the program:
C:\>set DataDir=blah
C:\>.\my_program
then your program will inherit the variable (but it won't persist across a reboot).
Similar considerations apply on Linux and other systems, but the details differ.
Note that I'm only guessing, based on the symptoms you reported, what system you're using. In the future, it would be helpful to provide that information in the question (if it's not relevant we can ignore it).