how it is that pointer to struct shows the wrong values? - c

I use ARM-M4 with GCC for ARM (10_2021.10)
I have a problem where a pointer to struct displays the wrong values.
__copy_table_start__ is define in the linker file, I see it's location in the map file and this is how I found it's true value (and the values make sense, they are correct)
Here is my code
#pragma GCC optimize("O0")
static void DataInit(void)
{
typedef struct {
uint32_t const* src;
uint32_t* dest;
uint32_t wlen;
} __copy_table_t;
extern const __copy_table_t __copy_table_start__;
extern const __copy_table_t __copy_table_end__;
extern const __zero_table_t __zero_table_start__;
extern const __zero_table_t __zero_table_end__;
static volatile __copy_table_t const* pTable;
pTable = &__copy_table_start__;
for (; pTable < &__copy_table_end__; ++pTable) {
for(uint32_t i=0u; i<pTable->wlen; ++i) {
pTable->dest[i] = pTable->src[i];
}
}
}
And what I see in the debugger, right after pTable = &__copy_table_start__; is that:
__copy_table_start__.src = 0x14A0D380
__copy_table_start__.dest = 0x00100000
__copy_table_start__.wlen = 0x38A
pTable->src = 0x14A0D380
pTable->dest = 0x14A0D380
pTable->wlen = 0x14A0D380
How can that be?
UPDATE:
I did another experiment, I created another struct variable and a pointer to that variable and get the same results. first time I see this kind of behavior.
const __copy_table_t mine = {(uint32_t const*)0x12345678, (uint32_t *)0x00004545, 0x89890000};
static volatile __copy_table_t const* my_ptr;
my_ptr = &mine;
The result is that my_ptr->src = my_ptr->dest = my_ptr->wlen = 0x12345678

Apparently the problem is with Keil (the IDE).
It displays the wrong values.
When I created 3 new parameters and loaded the data to them:
my_src = (uint32_t)pTable->src;
my_dest = (uint32_t)pTable->dest;
my_len = (uint32_t)pTable->wlen;
Those parameters got the correct values.
What threw me off was that doing a single step in debug skipped the entire for loop (the first one), as if the internal for loop didn't do anything. It actually did what it was supposed to do, but one parameter that was supposed to be reset after that didn't update in the IDE.

Related

C Unit Test: stub a constant structure (gcc --wrap)

Hi All here is my specific case:
service.h:
typedef struct {
uint8_t (*function1)(void);
uint8_t (*function2)(void);
} const service_struct_t;
extern service_struct_t service_api ;
service.c:
#include "service.h"
static uint8_t foo(void){
return 13+6;
}
static uint8_t bar(void){
return 7*6;
}
service_struct_t service_api = {
.function1 = foo,
.function2 = bar,
};
I need to stub (to mock, to replace) these functions but I have no right to change that original code. I'm using gcc to compile the unit tests. I've failed to:
use the --wrap option of gcc straight on foo and bar since they are static to source.c :
#include "service.h"
#define ENABLE_STUB 1 /* that is actually a variable toggled at runtime */
uint8_t __real_foo(void);
uint8_t __wrap_foo(void){
if(ENABLE_STUB){
return 1;
}else{
return __real_foo();
}
}
/* same for bar */
use the --wrap option of gcc onto the service_api object symbol because it's not a function
#include "service.h"
#define ENABLE_STUB 1 /* that is actually a variable toggled at runtime */
uint8_t __real_service_api ;
uint8_t __wrap_service_api = {
.function1 = foo,
.function2 = bar,
}
static uint8_t foo(void){
if(ENABLE_STUB){
return 1;
}else{
return __real_service_api.function1();
}
}
/* same for bar */
simply reassign the service_api member functions since the structure is constant and already assigned.
#include "service.h"
#define ENABLE_STUB 1 /* that is actually a variable toggled at runtime */
service_struct_t backup_service_api = {
.function1 = service_api.function1;
.function2 = service_api.function2;
}
service_struct_t stub_service_api = {
.function1 = foo;
.function2 = bar;
}
uint8_t foo(void){
if(ENABLE_STUB){
return 1;
}else{
return __real_foo();
}
}/* same for bar */
void service_poke_stub(bool_t enable_stubs){
if(enable_stubs){
service_api.function1 = stub_service_api.function1
service_api.function2 = stub_service_api.function2
}else{
service_api.function1 = backup_service_api.function1
service_api.function2 = backup_service_api.function2
}
}
thanks already for your help
You can't mock the functions in the structure, as you already found out.
So it depends on what you like to test:
If you want to test whether the structure contains the correct functions, the module service.c is your module-under-test and should be used as is. You need to check the correctness by watching what is done by the functions.
If you want to test that the structure is used correctly, you will mock the whole module. Now you are free to put in it whatever you want.
If your source code does not allow this, the design is bad for testing. This is often the case when the architecture is not done with testability in mind.

Pointer assignment truncates the pointer from 64bit to 32bit

I have been trying to modify a piece of code in likewise-open and am totally stumped here.
Some background
Working on this file, trying to code around some LDAP queries:
typedef void *MYH;
typedef MYH HANDLE;
HANDLE hDirectory = NULL;
hDirectory = LsaDmpGetLdapHandle(pConn);
The LsaDmpGetLdapHandle() is defined here
typedef void *MYH;
typedef MYH HANDLE;
HANDLE
LsaDmpGetLdapHandle(
IN PLSA_DM_LDAP_CONNECTION pConn
)
{
return pConn->hLdapConnection;
}
where PLSA_DM_LDAP_CONNECTION is typedef for following struct:
struct _LSA_DM_LDAP_CONNECTION
{
...
// NULL if not connected
HANDLE hLdapConnection;
...
};
Basically, there is HANDLE type everywhere.
Note: Just to avoid various *.h files defining it differently, I added that typedef void *MYH; in both files
The trouble:
The code would crash after the line where hDirectory is assigned from what is returned by LsaDmpGetLdapHandle and I try to further use hDirectory
What I have debugged, till now:
Attaching gdb, hLdapConnection in pConn is:
(gdb) p pConn->hLdapConnection
$5 = (void *) 0x7feb939d6390
However, hDirectory is:
(gdb) p hDirectory
$6 = (void *) 0xffffffff939d6390
I fail to understand why the difference, after assignment ??
Also, to note, the 939d6390 in both the pointer addresses is common.
Interestingly, both of these approaches work
// If I pass hDirectory reference
LsaDmLdapGetHandle(pConn, &hDirectory);
// where this function is defined as, in the other file:
DWORD
LsaDmLdapGetHandle(
IN PLSA_DM_LDAP_CONNECTION pConn,
OUT HANDLE* phDirectory)
{
HANDLE hDirectory = NULL;
hDirectory = LsaDmpGetLdapHandle(pConn);
*phDirectory = hDirectory;
return ERROR_SUCCESS;
}
// Or I call another function, which then call LsaDmpGetLdapHandle(), in the other file
hDirectory = LsaDmLdapGetHandleCopy(pConn);
HANDLE
LsaDmLdapGetHandleCopy(
IN PLSA_DM_LDAP_CONNECTION pConn)
{
HANDLE hDirectory = NULL;
hDirectory = LsaDmpGetLdapHandle(pConn);
return hDirectory;
}
I thought, maybe something to do with HANDLE definitions being different in those 2 files, hence I added my own void * definitions in both files
Looks like dup of this
By default all return values are int. So if a prototype is missing for function then compiler treats the return value as 32-bit and generates code for 32-bit return value. Thats when your upper 4 bytes gets truncated.

Trouble Including Externally Declared Enumeration - C Code

Update: The issue is resolved. Here is code that compiles properly.
---instruction.h---
#ifndef INSTRUCTION_H
#define INSTRUCTION_H
typedef enum OPCODE {ADD = 0x20,ADDI = 0x8,SUB = 0x22,MULT = 0x18,BEQ = 0x4,LW = 0x23,SW = 0x2B} opcode;
/*opcode is OPCODEs alias*/
typedef struct INSTRUCTION {
opcode op;
int rs;
int rt;
int rd;
int Imm;
} inst;
/*inst is INSTRUCTIONs alias*/
#endif // INSTRUCTION_H
---parser.c---
#include <stdio.h>
#include "instruction.h"
void parser(char *instruction)
{
/*Parse character string into instruction components*/
inst set1 = {LW,0,1,2,0};
printf("parsing");
};
int main()
{
char *instruction;
instruction = NULL;
parser(instruction);
};
/*pass in pointer for instruction being passed in*/
/*pointing to address of instruction being passed in*/
/*Parser return type is struct inst*/
I cannot seem to get my enumeration type "opcode" to be recognized in my main c file. I included the header file. I am fairly new to C, so haven't made much ground on the issue for some time now and wanted to see if anyone knew why I was getting the error messages below. My guess is the linking the header file is not working properly. Any help is much appreciated.
---instruction.h----
#ifndef INSTRUCTION_H
#define INSTRUCTION_H
typedef enum {add = 32,addi = 8,sub = 34,mult = 24,beq = 4,lw = 35,sw = 43}opcode;
extern opcode oper;
typedef struct {
opcode op;
int rs;
int rt;
int rd;
int Imm;
}inst;
#endif // INSTRUCTION_H
---Parser.c---
#include <stdio.h>
#include "instruction.h"
void parser(char *inst)
{
/*Parse character string into instruction components*/
struct inst{lw,0,1,2,0};
};
int main()
{
char *instruction;
instruction = NULL;
parser(instruction);
};
struct inst{lw,0,1,2,0};
This looks like it's supposed to be a variable declaration, but I don't see a name for the variable. Try:
struct inst name_of_the_variable = {lw,0,1,2,0};
As a side note, enum values are global constants, so it's probably not a good idea to give them names like lw that can be confused for variables. Standard practice would be to use all-caps for the names and give them a prefix… say, OPCODE_ADD, OPCODE_LW, etc.
This is not a valid variable definition:
struct inst{lw,0,1,2,0};
There's no struct inst defined, only inst, there's no variable name, and you need = to use an initializer. To create a variable of this type an initialize it, you need:
inst myinst = {lw,0,1,2,0};
Also, your function has a parameter named inst which masks the type inst. You need to give it a different name:
void parser(char *instruction)

Safe usage of longjmp/setjmp with volatile

I consider to use a TRY/CATCH macro based on setjmp/longjmp for error handling. Otherwise some of my quite structued functions will be blown up by ugly if statements and loop flags.
The code is like this example:
int trycatchtest(int i)
{
int result = 0;
volatile int error = 100;
volatile uint32_t *var = NULL;
TRY
{
error = 0;
var = os_malloc(4);
*var = 11;
if (i) THROW( i );
}
FINALLY
{
result = *var;
}
END;
return result;
}
THROW is in fact the macro
#define TRY do { jmp_buf buf; switch( setjmp(buf) ) { case 0: while(1) {
#define FINALLY break; } default: {
#define END break; } } } while(0)
#define THROW(x) longjmp(buf, x)
The Problem:
When the exception is thrown (e.g. i=1) the pointer var is reset to NULL, although I used the volatile keyword, which should avoid using a register for it. From the debugger I see that is is still within a register and not in memory.
Did I make a mistake ?
EDIT:
I changed declaration of var into
uint32_t * volatile var = NULL;
This works ;-)
I do not really understand what is the difference:
volatile uint32_t * var = NULL;
means, that the VALUE is volatile, whereas the former declararation makes the pointer volatile?
u32 *volatile var makes the pointer volatile, while volatile u32 *var tells the compiler that the data at that address is volatile. So since the pointer is not volatile in the latter example, I wouldn't be surprised if your compiler optimized away the default case completely to something like result = NULL;.
It probably doesn't expect the setjmp wizardry, and these are notorious for being even "more spaghetti than goto".

Unable to pass C struct into function

I'm having trouble passing a struct into a function and I am running into an error:
'PWM_PINS' undeclared (first use in this function)
I am typically able to do this in a C++ compiler without any trouble. I would appreciate some advice as to what I might be doing wrong here.
I have included the relevant parts from the header and c file below.
pwm.h file:
typedef struct PWM_tag{
int PWM_1;
int PWM_2;
int PWM_3;
int PWM_4;
int PWM_5;
int PWM_6;
} PWM;
void PWM_Set( uint32_t channelNum, uint32_t cycle, PWM PWN_PINS );
pwm.c file:
#include "pwm.h"
void PWM_Set( uint32_t ChannelNum, uint32_t cycle, PWM PWN_PINS)
{
if ( ChannelNum == 1 )
{
LPC_PWM1->MR0 = cycle;
LPC_PWM1->MR1 = PWM_PINS.PWM_1;
LPC_PWM1->MR2 = PWM_PINS.PWM_2;
LPC_PWM1->MR3 = PWN_PINS.PWM_3;
LPC_PWM1->MR4 = PWM_PINS.PWM_4;
LPC_PWM1->MR5 = PWM_PINS.PWM_5;
LPC_PWM1->MR6 = PWM_PINS.PWM_6;
}
return;
}
You declared a parameter called PWN_PINS (with an N), but you are referring to PWM_PINS (with an M).
Fixing this typo will address this particular error. There may be more errors, though - it's hard to tell, because the snippet does not show essential parts, such as the declaration of LPC_PWM1 variable.
Is there misspelling in the code?
The function parameter is PWN_PINS.But the code have 5 PWM_PINS, and one PWN_PINS.
I think what you should do is to change all PWN_PINS to PWM_PINS.

Resources