Testing a modified version of readelf - linux

I modified the readelf.c file in binutils-2.36.1/binutils/ such that it prints a few details differently with some flags such as "s","S","a" and doesn't affect the output of other flags.
I'm trying to test whether the changes I made to the file affected any other flags than the ones I intended(mentinoed above).
and therefore I generated a few tests of the following format :
./binutils/readelf -g ./readelfTests/Objects/ObjectFiles/object_1.o
./binutils/readelf -n ./readelfTests/Objects/ObjectFiles/object_1.o
./binutils/readelf -e ./readelfTests/Objects/ObjectFiles/object_1.o
./binutils/readelf -S ./readelfTests/Objects/ObjectFiles/object_1.o
and so on, you get the point.
the problem is the .o files I have are very basic with few sections and variables therefore running a test on them may not catch the errors in my code, I'd appreciate a way to get some .o files with a lot of sections and variables such that running tests on them may actually be effective.
or alternatively I'd appreciate a way to test my modified readelf file in an automatic way.

Related

How is the -fprofile-prefix-path option supposed to work?

When compiling code for coverage instrumentation (to use with lcov later on), we're compiling from a base directory tree (let's call it A), and we want the .gcda files to be produced at a different place (because the target directory tree is different - let's call it B).
So, the compilation command looked like this:
gcc -O0 -g --coverage -fprofile-dir=B -c -fPIC -Wall -o A/otherpath/to/mySourceFile.o A/path/to/mySourceFile.c
When checking the contents of mySourceFile.o (with the strings command), I saw that the mySourceFile.gcda file was set to be generated in B/A/otherpath/to/mySourceFile.gcda
Which is the mangling of the path given through the -fprofile-dir option with the exact absolute path of the object file created - just as written in the documentation. So far, no problem - except that what I want would be the mySourceFile.gcda file to be generated from the B directory, WITHOUT the A part.
So, the documentation also mentions the -fprofile-prefix-path option, which is supposed to allow you to remove part of the path, so that the mangling doesn't add the old path to the new.
I tried using it in the following way:
gcc -O0 -g --coverage -fprofile-dir=B -fprofile-prefix-path=A -c -fPIC -Wall -o A/otherpath/to/mySourceFile.o A/path/to/mySourceFile.c
However, after checking through strings, once again, in the generated object file, the path was still B/A/otherpath/to/mySourceFile.gcda, whereas I expected it to be B/otherpath/to/mySourceFile.gcda (that is, I expected the A part to have been stripped by the -fprofile-prefix-path option.)
Obviously, it didn't work. Any insight why ?
( Compiler used is GCC 11.2.1, which is a version recent enough to know about the option. )
Ok, after some tinkering, I got results. Maybe not exactly what I was expecting, but close enough.
Let me start by saying that the A and B "directories" I mentioned in my question were absolute paths. And it didn't work well.
However, while keeping the absolute B (target) path, I tried not using the full A (source) path while compiling. More precisely, I didn't use it to specify the OUTPUT file name, for the object. Instead, I went to the base directory (the A path), and then, ran the command by specifying the output file path relative to the current (A) directory
Which would give the following command:
(From directory A)
gcc -O0 -g --coverage -fprofile-dir=B -fprofile-prefix-path=A -c -fPIC -Wall -o otherpath/to/mySourceFile.o path/to/mySourceFile.c
This time, the source command did show an interesting result, for the mySourceFile.gcda file:
B#otherpath#to#mySourceFile.gcda
As you can see, it's not exactly what I wanted (there are # instead of /), but mentions to A disappeared, and overall, I'm confident it should work as intended. Not utterly sure yet (I still have to test it on the target platform, which will need tinkering with the way the makefiles currently work), but confident nonetheless.
Also, if I didn't use the -fprofile-prefix-path in the command, then the string would mention the A path, like this (with the '/' inside the A path being replaced with '#' characters, obviously):
B#A#otherpath#to#mySourceFile.gcda
So, the option works, but only when using relative paths, not when using absolute ones, for the object file. Hope that helps people.
PS: I checked by changing the path to the source (.c) file. Whether specified using absolute, or relative, paths, it didn't change the outcome. What matters is specifying the path to the object file in a relative manner.

When changing the comment of a .c file, scons still re-compile it?

It's said that scons uses MD5 signature as default decider to dertermine whether a source file needs re-compilation. E.g. I've got SConstruct as below:
Library('o.c')
And my o.c is:
$ cat o.c
/*commented*/
#include<stdio.h>
int f(){
printf("hello\n");
return 2;
}
Run scons and remove the comment line, run scons again. I expect that scons should not compile it again, but actually it's:
gcc -o o.o -c o.c
scons: done building targets.
If I change SConstruct file to add one line:
Decider('MD5').
Still same result.
My question is: how to make sure that for scons, when changing source file comments, they don't get re-built?
Thanks!
As you correctly stated, SCons uses the MD5 hashsum of a source file to decide whether it has changed or not (content-based), and a rebuild of the target seems to be required (since one of its dependencies changed).
By adding or changing a comment, the MD5 sum of the file changes...so the trigger fires.
If you don't like this behaviour, you can write and use your own Decider function which will omit comment changes to your likings. Please check section 6.1.4 "Writing Your Own Custom Decider Function" in the UserGuide to see how this can be done.

Handling command line options with multiple arguments for some flags

I'm writing a program where the command line usage should be something like:
mkblueprint FILE FILE FILE -o <output name> -s <string> -r <number> -p pOPT1 pOPT2 pOPT3
I'm currently using CmdLib and I can't figure out a way to handle this; a flag is required for each input(so I can't just have FILEs sitting alone) and there doesn't appear to be a way to pass multiple arguments to a flag, as with -p. These are extremely common in command line programs so I figure I'm just misunderstanding the documentation, but it's not mentioned in any command line library I look at for Haskell.
After some more work with CmdLib I was able to handle the bare FILE input via the Extra tag and then checking that each string is a valid file, which seems to be the standard way to handle it despite the name. -p pOPT1 pOPT2 pOPT3 is apparently not allowed under the POSIX standard, which is why I'm not finding libraries that will do it.
You might consider the GetOpt bindings that come with base. They're not as sexy as some of the more modern alternatives, but they support bare arguments and final options well.

Windres syntax error

I am working in MinGW environment (downloaded with their installer on 12/12/2011). I am attempting to compile a resource (.rc) file using Windres. The specific command I use is
Windres -O coff About1.rc -o About1.res
Windres generates at least 100 lines of warning messages reading: "warning: null characters ignored". Following this Windres emits: "Abouty1.rc:1:syntax error".
As a matter of fact, there are no null characters in the About1.rc file. In addtition, the first line of the file is an include statement: #include "dlgresource.h". I played around and eliminated this statement and it turns out that it doesn't matter what I put there, I get the same flurry of messages and the syntax error notification.
To make things more confusing, this same .rc file compiles without any problem using MSFT's rc.exe. The resulting .res file links smoothly with the program .obj file and runs perfectly.
I have no idea what is going on. Any ideas?
Thanks,
Mark Allyn
Your .rc file is probably encoded as UTF-16.
That's what's required in general by Microsoft's [rc.exe], in order to be able to deal with international characters, but GNU [windres.exe] can only deal with ANSI encoding.
One workaround is to convert the file to ANSI on the spot (possibly losing e.g. Russian or Greek characters):
> chcp 1252
Active code page: 1252
> type my.rc | windres --output-format=COFF -o my.res
> _
You probably used VS or a similar tool to generate the file. There are some parts of the character encodings that you cannot see resulting in null characters and etc.
Generate a new .res file with the same content, don't copy/paste the content, type it in yourself.
Try:
windres About1.rc -o About1.o
and then just use the resulting .o file instead of the originally intended .res file.
I've had the same troubles than you today. I know it has passed a lot of time from your question, but I'm writting this on the hope that it can be useful for someone.
First, I obtained an object file .o compiled using Cygwin, writting:
windres -o resource.o resource.rc
By doing that, you dont need to use the .res file, but the .o one, and you can then link this object with all the others, when you compile yout program, using GNU resources:
g++ Header_files CPP_files flags ... -o program.exe recource.o -lm
For instance.

valgrind : Opening several suppression files at once

I have a script which executes my unit tests using valgrind. Now the script became big, because I have maybe 10 suppression files (one per library), and it is possible that I will have to add more suppressions files.
Now instead of having a line like this :
MEMCHECK_OPTIONS="--tool=memcheck -q -v --num-callers=24 --leak-check=full --show-below-main=no --undef-value-errors=yes --leak-resolution=high --show-reachable=yes --error-limit=no --xml=yes --suppressions=$SUPPRESSION_FILES_DIR/suppression_stdlib.supp --suppressions=$SUPPRESSION_FILES_DIR/suppression_cg.supp --suppressions=$SUPPRESSION_FILES_DIR/suppression_glut.supp --suppressions=$SUPPRESSION_FILES_DIR/suppression_xlib.supp --suppressions=$SUPPRESSION_FILES_DIR/suppression_glibc.supp --suppressions=$SUPPRESSION_FILES_DIR/suppression_glib.supp --suppressions=$SUPPRESSION_FILES_DIR/suppression_qt.supp --suppressions=$SUPPRESSION_FILES_DIR/suppression_sdl.supp --suppressions=$SUPPRESSION_FILES_DIR/suppression_magick.supp --suppressions=$SUPPRESSION_FILES_DIR/suppression_sqlite.supp --suppressions=$SUPPRESSION_FILES_DIR/suppression_ld.supp --suppressions=$SUPPRESSION_FILES_DIR/suppression_selinux.supp --suppressions=$SUPPRESSION_FILES_DIR/suppression_opengl.supp"
I tried doing like this:
MEMCHECK_OPTIONS="--tool=memcheck -q -v --num-callers=24 --leak-check=full --show-below-main=no --undef-value-errors=yes --leak-resolution=high --show-reachable=yes --error-limit=no --xml=yes --suppressions=$SUPPRESSION_FILES_DIR/*.supp"
but valgrind needs a filename (doesn't accept the asterix).
Since I am doing this in a bash script, can someone tell me what is the easiest way to form that line?
I thought about listing all files in the suppression directory, then iterating over that list, and adding --suppressions= prefix.
EDIT
I forgot to ask. This is what I have so far :
ALL_SUPPRESION_FILES=`ls $SUPPRESSION_FILES_DIR/*.supp`
but I can not find how to transfer that into an array. Can someone help?
Just do it this way:
# form the list of suppression files to pass to the valgrind
VALGRIND_SUPPRESSION_FILES_LIST=""
for SUPPRESSION_FILE in $SUPPRESSION_FILES_DIR/*.supp; do
VALGRIND_SUPPRESSION_FILES_LIST+=" --suppressions=$SUPPRESSION_FILE"
done
There's no need for ls.
Here's a way to do it without a loop:
array=($SUPPRESSION_FILES_DIR/*.supp)
VALGRIND_SUPPRESSION_FILES_LIST=${array[#]/#/--suppressions=}
Neither of these work properly if filenames contain spaces, but additional steps can take care of that.
For those who still facing this problem - have a look at Valgrind Suppression File Howto.
When valgrind runs its default tool, Memcheck, it automatically tries to read a file called $PREFIX/lib/valgrind/default.supp ($PREFIX will normally be /usr). However you can make it use additional suppression files of your choice by adding --suppressions= to your command-line invocation. You can repeat this up to 100 times, which should be sufficient for most situations ;)
Rather than having to type this each time, it's more sensible to write it to an rc file. Each time it runs, valgrind looks for options in files called ~/.valgrindrc and ./.valgrindrc. [...]
Create the files if they don't already exist. So I now have a ~/.valgrindrc containing:
--memcheck:leak-check=full
--show-reachable=yes
--suppressions=/file/path/file1.supp
--suppressions=/file/path/file2.suppth/file2.supp
To check that valgrind is actually using the suppression files, run it with the -v option. The list of suppression files read is near the beginning of the output.
Well, I managed to solve the issue this way :
# form the list of suppression files to pass to the valgrind
ALL_SUPPRESION_FILES=`ls $SUPPRESSION_FILES_DIR/*.supp`
VALGRIND_SUPPRESSION_FILES_LIST=""
for SUPPRESSION_FILE in ${ALL_SUPPRESION_FILES[#]}; do
VALGRIND_SUPPRESSION_FILES_LIST="$VALGRIND_SUPPRESSION_FILES_LIST --suppressions=$SUPPRESSION_FILE"
done
I used tokenizing strings and concanating strings to form the list.

Resources