How to use string value as a logging file name - c

I'm debugging a C program with GDB. I've got an array which the values are updated many times (a little bit less than 4.000). I want to write thoses value in a different file for each iterations.
I tried to set the log file name directly in a GDB file:
break test.c:95
commands
silent
# Set the logging file
set $_file=(char*)malloc(64)
call snprintf($_file, 64, "~/path/to/logging/file_%04d.txt", i) # i is the for variable
set logging file $_file
call free($_file)
set logging redirect on
set pagination off
set logging overwrite on
set logging on
set $_data=array
set $_x=0
while ($_x<2000)
set $_y=0
while ($_y<2000)
printf "%f ", $_data[$_x][$_y]
set $_y++
end
printf "\n"
set $_x++
end
# Log default setup
set logging off
set logging redirect off
set logging overwrite off
set pagination on
continue
end
But gdb created a file $_file in my working directory instead of reading the value of the variable.
I then tried to put the file name in which I want log the output in a variable fileName in my code (also with snprintf). And the result is the same, a fileName file is created in my working directory.
Finaly I tried to put the debug code into a gdb function, and give the fileName as an argument of the function, but as previously, it does not interpret the string.
My question
With GDB, how can I use the value of a C-string as a logging file name?

You can use eval to insert variables value into gdb's commands. In your case, logging file name could be setted to $_file by command:
eval "set logging file %s", $_file
Also you can use dump, in case if you want to dump array to fileName by gdb builtin commands:
eval "dump value %s array", fileName
Note: dumped value is binary.

But gdb created a file $_file in my working directory instead of reading the value of the variable.
It looks like GDB set logging file is missing an eval of its argument. You should file a bugzilla feature request issue for that.
If your GDB is built with embedded Python, you can trivially do what you want by attaching a Python command to the breakpoint.

Related

printf() redirection to file in command line (Cygwin)

I've got a C program that's supposed to work on command line interface taking few arguments - to do that I'm using Cygwin.
I want to know if it's possible to printf some prompts into command like - things like "Give a number:" before I get data (program needs to prompt for a couple of things) and get the final result redirected to file. Or if I'm redirecting to file I need to just resign myself to the fact that I can't print anything and everything goes into the file?
Essentialy I'd like something like this:
printf("Please enter any number:");//prompting for some variable
scanf("%d", &some_variable);
function_printing_its_output();//a nodescript function that at the end uses printf() to get results on screen
Now I was wondering if it's possible to make the first printf() prompt appear in command lie (possibly using different function if it exists) but have the function output go into the file (and I cannot directly make it print to file, the program needs to use ./program_name some_stuff file1 > file2 format to work redirecting to file2).
You could have your prompt go to stderr using fprintf(stderr, "...");.
– lurker

Changing the default main file in gdb

When I run gdb, there seems to be a notion of a main file, as if I set a breakpoint with just a number, it will get set for the source file that contains the main function.
How can I reconfigure gdb to set this to the file containing a function named my_main? (My actual main is provided by my library, in 99.9% of cases I want to focus on the the wrapped and prefixed main that the actual, library-provided, main calls).
GDB isn't doing what you say. When you say break LINE it sets a breakpoint in the "current" file, as per the docs:
The current source file is the last file whose source text was printed.
So perhaps what you want is to always set a breakpoint in my_main. If it helps you can make GDB let you up-arrow or Ctrl-R search backward through commands entered in previous sessions by following the instructions here: How can I make gdb save the command history?
You can set a breakpoint using directly function name: break my_main or you can specify filename and line: break file.c:100

Trying to run a batch file from another program and redirecting the output

I have a method to run a batch file with a list of parameters. Those parameters are sent to the batch file and the batch file calls another program that needs the parameter set up in a certain way:
start test --entities=%entities% --tags=%out% --start=%start% --end=%end% --interval=%interval% --wide>%output%
Where output is the file I want the results of running:
test --entities=%entities% --tags=%out% --start=%start% --end=%end% --interval=%interval% --wide
To be placed but I keep getting 1> instead of > when I run the file.
> is just a short form of 1> (1 means STDOUT = Standard output stream). Command repetition will insert the 1 for you, if you didn't write it. That's neither a failure nor a problem.
Your actual problem is, that you redirect the output of the start command - which is empy.
To redirect the output of your batchfile, use
start test --entities=%entities% --tags=%out% --start=%start% --end=%end% --interval=%interval% --wide ^>%output%
You might want to try, if
call test --entities=%entities% --tags=%out% --start=%start% --end=%end% --interval=%interval% --wide >%output%
works even better for you.
Check out Ryan's Guide to Piping and Redirection: http://ryanstutorials.net/linuxtutorial/piping.php .

How can a C program tell if it was launched from the Finder?

The title kind of says it all:
I'm wondering if there's any _NSWasLaunchedFromFinder-type API or hook that an OS/X C program (of the int main(int argc, char* argv[]) variety) could use to determine if it was launched by a user clicking on the executable in the Finder vs. if it was run through a more traditional route (like being typed into the Terminal).
If you are talking about plain command line utility - there is no way to determine whether it was launched from Finder or in terminal since Finder will launch terminal and then execute your program in it.
But there is a solution. I'd rather call it a workaround. You can wrap your executable with bundle, create simple script (lets call it finderLauncher) which will launch actual executable with some additional command line parameter (-launchedFromFinder for example). Don't forget to make it executable. Than in your Info.plist file set finderLauncher as CFBundleExecutable value.
And now in Finder user will see only your bundle and by clicking on it your actual executable will be launched via finderLauncher passing specified command line parameter. Same behaviour will be by using open command in terminal.
And by direct launch from terminal there would be no -launchedFromFinder parameter (off course if user will not pass it directly).
P.s. It would be much easier by specifying command line parameters directly in Info.plist, but I can't find such key in Information Property List Key Reference although there is such key for agents/daemons.
Method 1 ::
You can use NSGetExecutablePath
Here's the dev reference to it :: Mac Developer Library
_NSGetExecutablePath() copies the path of the main executable into the buffer buf. The bufsize parameter should initially be the size of the buffer. This function returns 0 if the path was successfully copied, and * bufsize is left unchanged. It returns -1 if the buffer is not large enough, and *
bufsize is set to the size required. Note that _NSGetExecutablePath() will return "a path" to the exe-
cutable not a "real path" to the executable. That is, the path may be a symbolic link and not the real
file. With deep directories the total bufsize needed could be more than MAXPATHLEN.
Method 2 ::
Use AppleScript
You can use AppleScript to find the current applications open with the following script ::
tell application "Finder"
set appPath to my getFrontAppPath()
set AppleScript's text item delimiters to {":"}
set currentApp to text item -2 of appPath
say currentApp
end tell
on getFrontAppPath()
set frontAppPath to (path to frontmost application) as text
set myPath to (path to me) as text
if frontAppPath is myPath then
try
tell application "Finder" to set bundleID to id of file myPath
tell application "System Events" to set visible of (first process whose bundle identifier is bundleID) to false
-- we need to delay because it takes time for the process to hide
-- I noticed this when running the code as an application from the applescript menu bar item
set inTime to current date
repeat
set frontAppPath to (path to frontmost application) as text
if frontAppPath is not myPath then exit repeat
if (current date) - inTime is greater than 2 then exit repeat
end repeat
end try
end if
return frontAppPath
end getFrontAppPath
That should get you the application last opened, whether it was Terminal or Finder :)
For Finder you get a response :: "Macintosh HD:System:Library:CoreServices:Finder.app:"
For Terminal :: "Macintosh HD:Applications:Utilities:Terminal.app:"
Get the Parent Process ID. Then browse its Process Status to get its PPID, recursively up to Finder.app or init.
Once you have found the terminal ancestor that is child of Finder.app, you can look at its start time and its arguments (see the -o and -O options in man ps: your keywords should include args and start): if the terminal process started near your programm start time and the arguments include your program name, you know that it has been started by Finder.app.
Probably, you can ignore the times and just look for the terminal's arguments.
You can assume the reverse logic and use isatty.
if (isatty(1)) printf("Launched in a terminal\n");
else printf("Launched by clicking something\n");
This just determines if stdout is a tty. If you launch it from a program, icon, menu etc... it will be false. also if you want to tell if an X server is running and it was launched from a terminal emulator you can use getenv("DISPLAY") which is set when X starts (so it will be NULL if run from the console)
// when the user doubleclicks your program it will be started with a -psn_ parameter
if (argc >= 2 && (strncmp(argv[1], "-psn_", 5) == 0)) {
InfoLogWithClient(L"Init", L"Program %d cannot be started with double-click!", getpid());
return EX_USAGE;
}

Set GDB breakpoint in C file

Is it possible to add GDB breakpoints in a C files, before compilation? Currently, I have to specify breakpoints after compilation through GDB.
I'm looking for something similar to JavaScript's debugger; statement.
Not as such, but you can insert some helpful function calls:
One option is to create a function:
void break_here ()
{
/* do nothing */
}
then call it wherever you want, but be careful it doesn't get inlined (put it in a different file, or add a "noinline" attribute).
Then, in GDB, just set a breakpoint on break_here, and you're done. If you find it tedious to set that breakpoint every time, you can create a file named .gdbinit in your home directory or in the current working directory that contains the breakpoint command.
Another option that works on Linux is to use a signal:
raise (SIGUSR1);
You could use any signal you like, but it's better to use one that doesn't kill your program (although you can configure GDB to not pass them onto your program, if you choose).
I'm not aware of a way to directly set a breakpoint, but GDB will catch interrupts, so that is one possible solution.
Something like this should work. You'll need to include signal.h:
raise(SIGABRT);
on linux, which I'm assuming you're on since you're using gdb you could make a script to do it with comments in the code
#!/bin/bash
#debug: Script to run programs in gdb with comments to specify break
points
echo "file ./a.out" > run
grep -nrIH "/\*GDB\*/" |
sed "s/\(^[^:]\+:[^:]\+\):.*$/\1/g" |
awk '{print "b" " " $1 }'|
grep -v $(echo $0| sed "s/.*\///g") >> run
gdb --init-command ./run -ex=r
exit 0
then wherever you need a breakpoint, just add /*GDB*/, the script will use grep to find the line numbers and files with those comments, and set a break point on each line of each file it finds them on, then start gdb

Resources