Specify the type residing in a specific address - c

I use Bash to get a c program variables' addresses. How to know if the address is related to an integer, float or double variable?

As the comments mentioned you can't get the type unless you have debugging symbols. But if you do have the symbols then you can use GDB. Consider this program:
#include <stdio.h>
static int i = 42;
static float f = 42.1;
static double d = 42.2;
int main (int argc, char **argv) {
printf("i=%d, f=%f, d=%f\n", i, f, d);
return (0);
}
If you compile it as follows:
gcc -g -o types types.c
You can then get the type of variables like this:
ubuntu#ubuntu:~$ echo ptype i | gdb --silent types
Reading symbols from /home/ubuntu/types...done.
(gdb) type = int
ubuntu#ubuntu:~$ echo ptype f | gdb --silent types
Reading symbols from /home/ubuntu/types...done.
(gdb) type = float
ubuntu#ubuntu:~$ echo ptype d | gdb --silent types
Reading symbols from /home/ubuntu/types...done.
(gdb) type = double
ubuntu#ubuntu:~$
If you only have the symbol table and not full debugging information, i.e. the binary was compiled with -g, then processed by strip -d, then the best you can do is get the size of the given object using binary dump utilities such as nm, objdump or readelf.
Using nm:
ubuntu#ubuntu:~$ read addr next_addr <<< $(nm -n types | grep -A1 ' i$' | cut -d' ' -f1)
ubuntu#ubuntu:~$ echo "ibase=16; ${next_addr^^} - ${addr^^}" | bc
4
ubuntu#ubuntu:~$ read addr next_addr <<< $(nm -n types | grep -A1 ' f$' | cut -d' ' -f1)
ubuntu#ubuntu:~$ echo "ibase=16; ${next_addr^^} - ${addr^^}" | bc
4
ubuntu#ubuntu:~$ read addr next_addr <<< $(nm -n types | grep -A1 ' d$' | cut -d' ' -f1)
ubuntu#ubuntu:~$ echo "ibase=16; ${next_addr^^} - ${addr^^}" | bc
8
ubuntu#ubuntu:~$
This works as follows:
nm -n lists the symbol table with addresses in numerical order
grep -A1 ' i$ filters the symbol we are interested long with the immediately following line. Note this is a regular expression search constructed to find exactly the symbol i and nothing else
cut -d' ' -f1 lists just the addresses
read addr next_addr puts the addresses into two variables
The expression piped into bc then calculates the difference between the address we are interested in and the immediately following address. Note the addresses are in hex, so we need to tell bc that with the ibase parameter. Also the ${var^^} bash expansion converts the hex digits a-f to uppercase as bc requires this.

Related

concatenating strings to use on the command line

My assignment wants me to gather all the processes being run by using a ps -ef | grep -v grep | grep <PID#> I need to use, but I am receiving an illegal hardware instruction. here is the code:
//some code^
int PID = getpid();
char command[] = "ps -ef | grep -v grep | grep ";
char PIDString[12];
sprintf(PIDString, "%i", PID);
system("clear");
//These print just fine
//printf("%s\n",command);
//printf("ID %s",PIDString);
strcat(command, PIDString);
system(command);
When I tried to insert a %i. into the string "grep ...%.." it wouldn't work. Is there a way to do this instead of changing the int to a string and concatenating them. Please let me know what I'm missing to grasp.
char command[] = "ps -ef | grep -v grep | grep ";
Your compiler will allocate just enough memory to hold this string.
If you want to have additional space available, you could make sure by specifying the size of the array.
char command[100] = "ps -ef | grep -v grep | grep ";
You may wish to define a constant to hold that value, rather than just a magic number.

Why is the following shell command working when executed directly in command line, but not working when executed through C program using popen/system?

The command is : ps -c -p | tr -s " " | cut -d " " -f 2,6-10,13 | grep 'R'
I am running it through adb shell. Basically, I want a list of processes (and certain parameters) which are currently in the run queue. This is working fine if I run it directly through the shell.
However, if I put it in a C program and cross-compile it to run on Android, it's not working. Only ps -c -p is working (I have checked that). But on running this ps -c -p | tr -s " " | cut -d " " -f 2,6-10,13 | grep 'R', I get the output :
usage: tr [-cds] SET1 [SET2]
Translate, squeeze, or delete characters from stdin, writing to stdout
-c/-C Take complement of SET1
-d Delete input characters coded SET1
-s Squeeze multiple output characters of SET2 into one character
tr: Needs 1 argument
usage: cut OPTION... [FILE]...
Print selected parts of lines from each FILE to standard output.
-b LIST select only these bytes from LIST.
-c LIST select only these characters from LIST.
-f LIST select only these fields.
-d DELIM use DELIM instead of TAB for field delimiter.
-s do not print lines not containing delimiters.
-n don't split multibyte characters (Ignored).
cut: Needs -fcb
I think the output of ps -c -p is not being conveyed to tr, which doesn't convey it to cut.
Can you please suggest what's the issue?
Here's the code I am using:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 128
int main(int argc,char **argv)
{
char *cmd4 = "ps -c -p | tr -s " " | cut -d " " -f 2,6-10,13 | grep 'R'";
system(cmd4);
FILE *fp;
char buf[BUFSIZE];
// Another method
if ((fp = popen(cmd4, "r")) == NULL) {
printf("Error opening pipe4!\n");
return -1;
}
while (fgets(buf, BUFSIZE, fp) != NULL) {
// Do whatever you want here...
printf("cmd 4 running!");
printf("OUTPUT: %s", buf);
}
if(pclose(fp)) {
printf("Command not found or exited with error status4\n");
return -1;
}
return 0;
}
In the shell, you're using the following command:
ps -c -p | tr -s " " | cut -d " " -f 2,6-10,13 | grep 'R'
In C, you're passing the following to system (and later to popen):
ps -c -p | tr -s | cut -d -f 2,6-10,13 | grep 'R'
See the difference? Quotes need to be escaped in C source code. Also, when you have trouble like this, be sure to output the relevant data so you can see what is actually happening instead of what you planned. A simple puts(cmd4) would have revealed this instantly.

List global array variables in a C program

There is a similar question asked before about listing global variables in C and the answers to that were using nm and ctags. ctags cli was -
ctags -R -x --sort=yes --c-kinds=v --file-scope=no
Is there a ctags option to list only global arrays. In a huge codebase we are trying to reduce memory footprint and need to analyze all global arrays. Thanks.
If you use universal-ctags (https://ctags.io), readtags distributed as part of u-ctags may help you. The readtags command supports S-expression based filtering.
[yamato#slave]~/var/ctags-github% cat /tmp/a.c
cat /tmp/a.c
int f[10];
int g;
struct point {
int x, y;
} points [64][32];
[yamato#slave]~/var/ctags-github% ./ctags --kinds-C=v --fields=+t /tmp/a.c
./ctags --kinds-C=v --fields=+t /tmp/a.c
[yamato#slave]~/var/ctags-github% cat tags
cat tags
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/
!_TAG_PROGRAM_AUTHOR Universal Ctags Team //
!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/
!_TAG_PROGRAM_URL https://ctags.io/ /official site/
!_TAG_PROGRAM_VERSION 0.0.0 /26a9333b/
f /tmp/a.c /^int f[10];$/;" v typeref:typename:int[10]
g /tmp/a.c /^int g;$/;" v typeref:typename:int
points /tmp/a.c /^} points [64][32];$/;" v typeref:struct:point[64][32]
[yamato#slave]~/var/ctags-github% ./readtags -t tags -e -Q '(substr? ($ "typeref") "[")' -l
./readtags -t tags -e -Q '(substr? ($ "typeref") "[")' -l
f /tmp/a.c /^int f[10];$/;" kind:v typeref:typename:int[10]
points /tmp/a.c /^} points [64][32];$/;" kind:v typeref:struct:point[64][32]

How to show 'preprocessed' code ignoring includes with GCC

I'd like to know if it's possible to output 'preprocessed' code wit gcc but 'ignoring' (not expanding) includes:
ES I got this main:
#include <stdio.h>
#define prn(s) printf("this is a macro for printing a string: %s\n", s);
int int(){
char str[5] = "test";
prn(str);
return 0;
}
I run gcc -E main -o out.c
I got:
/*
all stdio stuff
*/
int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);
return 0;
}
I'd like to output only:
#include <stdio.h>
int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);
return 0;
}
or, at least, just
int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);
return 0;
}
PS: would be great if possible to expand "local" "" includes and not to expand "global" <> includes
I agree with Matteo Italia's comment that if you just prevent the #include directives from being expanded, then the resulting code won't represent what the compiler actually sees, and therefore it will be of limited use in troubleshooting.
Here's an idea to get around that. Add a variable declaration before and after your includes. Any variable that is reasonably unique will do.
int begin_includes_tag;
#include <stdio.h>
... other includes
int end_includes_tag;
Then you can do:
> gcc -E main -o out.c | sed '/begin_includes_tag/,/end_includes_tag/d'
The sed command will delete everything between those variable declarations.
When cpp expands includes it adds # directives (linemarkers) to trace back errors to the original files.
You can add a post processing step (it can be trivially written in any scripting language, or even in C if you feel like it) to parse just the linemarkers and filter out the lines coming from files outside of your project directory; even better, one of the flags (3) marks system header files (stuff coming from paths provided through -isystem, either implicitly by the compiler driver or explicitly), so that's something you could exploit as well.
For example in Python 3:
#!/usr/bin/env python3
import sys
skip = False
for l in sys.stdin:
if not skip:
sys.stdout.write(l)
if l.startswith("# "):
toks = l.strip().split(" ")
linenum, filename = toks[1:3]
flags = toks[3:]
skip = "3" in flags
Using gcc -E foo.c | ./filter.py I get
# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "foo.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 4 "foo.c"
int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);;
return 0;
}
Protect the #includes from getting expanded, run the preprocessor textually, remove the # 1 "<stdint>" etc. junk the textual preprocessor generates and reexpose the protected #includes.
This shell function does it:
expand_cpp(){
sed 's|^\([ \t]*#[ \t]*include\)|magic_fjdsa9f8j932j9\1|' "$#" \
| cpp | sed 's|^magic_fjdsa9f8j932j9||; /^# [0-9]/d'
}
as long as you keep the include word together instead of doing crazy stuff like
#i\
ncl\
u??/
de <iostream>
(above you can see 2 backslash continuation lines + 1 trigraph (??/ == \ ) backslash continuation line).
If you wish, you can protect #ifs #ifdefs #ifndefs #endifs and #elses the same way.
Applied to your example
example.c:
#include <stdio.h>
#define prn(s) printf("this is a macro for printing a string: %s\n", s);
int int(){
char str[5] = "test";
prn(str);
return 0;
}
like as with expand_cpp < example.c or expand_cpp example.c, it generates:
#include <stdio.h>
int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);;
return 0;
}
You can use -dI to show the #include directives and post-process the preprocessor output.
Assuming the name of your your file is foo.c
SOURCEFILE=foo.c
gcc -E -dI "$SOURCEFILE" | awk '
/^# [0-9]* "/ { if ($3 == "\"'"$SOURCEFILE"'\"") show=1; else show=0; }
{ if(show) print; }'
or to suppress all # line_number "file" lines for $SOURCEFILE:
SOURCEFILE=foo.c
gcc -E -dI "$SOURCEFILE" | awk '
/^# [0-9]* "/ { ignore = 1; if ($3 == "\"'"$SOURCEFILE"'\"") show=1; else show=0; }
{ if(ignore) ignore=0; else if(show) print; }'
Note: The AWK scripts do not work for file names that include whitespace. To handle file names with spaces you could modify the AWK script to compare $0 instead of $3.
supposing the file is named c.c :
gcc -E c.c | tail -n +`gcc -E c.c | grep -n -e "#*\"c.c\"" | tail -1 | awk -F: '{print $1}'`
It seems # <number> "c.c" marks the lines after each #include
Of course you can also save gcc -E c.c in a file to not do it two times
The advantage is to not modify the source nor to remove the #include before to do the gcc -E, that just removes all the lines from the top up to the last produced by an #include ... if I am right
Many previous answers went in the direction of using the tracing # directives.
It's actually a one-liner in classical Unix (with awk):
gcc -E file.c | awk '/# [1-9][0-9]* "file.c"/ {skip=0; next} /# [1-9][0-9]* ".*"/ {skip=1} (skip<1) {print}'
TL;DR
Assign file name to fname and run following commands in shell. Throughout this ansfer fname is assumed to be sh variable containing the source file to be processed.
fname=file_to_process.c ;
grep -G '^#include' <./"$fname" ;
grep -Gv '^#include[ ]*<' <./"$fname" | gcc -x c - -E -o - $(grep -G '^#include[ ]*<' <./"$fname" | xargs -I {} -- expr "{}" : '#include[ ]*<[ ]*\(.*\)[ ]*>' | xargs -I {} printf '-imacros %s ' "{}" ) | grep -Ev '^([ ]*|#.*)$'
All except gcc here is pure POSIX sh, no bashisms, or nonportable options. First grep is there to output #include directives.
GCC's -imacros
From gcc documentation:
-imacros file: Exactly like ‘-include’, except that any output produced by scanning file is
thrown away. Macros it defines remain defined. This allows you to acquire all
the macros from a header without also processing its declarations
So, what is -include anyway?
-include file: Process file as if #include "file" appeared as the first line of the primary
source file. However, the first directory searched for file is the preprocessor’s
working directory instead of the directory containing the main source file. If
not found there, it is searched for in the remainder of the #include "..."
search chain as normal.
Simply speaking, because you cannot use <> or "" in -include directive, it will always behave as if #include <file> were in source code.
First approach
ANSI C guarantees assert to be macro, so it is perfect for simple test:
printf 'int main(){\nassert(1);\nreturn 0;}\n' | gcc -x c -E - -imacros assert.h.
Options -x c and - tells gcc to read source file from stdin and that the language used is C. Output doesn't contain any declarations from assert.h, but there is still mess, that can be cleaned up with grep:
printf 'int main(){\nassert(1);\nreturn 0;}\n' | gcc -x c -E - -imacros assert.h | grep -Ev '^([ ]*|#.*)$'
Note: in general, gcc won't expand tokens that intended to be macros, but the definition is missing. Nevertheless assert happens to expand entirely: __extension__ is compiler option, __assert_fail is function, and __PRETTY_FUNCTION__ is string literal.
Automatisation
Previous approach works, but it can be tedious;
each #include needs to be deleted from file manually, and
it has to be added to gcc call as -imacros's argument.
First part is easy to script: pipe grep -Gv '^#include[ ]*<' <./"$fname" to gcc.
Second part takes some exercising (at least without awk):
2.1 Drop -v negative matching from previous grep command: grep -G '^#include[ ]*<' <./"$fname"
2.2 Pipe previous to expr inside xarg to extract header name from each include directive: xargs -I {} -- expr "{}" : '#include[ ]*<[ ]*\(.*\)[ ]*>'
2.3 Pipe again to xarg, and printf with -imacros prefix: xargs -I {} printf '-imacros %s ' "{}"
2.4 Enclose all in command substitution "$()" and place inside gcc.
Done. This is how you end up with the lengthy command from the beginning of my answer.
Solving subtle problems
This solution still has flaws; if local header files themselves contains global ones, these global will be expanded. One way to solve this problem is to use grep+sed to transfer all global includes from local files and collect them in each *.c file.
printf '' > std ;
for header in *.h ; do
grep -G '^#include[ ]*<' <./$header >> std ;
sed -i '/#include[ ]*</d' $header ;
done;
for source in *.c ; do
cat std > tmp;
cat $source >> tmp;
mv -f tmp $source ;
done
Now the processing script can be called on any *.c file inside pwd without worry, that anything from global includes would leak into. The final problem is duplication. Local headers including themselves local includes might be duplicated, but this could occur only, when headers aren't guarded, and in general every header should be always guarded.
Final version and example
To show these scripts in action, here is small demo:
File h1.h:
#ifndef H1H
#define H1H
#include <stdio.h>
#include <limits.h>
#define H1 printf("H1:%i\n", h1_int)
int h1_int=INT_MAX;
#endif
File h2.h:
#ifndef H2H
#define H2H
#include <stdio.h>
#include "h1.h"
#define H2 printf("H2:%i\n", h2_int)
int h2_int;
#endif
File main.c:
#include <assert.h>
#include "h1.h"
#include "h2.h"
int main(){
assert(1);
H1;
H2;
}
Final version of the script preproc.sh:
fname="$1"
printf '' > std ;
for source in *.[ch] ; do
grep -G '^#include[ ]*<' <./$source >> std ;
sed -i '/#include[ ]*</d' $source ;
sort -u std > std2;
mv -f std2 std;
done;
for source in *.c ; do
cat std > tmp;
cat $source >> tmp;
mv -f tmp $source ;
done
grep -G '^#include[ ]*<' <./"$fname" ;
grep -Gv '^#include[ ]*<' <./"$fname" | gcc -x c - -E -o - $(grep -G '^#include[ ]*<' <./"$fname" | xargs -I {} -- expr "{}" : '#include[ ]*<[ ]*\(.*\)[ ]*>' | xargs -I {} printf '-imacros %s ' "{}" ) | grep -Ev '^([ ]*|#.*)$'
Output of the call ./preproc.sh main.c:
#include <assert.h>
#include <limits.h>
#include <stdio.h>
int h1_int=0x7fffffff;
int h2_int;
int main(){
((void) sizeof ((
1
) ? 1 : 0), __extension__ ({ if (
1
) ; else __assert_fail (
"1"
, "<stdin>", 4, __extension__ __PRETTY_FUNCTION__); }))
;
printf("H1:%i\n", h1_int);
printf("H2:%i\n", h2_int);
}
This should always compile. If you really want to print every #include "file", then delete < from grep pattern '^#include[ ]*<' in 16-th line of preproc.sh`, but be warned, that content of headers will then be duplicated, and code might fail, if headers contain initialisation of variables. This is purposefully the case in my example to address the problem.
Summary
There are plenty of good answers here so why yet another? Because this seems to be unique solution with following properties:
Local includes are expanded
Global included are discarded
Macros defined either in local or global includes are expanded
Approach is general enough to be usable not only with toy examples, but actually in small and medium projects that reside in a single directory.

How to execute multiple commands in system() , also using a variable

Ok so I've googled for an hour or more and I still didn't solved my issue.
I have these 3 bash commands:
find . -name "file_name" -exec du -h {} \; -> gives me the file's size
ls -l --time-style='+%d/%m/%Y' "file_name" | awk '{print $6}' -> last modiffied date
ls -l "file_name"|cut -d" " -f1 -> file's permissions
And I want to execute these 3 commands at a time using system();
Output example :
File size : ...
Last modiffied date : ...
File permissions : ...
My attempt :
char command[256];
char file_name[]={"myfile.txt"};
sprintf(command,"find . -name %s -exec du -h {} \; &&
ls -l --time-style='+%D/%m/%Y' %s | awk '{print $6}' &&
ls -l %s | cut -d' ' -f1",
file_name,file_name,file_name);
system((char*)command);
NOTES : I don't have to worry about the file's path because I'm using files from the same directory I execute my c program.
Compilation error : 'Sh: && is not expected'
You needed to add a percent sign in front of each percent sign you wanted in your command, otherwise it would be interpreted by sprintf as a print-mask introducer. Additionally, you need to add a back-slash in front of each back-slash you want in your command, otherwise it would be interpreted by sprintf as an introducer (e.g. for \n etc.). Additionally, I modified the sprintf second argument (i.e. the string)... I put ending quotes at the end of each physical line in your code, and at the beginning of the next physical line in your code.
Here is an example that may be what you are looking for (at least it compiles and runs):
#include <stdio.h>
int main(int argc, char **argv)
{
char command[256];
char file_name[] = "myfile.txt";
sprintf(command, "find . -name %s -exec du -h {} \\; && "
"ls -l --time-style='+%%D/%%m/%%Y' %s | awk '{print $6}' && "
"ls -l %s | cut -d' ' -f1",
file_name,
file_name,
file_name);
printf("command: -->%s<--\n\n\n", command);
system((char*)command);
}

Resources