GDB: How to convert enum value to string in GDB script - arrays

I have the following enum in my code:
enum myenum {
ready,
waiting,
stopping,
};
then I have a struct like so:
typedef struct {
int a;
int b;
uint8 step; // this is set using myenum.
} mystruct;
During GDB debugging session I am trying to declare an array of strings and then use its index to convert to string but running into couple of issues:
It requires me to keep the array elements to be of the same size:
(gdb) set $step_str={"ready", "waiting", "stopping"}
array elements must all be the same size
If I fix #1 by adding spaces and make all strings of same size then printf doesn't work with it:
(gdb) set $step_str={"ready ", "waiting ", "stopping"}
(gdb) printf "step=%s", $step_str[0]
Attempt to take address of value not located in memory.
The only way I could make it work is by using output command but the problem with output also is that if I end up adding a lot of spaces to a particular string then it is printed like this:
(gdb) set $step_str={"ready ", "this_is_a_long_enum_symbol"}
(gdb) output $step_str[0]
"ready", ' ' <repeats 21 times>
Having "' ' <repeats 21 times>" doesn't look nice and a bit confusing to the new readers of my output. I am trying to do this with a lot of enums and trying to gather debug info using GDB scripts on a core dump.
Another solution I thought of was to declare a helper command and make it set a variable but that becomes really long if I have several enums. For example:
define enum2str
if $arg0 == 0
set $retval="ready"
end
if $arg0 == 1
set $retval="this_is_a_long_enum_symbol"
end
... and so on but this will grow crazy if I have 20 enum values ...
Is there a better way to convert enum value to string? So I don't have to add those spaces to make array of same size elements and don't get that in my output?
Thanks much in advance!

I believe the $_as_string convenience function is what you're after.
$_as_string(value)
Return the string representation of value.
This function is useful to obtain the textual label (enumerator) of an
enumeration value. For example, assuming the variable node is of an
enumerated type:
(gdb) printf "Visiting node of type %s\n", $_as_string(node)
Visiting node of type NODE_INTEGER

Related

Segmentation fault when trying to check command line arguments (in C)

I wanted to give several arguments in the command line, like:
./programName -a 103 -p argument1,argument2,argument3
Then, I wanted to create several variables with values of these arguments: one integer variable for the number just after the flag -a, one integer variable for the number of arguments just after the flag -p and one array variable with all these arguments.
It would be always the same arguments (so my code can not manage other forms of input): -a (integer) -p (a list of arguments separated with ,)
My problem is that there is a segmentation fault. After several attempts to see where it occurs (using several printf), there is a segmentation fault when the variable a = 3 (so at the flag -p). And the segmentation occurs at the line "case 'p'".
I don't understand why this code accepts the argument "-a" but not "-p". And I don't think there is an error because of my code in the "case 'p'" because the segmentation fault occurs after that (on the line "case 'p'").
I hope you'll understand my problem and thank you for your help :).
EDIT:
Thanks to Mark Wilkins and ooga for their answers. The segmentation fault was indeed due to the individual elements of the array which wasn't initialized.
If some people don't know how to efficiently initialize an array of strings, check this other question, it's well explained ;) :
Initialize array of strings
One issue that would result in a segmentation fault is the use of arg_p. It is declared as an array of char*, but the individual elements of the array are never initialized. The subsequent use of it will result in accessing an uninitialized pointer:
*(arg_p[b]+c) = *(chrp+c);
Your segfault occurs whilst assembling your argument array. Try this instead:
arg_p[0] = chrp;
chrp2 = strchr(argv[a+1], ',');
int b = 1;
while (chrp2 != NULL) {
*chrp2 = '\0';
arg_p[b++] = chrp2 + 1;
chrp2 = strchr(chrp2 + 1, ',');
}
Also note that your arg_p array is declared locally to that block and will cease to exist after that block. You may want to declare a char** arg_p pointer and malloc the space. Remember to free it at the end.
When you increment 'a' by 2, you're going to go off the end of the argv array. You only want to increment by 1 because it's indexing the words in the command line (separated by spaces) not the characters.

memset() not setting memory in c

I apologize if my formatting is incorrect as this is my first post, I couldn't find a post on the site that dealt with the same issue I am running into. I'm using plain C on ubuntu 12.04 server. I'm trying to concatenate several strings together into a single string, separated by Ns. The string sizes and space between strings may vary, however. A struct was made to store the positional data as several integers that can be passed to multiple functions:
typedef struct pseuInts {
int pseuStartPos;
int pseuPos;
int posDiff;
int scafStartPos;
} pseuInts;
As well as a string struct:
typedef struct string {
char *str;
int len;
} myString;
Since there are break conditions for the concatenated string multiple nodes of a dynamically linked list were assembled containing an identifier and the concatenated string:
typedef struct entry {
myString title;
myString seq;
struct entry *next;
} entry;
The memset call is as follows:
} else if ((*pseuInts)->pseuPos != (*pseuInts)->scafStartPos) {
(*pseuEntry)->seq.str = realloc ((*pseuEntry)->seq.str, (((*pseuEntry)->seq.len) + (((*pseuInts)->scafStartPos) - ((*pseuInts)->pseuPos)))); //realloc the string being extended to account for the Ns
memset (((*pseuEntry)->seq.str + ((*pseuEntry)->seq.len)), 'N', (((*pseuInts)->scafStartPos) - ((*pseuInts)->pseuPos))); //insert the correct number of Ns
(*pseuEntry)->seq.len += (((*pseuInts)->scafStartPos) - ((*pseuInts)->pseuPos)); //Update the length of the now extended string
(*pseuInts)->pseuPos += (((*pseuInts)->scafStartPos) - ((*pseuInts)->pseuPos)); //update the position values
}
These are all being dereferenced as this else if decision is in a function being called by a function called from main, but the changes to the pseuEntry struct need to be updated in main so as to be passed to another function for further processing.
I've double checked the numbers being used in pseuInts by inserting some printf commands and they are correct in the positioning of how many Ns need to be added, even as they change between different short strings. However, when the program is run the memset only inserts Ns the first time it's called. IE:
GATTGT and TAATTTGACT are separated by 4 spaces and they become:
GATTGTNNNNTAATTTGACT
The second time it is called on the same concatenated string it doesn't work though. IE:
TAATTTGACT and TCTCC are separated by 6 spaces so the long string should become:
GATTGTNNNNTAATTTGACTNNNNNNTCTCC
but it only shows:
GATTGTNNNNTAATTTGACTTCTCC
I've added printfs to display the concatenated string immediately before and after the memset and the they are identical in output.
Sometimes the insertion is adding extra character spaces, but not initializing them so they print nonsense (as would be expected). IE:
GAATAAANNNNNNNNNNNNNNNNN¬GCTAATG
should be
GAATAAANNNNNNNNNNNNNNNNNGCTAATG
I've switched the memset with a for or a while loop and I get the same result. I used an intermediate char * to realloc and still get the same result. I'm looking for for suggestions as to where I should look to try and detect the error.
If you are okay with considering a completely different approach, I would like to offer this:
I understand your intent to be: Replace existing spaces between two strings with an equal number of "N"s. memset() (and associated memory allocations) is the primary method to perform the concatenations.
The problems you have described with your current concatenation attempts are :
1) garbage embedded in resulting string.
2) writing "N" in some unintended memory locations.
3) "N" not being written in other intended memory locations.
Different approach:
First: verify that the memory allocated to the string being modified is sufficient to contain results
second: verify all strings to be concatenated are \0 terminated before attempting concatenation.
third: use strcat(), and a for(;;) loop to append all "N"s, and eventually, subsequent strings.
eg.
for(i=0;i<numNs;i++)//compute numNs with your existing variables
{
strcat(firstStr, "N");//Note: "N" is already NULL term. , and strcat() also ensures null term.
}
strcat(firstStr, lastStr); //a null terminated concatenation
I know this approach is vastly different from what you were doing, but it does address at least the issues identified from your problem statement. If this makes no sense, please let me know and I will address questions as I am able to. (currently have other projects going on)
Looking at your memset:
memset (((*pseuEntry)->seq.str + ((*pseuEntry)->seq.len))), ...
That's the destination. Shouldn't it be:
(memset (((*pseuEntry)->seq.str + ((*pseuEntry)->seq.len) + ((*pseuEntry)->seq.pseuStartPos))
Otherwise I'm missing the meaninging of pseuInts .

GDB reports "no symbol in current context" upon array initialization

I am attempting to initialize an array with a size of ceil(buflen/125.0) as follows:
long long maxjpg = ceil(buflen/125.0);
long long arr[maxjpg];
I do not receive a compiler error, but GDB reports "no symbol 'arr' in current context". The only fix I have found is by hardcoding a numerical value into the array size like so:
long long arr[5];
I have tried casting, using different variable types, using const and any combination of these approaches. I know that ceil returns a double, I have tried working with that too.
Initializing a value and printing it like so works:
arr[0] = 25;
printf(pos 0 is %d\n", arr[0]);
output: pos 0 is 25
Printing arr[0] through GDB after that modification results in "value has been optimized out".
Minimum viable code to reproduce:
#include <math.h>
int main(void){
long long size = ceil(123.45);
long long arr[size];
return 0;
}
GDB Fedora 7.4.50.20120120-52.fc17
VLAs do not currently work in gdb. There's a bug open about it and an ongoing project to fix it: https://sourceware.org/gdb/wiki/VariableLengthArray
There's an implementation in archer.git that works in some cases, but it isn't considered good enough to go in trunk.

How to write into a char array in C at specific location using sprintf?

I am trying to port some code written in MATLAB to C, so that I can compile the function and execute it faster (the code is executed very often and it would bring a significant speed increase).
So basically what my MATLAB code does it that it takes a matrix and converts it to a string, adding brackets and commas, so I can write it to a text file. Here's an idea of how this would work for a vector MyVec:
MyVec = rand(1,5);
NbVal = length(MyVec)
VarValueAsText = blanks(2 + NbVal*30 + (NbVal-1));
VarValueAsText([1 end]) = '[]';
VarValueAsText(1 + 31*(1:NbVal-1)) = ',';
for i = 1:NbVal
VarValueAsText(1+(i-1)*31+(1:30)) = sprintf('%30.15f', MyVec(i));
end
Now, how can I achieve a similar result in C? It doesn't seem too difficult, since I can calculate in advance the size of my string (char array) and I know the position of each element that I need to write to my memory area. Also the sprintf function exists in C. However, I have trouble understanding how to set this up, also because I don't have an environment where I can learn easily by trial and error (for each attempt I have to recompile, which often leads to a segmentation fault and MATLAB crashing...).
I hope someone can help even though the problem will probably seem trivial, but I have have very little experience with C and I haven't been able to find an appropriate example to start from...
Given an offset (in bytes) into a string, retrieving a pointer to this offset is done simply with:
char *ptr = &string[offset];
If you are iterating through the lines of your matrix to print them, your loop might look as follow:
char *ptr = output_buffer;
for (i = 0; i < n_lines; i++) {
sprintf (ptr, "...", ...);
ptr = &ptr[line_length];
}
Be sure that you have allocated enough memory for your output buffer though.
Remember that sprintf will put a string-terminator at the end of the string it prints, so if the string you "print" into should be longer than the string you print, then that won't work.
So if you just want to overwrite part of the string, you should probably use sprintf to a temporary buffer, and then use memcpy to copy that buffer into the actual string. Something like this:
char temp[32];
sprintf(temp, "...", ...);
memcpy(&destination[position], temp, strlen(temp));

Constants in C pros/cons [duplicate]

At the end of the article here: http://www.learncpp.com/cpp-tutorial/45-enumerated-types/, it mentions the following:
Finally, as with constant variables, enumerated types show up in the debugger, making them more useful than #defined values in this regard.
How is the bold sentence above achieved?
Thanks.
Consider this code,
#define WIDTH 300
enum econst
{
eWidth=300
};
const int Width=300;
struct sample{};
int main()
{
sample s;
int x = eWidth * s; //error 1
int y = WIDTH * s; //error 2
int z = Width * s; //error 3
return 0;
}
Obviously each multiplication results in compilation-error, but see how the GCC generates the messages for each multiplication error:
prog.cpp:19: error: no match for
‘operator*’ in ‘eWidth * s’
prog.cpp:20: error: no match for
‘operator*’ in ‘300 * s’
prog.cpp:21: error: no match for
‘operator*’ in ‘Width * s’
In the error message, you don't see the macro WIDTH which you've #defined, right? That is because by the time GCC makes any attempt to compile the line corresponds to second error, it doesn't see WIDTH, all it sees only 300, as before GCC compiles the line, preprocessor has already replaced WIDTH with 300. On the other hand, there is no any such thing happens with enum eWidth and const Width.
See the error yourself here : http://www.ideone.com/naZ3P
Also, read Item 2 : Prefer consts, enums, and inlines to #defines from Effective C++ by Scott Meyers.
enum is compile time constant with debug info with no storage allocation.
const is allocated with a storage, depending on whether it is optimised away by the compiler with constant propagation.
#define has no storage allocation.
#define values are replaced by the pre-processor with the value they are declared as, so in the debugger, it only sees the value, not the #defined name, e.g. if you have #define NUMBER_OF_CATS 10, in the debugger you'll see only 10 (since the pre-processor has replaced every instance of NUMBER_OF_CATS in your code with 10.
An enumerated type is a type in itself and the values are constant instances of this type, and so the pre-processor leaves it alone and you'll see the symbolic description of the value in the debugger.
The compiler stores enum information in the binary when the program is compiled with certain options.
When a variable is of a enum type, a debugger can show the enum name. This is best shown with an example:
enum E {
ONE_E = 1,
};
int main(void)
{
enum E e = 1;
return 0;
}
If you compile that with gcc -g you can try out the following in gdb:
Reading symbols from test...done.
(gdb) b main
Breakpoint 1 at 0x804839a: file test.c, line 8.
(gdb) run
Starting program: test
Breakpoint 1, main () at test.c:7
7 enum E e = 1;
(gdb) next
9 return 0;
(gdb) print e
$1 = ONE_E
(gdb)
If you used a define, you would not have a proper type to give e, and would have to use an integer. In that case, the compiler would print 1 instead of ONE_E.
The -g flag asks gdb to add debugging information to the binary. You can even see that it is there by issuing:
xxd test | grep ONE_E
I don't think that this will work in all architectures, though.
At least for Visual Studio 2008 which I currently have at hand, this sentence is correct. If you have
#define X 3
enum MyEnum
{
MyX = 3
};
int main(int argc, char* argv[])
{
int i = X;
int j = (int)MyX;
return 0;
}
and you set a breakpont in main, you can hover your mouse over "MyX" and see that it evaluates to 3. You do not see anything useful if you hover over X.
But this is not a language property but rather IDE behavior. Next versions might do it differently, as well as others IDEs. So just check it out for your IDE to see if this sentence applies in your case.
I am answering too late but i feel i can add something -
enum vs. const vs. #define
enum -
Does not require assining values (if just want to have sequential values 0, 1, 2..) whereas in case of #defines you manually need to manage values which could cause human error sometime
It works just as variable to during online debugging the value of enum can be watched in watch window
You can have a variable of enum type to which you can assign an enum
typedef enum numbers
{
DFAULT,
CASE_TRUE,
CASE_OTHER,
};
int main(void)
{
numbers number = CASE_TRUE;
}
const -
It is constant stored in read only area of memory but can be accessed using address which is not possible in case of #define
You have type check in your hand if you use const rather than #define
defines are pre-processing directive but const is compile time
for example
const char *name = "vikas";
You can access the name and use its base address to read the such as vikas[3] to read 'a' etc.
#defines -
are dumb preprocessor directives which does textual replacement
Check the following article, nice summary
http://www.queryhome.com/26340/define-vs-enum-vs-constant

Resources