Different offset in libc's backtrace_symbols() and libunwind's unw_get_proc_name() - stack-trace

I make a stack trace at some point in my program. Once with libc's backtrace_symbols() function and once with unw_get_proc_name() from libunwind.
backtrace_symbols() output:
/home/jj/test/mylib.so(+0x97004)[0x7f6b47ce9004]
unw_get_proc_name() output:
ip: 0x7f6b47ce9004, offset: 0x458e4
Here you see that the instruction pointer address (0x7f6b47ce9004) is the same and correct. The function offset 0x97004 from backtrace_symbols() is also correct but not the one I get from unw_get_proc_name() (0x458e4).
Does somebody have a clue what's going on here and what might cause this difference in offsets?
Both methods use a similar code like the following examples:
backtrace():
void *array[10];
size_t size;
size = backtrace(array, 10);
backtrace_symbols_fd(array, size, STDERR_FILENO);
libunwind:
unw_cursor_t cursor;
unw_context_t context;
unw_getcontext(&context);
unw_init_local(&cursor, &context);
while (unw_step(&cursor) > 0) {
unw_word_t offset, pc;
char fname[64];
unw_get_reg(&cursor, UNW_REG_IP, &pc);
fname[0] = '\0';
(void) unw_get_proc_name(&cursor, fname, sizeof(fname), &offset);
printf ("%p : (%s+0x%x) [%p]\n", pc, fname, offset, pc);
}

I think unw_get_proc_name compute offset from an unnamed internal frame.
For example:
void f() {
int i;
while (...) {
int j;
}
}
Notice there is a variable declaration inside loop block. In this case (and depending of level of optimization), compiler may create a frame (and related unwind information) for the loop. Consequently, unw_get_proc_name compute offset from this loop instead of begin of function.
This is explained in unw_get_proc_name man page:
Note that on some platforms there is no reliable way to distinguish
between procedure names and ordinary labels. Furthermore, if symbol
information has been stripped from a program, procedure names may be
completely unavailable or may be limited to those exported via a
dynamic symbol table. In such cases, unw_get_proc_name() may return
the name of a label or a preceeding (nearby) procedure.
You may try to test again but without stripping your binary (Since unw_get_proc_name is not able to find name of function, I think your binary is stripped).

Related

Dynamic generation of signal spies in testbench

I have a .txt file that contains certain signals that I want to monitor in my testbench during the application of some stimulus.
I am creating an initial block in which I am reading the file and then I try to generate a init_signal_spy() for every one of the lines that I have read.
The code that I have written up until this point has the following format:
module testbench();
logic probes[];
initial begin : read_signals_to_dump_at
automatic int fd;
automatic string fname,line,line_stripped;
if ($value$plusargs("sigfile=%s",fname)) begin : read
fd = $fopen(fname,"r");
while($fgets(line,fd)) begin
//static logic net_to_be_probed;
automatic sig_and_spy entry = new();
// Trim away the '\n' from the line.
line_stripped = line.substr(0,line.len()-2);
// Resize the array
probes = new [probes.size() + 1] (probes);
// Link the extracted new line with the probe list
// - this raises an error "An invalid empty string was passed in as the Destination object."
// - expected since the last element is empty...
$init_signal_spy(line_stripped, probes[probes.size()-1] , 1);
end
end
end : read_signals_to_dump_at
endmodule
In the code above, just before I issue the generation for the spy, I get why the error
An invalid empty string was passed in as the Destination object.
is generated by the compiler. Although the array has been resized, it does not hold any element i.e., its empty. Thus, I tried creating locally a logic variable that then I assign to the signal spy within the loop in the following manner:
module testbench();
logic probes[];
initial begin : read_signals_to_dump_at
automatic int fd;
automatic string fname,line,line_stripped;
if ($value$plusargs("sigfile=%s",fname)) begin : read
fd = $fopen(fname,"r");
while($fgets(line,fd)) begin
logic new_probe;
// Trim away the '\n' from the line.
line_stripped = line.substr(0,line.len()-2);
// Resize the array and copy old values.
probes = new [probes.size() + 1] (probes);
// Add the new probe to the Testbenchs' probes array
probes[probes.size()-1] = new_probe;
// Again, An invalid empty string was passed in as the Destination object.
$init_signal_spy(line_stripped, probes[probes.size()-1] , 1);
end
end
end : read_signals_to_dump_at
endmodule
But then again, I see the same error at runtime during the simulation. So...Is there a way of achieving such a "dynamic" signal monitoring in the testbench somehow? As far as I understood the error concerns that the destination object is NOT a signal of the testbench. Thus the logic new_probe has no effect. Which is to be expected I mean, but is there a way of achieving the desired behavior in the Testbench via sysverilog?
You have at least two problems.
Both the source and destination arguments to init_signal_spy() need to be strings. Your destination argument is an integral variable with a 0 value, and that gets interpreted as a null string. init_signal_spy() was designed for mixed language simulation, and using strings was the only way to achieve that.
Your destination variable should be queue, not a dynamic array. Every time you re-size a dynamic array, the previous elements get relocated and that breaks the previous connection made by signal spy.
This example shows the proper syntax for string this up
module top;
int A[$];
int s1,s2;
initial begin
A.push_back(0);
$init_signal_spy("s1","A[0]");
A.push_back(0);
$init_signal_spy("s2","A[1]");
#1 s1 = 1;
#1 s2 = 2;
#1 $display("%p",A);
end
endmodule
A far better solution for performance is converting your .txt file into actual SystemVerilog code that can be compiled into your testbench.

My mex function ignores my if statement

I have a mex function that takes in a field of a struct in the third input (i.e. prhs[2]), which is a boolean. If true, it will parse information from the fourth input (i.e. prhs[3]). In a nutshell, this is the code excerpt:
mxValue = mxGetField(prhs[3], 0, "change"); mxLogical *change;
change = mxGetLogicals(mxValue);
mexPrintf("true/false: %i \n", *change);
mexEvalString("drawnow;");
if ( change ) {
mexPrintf("...Parsing info... \n");
mexEvalString("drawnow;");
mxValue = mxGetField(prhs[3], 0, "info");
nRows = mxGetM(mxValue); nCols = mxGetN(mxValue);
Eigen::Map<Eigen::VectorXd> info((double *)mxGetPr(mxValue),nRows);
}
As you can see, I do a printout to see whether the input prhs[2] is true or false. Even if the function prints out false, the if statement gets executed regardless, because I can see the printout ...Parsing info....
Why is my MATLAB mex function ignoring my if statement?
C is not MATLAB! C is C!
You are checking if pointer change has a value. It does indeed have a value, a memory direction e.g. #72BA21, to the location where the value of the boolean is stored.
You can either check the contents of whats inside that specific direction if(*change) as #buzjwa suggest, or grab the information on the array, instead of a pointer to it, using mxGetData.
As a side note: learn to debug, or at least, print statements. a simple mexPrintf() call would have shown you what change contains

How to generate ascending values during randomisation

Please help to resolve one randomization-constraint related issue that I am facing.
So in my seqItem, I have a write_addr random variable. This variable controls the location in memory where the data should be written.
I want to implement different writing address changing modes like random-address, given range address, ascending and descending type.
I have params_pkg, where user defines the address change type and my TB generates write_addr values correspondingly.
I was thinking to implement this using constraints, like by enableing/disabling the constrains get the required behavioral:
class seqItem extends uvm_sequence_item;
`uvm_object_param_utils(seqItem)
randc logic [541-1:515] wfifo_addr;
if (params_pkg::writeAddressType == "WriteGivenRangeAddress") begin
constraint wArrdGivnRangCnstr {
this.wfifo_addr inside {[params_pkg::addrLowValue:params_pkg::addrHighValue]};
}
end
function new (string name="seqItem");
super.new(name);
this.wArrdGivnRangCnstr.constraint_mode(0);
endfunction
endclass
However there is no way to generate ascending or descending address values using constraints. Because to have ascending address, the seqitem code needs to know the write_addr variable value from the previous randomization, which I could not implement.
My question is: whether it is possible to have ascending write_addr values using constraints?
And second, the example code that I posted is not working, simulator gives error saying that generate constraints are not allowed. Most probably this is something not supported in System Verilog. Am I right?
Second part first: I suspect "Generate constraints" are constraints contained within a generate block. Generate blocks are only allowed within modules, programs, and checkers not classes, hence "Generate constraints" are illegal (although the term is oddly specific. I'd expect an error saying "Generates are not allowed in classes"). You can rewrite your constraints by moving the conditional inside the constraint block:
constraint wArrdGivnRangCnstr {
if (params_pkg::writeAddressType == "WriteGivenRangeAddress") {
this.wfifo_addr inside {[params_pkg::addrLowValue:params_pkg::addrHighValue]
};
}
BTW: you might want to consider an enum for the writeAddressType variable. That way typos are caught at compile time.
Another thing...
You have your random variable defined as randc.
Variables declared with the randc keyword are random-cyclic variables that cycle through all the values in a random permutation of their declared range.
If you limit the range on a randc variable, it can't "cycle through all the values...of [it's] declared range". It's not clear from the SystemVerilog LRM what will happen here, but I suspect that once all the values between low and high are exhausted randomisation will fail.
Also, the variable is 26-bits in size. That's 67,108,864 different values you're asking the simulator to keep track of to see if they've been used before. It will need 8MB of flags just for this one variable.
I expect what you really want here is to define the variable as rand and not randc.
On to your main question...
You are right, you need some kind of storage of the last value in order to get incrementing values, and because this is a sequence item I suspect that you're creating a new instance each time, hence we can't store the last value in an instance variable as all instance variables are destroyed.
So there's two options:
Store the last value in a static instance variable.
class seqItem extends uvm_sequence_item;
`uvm_object_param_utils(seqItem)
rand logic [541-1:515] write_addr;
static logic [541-1:515] last_write_addr = 0;
constraint wAddrIncr {
write_addr > last_write_addr;
}
function new (string name="seqItem");
super.new(name);
endfunction
function post_randomize();
last_write_add = write_addr;
endfunction
endclass
Add a constraint in the sequence when randomising the sequence item
class someSequence extends uvm_sequence;
...stuff omitted...
task body();
seqItem item;
seqItem last_item;
last_item = null;
repeat (4728346) begin
item = new(); // or create to use factory
if (last_item) begin
item.randomize() with {
write_addr > last_item.write_addr
};
end else begin
item.randomize();
end
last_item = item;
// Send to driver or whatever
end
endtask
endclass
Number 2 is better in my opinion, because it doesn't bake the increasing address behaviour into the sequence item. Incrementing addresses is really a property of the sequence of items, not of any single item. I can now write some sequences that have increasing addresses, decreasing addresses, or any other pattern.
One solution to your problem of generating ascending (or descending) addresses is to keep a note of the last value generated and to use this as the lower bound in the constraint:
class seqItem;
randc logic [0:15] wfifo_addr;
static logic [0:15] last_wfifo_addr = '0;
constraint wArrdGivnRangCnstr {
this.wfifo_addr inside {[last_wfifo_addr:params_pkg::addrHighValue]};
}
function void post_randomize;
last_wfifo_addr = wfifo_addr;
if (last_wfifo_addr >= params_pkg::addrHighValue)
last_wfifo_addr= params_pkg::addrLowValue;
endfunction
endclass
http://www.edaplayground.com/x/3QxX
The post_randomize function is a built-in method that can be overrided. It is called implicitly after the (built-in) randomize method. There is also a built-in pre_randomize, which of course you can override, too.
One solution to your problem of changing randomisation modes, is to turn constraints on and off:
You can turn a constraint off using the implicit constraint_mode method:
s.wArrdGivnRangCnstr.constraint_mode(0);
and then turn it on again:
s.wArrdGivnRangCnstr.constraint_mode(1);
(where s is a reference to your seqItem class). You can't put constraints inside an if statement as your error message demonstrates.

Ncurses no-wrap mode when adding strings to window

I'm adding strings to a window, with waddwstr() function, one line after other, in consecutive rows. I don't want ncurses to automatically wrap lines for me – I'm overwriting them with consecutive calls to waddwstr() and sometimes tail of previous line is left displaying. Can ncurses just stop when right edge of window is reached?
The non-wrapping functions have "ch" in their name, e.g., wadd_wchstr.
The same is true of the non-wide interfaces waddstr versus waddchstr.
However, the wrapping/non-wrapping functions differ by more than that. They use different parameter types. The wrapping functions rely upon the video attributes set via wattr_set, etc., while the non-wrapping functions combine the video-attributes with the character data:
waddstr and waddchstr use char* and chtype* parameters, respectively
waddwstr and wadd_chstr use wchar_t* and cchar_t* parameters.
Converting between the two forms can be a nuisance, because X/Open, etc., did not define functions for doing the conversion.
The manual page for bkgd describes how these video attributes are combined with the background character to obtain the actual display.
The accepted answer (by Mr. Dickey) is correct. However, the "ch" functions do not work with ordinary C strings (array of bytes). Another solution is to create a wrapper for waddstr which checks the current cursor position and window size and prints only as much as would fit.
For example:
int waddstr_trunc(WINDOW *win, const char *str)
{
int cur_x, max_x, dummy [[maybe_unused]];
getyx(win, dummy, cur_x);
getmaxyx(win, dummy, max_x);
int w=max_x - cur_x;
if (w <= 0) return 0;
char *str2 = strndup(str, w);
if (str2 == NULL) return 1;
int rv = waddstr(win, str2);
free(str2);
return rv;
}

Constraining an entire object in SystemVerilog

I'm trying to constrain an entire object (not just the fields of an object) based on some other object. Here is a stripped down version of my production code:
I have the following class:
class some_class;
bit[7:0] some_field;
bit[3:0] some_other_field;
// this function would do some complex procedural
// operations on the fields of the object
function void do_some_op();
bit[3:0] tmp = some_field[3:0];
some_field[3:0] = some_other_field;
some_other_field = some_field[7:4];
some_field[7:4] = tmp;
endfunction
function some_class some_function(bit some_param);
some_function = new this;
$display("foo"); // this print here to see that method is executed
if (some_param)
some_function.do_some_op();
endfunction
function void print();
$display("some_field = %x", some_field);
$display("some_other_field = %x", some_other_field);
endfunction
endclass // some_class
This class contains some integral fields. It also has a method that does some complex procedural on the fields of that class. In the example I've simplified it. I also have another class that returns a new object on which the operation has been performed.
I have another class that operates with some_class instances. As per Dave's input I have made it create the objects first (as randomize() does not create objects).
class some_shuffler;
rand bit params[];
rand some_class objects[];
constraint size_c {
params.size() == objects.size() - 1;
params.size() <= 10;
};
constraint shuffle_c {
// not allowed by standard
// foreach (params[i])
// objects[i+1].some_field == objects[i].some_function(params[i]);
foreach (params[i])
objects[i+1].some_field ==
objects[i].some_function(params[i]).some_field &&
objects[i+1].some_other_field ==
objects[i].some_function(params[i]).some_other_field;
};
function new();
objects = new[10]; // create more objects than needed
foreach (objects[i])
objects[i] = new();
// initialize first object
objects[0].some_field = 8'hA5;
endfunction // new
function void post_randomize();
foreach (objects[i]) begin
$display("objects[%0d]:", i);
objects[i].print();
$display("");
end
endfunction
endclass
This class has two arrays, one of operations performed and one of the intermediate states. There is an initial object. On this one, some_function is performed and it results in the next object.
This is how I wanted to test it:
module top;
import some_pkg::*;
initial begin
static some_shuffler shuffler = new();
bit rand_ok;
rand_ok = shuffler.randomize() with {
params.size() == 1;
};
assert (rand_ok);
end
endmodule
When trying to constrain the objects directly I immediately get a constraint violation. The simulator seems to try to make the 2 handles equal. This is anyway forbidden by the standard and I'm not doing it anymore (though a compile failure would have been nice). I've unraveled the constraints as suggested by Dave and Greg (I think doing some_function().some_field is non-standard, but it compiles in Questa).
Even now, the foo print does not appear on the command line (some_function() is not getting executed). What I see is that objects[1] contains the initial value (all 0s for both fields).
I can't just generate the list of params and then procedurally randomize the objects for each iteration, because I want to be able to constrain the last object to have a certain value - basically giving the constraint solver the start and the end points and let it figure out the way to get there.
Object vs. object constraints are not allowed in SystemVerilog because they are not integral types. See IEEE Std 1800-2012 § 18.3:
Constraints can be any SystemVerilog expression with variables and constants of integral type (e.g., bit, reg, logic, integer, enum, packed struct).
You can constrain the integral components of class object if the component is a rand (ex obj[1].value == obj[0].value+1;).
Functions are allowed in constraints, but there limitation. See IEEE Std 1800-2012 § 18.5.12 Functions in constraints for full details. Limitations include:
Functions cannot contain output or ref arguments
Functions should be automatic and leave no side effects
The functions arguments have an implicit priority (ex x<=F(y) infers solve y before x)
Circular dependencies will result in an error
Update:
Looks like the only thing truly being randomized is params. The values of some_field and some_other_fieldare calculations. So it makes more sense to move the loop for shuffling into thepost_randomize` function.
constraint size_c {
params.size() == objects.size() - 1;
params.size() <= 10;
};
function void postrand_shuffle();
foreach (params[i])
objects[i+1] = objects[i].some_function(params[i]);
endfunction
function void post_randomize();
postrand_shuffle();
// ... your other post_rand code...
endfunction
SystemVerilog's random constraint solver will work when there is at least one solution. However when the solution space is small and difficult to determine or a long chain, simulator performance drops. For these scenarios it is better move the one-to-one sequential calculations into post_randomize.
A couple of problems with your example code.
Objects must be constructed first before calling randomize(). If
you know the exact size before calling randomize (like in your
example), just new[n] the dynamic arrays constructing each object
element first, and remove the size constraints. If the size will be
random, you need an upper limit constraint on the size. construct the max
number of objects before calling randomize(), and after randomizing the array, the unused objects will be eliminated.
Constraint expressions must be integral. You can do objects[i+1].some_field == objects[i].some_field but the solver cannot manipulate class handles.
The return values of functions are treated as state variables. Move these to post_randomize