I'm trying to understand what this code actually does. Specifically the part after declaring and initializing the pointer ramVectorTable confuses me the most.
It is about function that sets the interrupt vector of the specified system interrupt number. It's for cypress's PsoC 5 that has ARM Cortex M3 if this helps somehow.
#define CY_INT_VECT_TABLE ((cyisraddress **) 0xe000ed08u)
typedef void (* cyisraddress)(void);
cyisraddress CyIntSetSysVector(uint8 number, cyisraddress address)
{
cyisraddress oldIsr;
cyisraddress *ramVectorTable = *CY_INT_VECT_TABLE;
/* Save old Interrupt service routine. */
oldIsr = ramVectorTable[number & CY_INT_SYS_NUMBER_MASK];
/* Set new Interrupt service routine. */
ramVectorTable[number & CY_INT_SYS_NUMBER_MASK] = address;
return (oldIsr);
}
It can be understood as follows:
cyisraddress is a function pointer (a pointer to a function). Here it has the form of a function taking no argument (void) and returning nothing (void). Since this is on ARM Cortex-M3, a pointer shall be a 4-byte value, e.g. 0x20010004. This 4-byte value is the location of the function in memory, i.e. the address of its first instruction. Here, oldIsrand address point to the existing and new ISRs (Interrupt Service Routine) respectively.
In this line #define CY_INT_VECT_TABLE ((cyisraddress **) 0xe000ed08u), 0xe000ed08u is specified to have the type of cyisraddress **, which means pointer to a pointer to a function pointer. Note that 0xe000ed08u is the address of the register VTOR (Vector Table Offset Register), which stores the offset of the vector table base address from memory address 0x00000000 (reference)
When they use *CY_INT_VECT_TABLE, it means the value stored at address 0xe000ed08, which effectively is the address of the vector table. This value has a type of pointer to a function pointer.
Now is the interesting part. For cyisraddress *ramVectorTable, the type of ramVectorTable is a pointer to a function pointer. When reading the code further, you will notice that they use ramVectorTable as an array, which is similar to this simpler version:
int a[10];
Then you can use either a[i] (a as an array of integers) or *(a+i) (a as a pointer to an integer) to access the array elements.
Therefore, ramVectorTable can be used as an array of function pointer, thus ramVectorTable[number & CY_INT_SYS_NUMBER_MASK] is just *(ramVectorTable + number & CY_INT_SYS_NUMBER_MASK), this value has the type of cyisraddress (function pointer).
Lastly, the vector table can be thought of as an array of function pointers, thus ramVectorTable is simply an array of pointers to an ISR.
As you have posted not enough code, I can only guess. The vector table was probably located in the RAM memory. The code just changes one of the addresses to point to the new interrupt handler.
Somewhere in the code the table is probably placed in the memory and it is aligned by 0x200. Another part of the code changes the value of the VTOR register to the address of this table.
Related
sqlite3_open takes a pointer to a pointer. Id like to trace the address of the second pointer.
E.g: p1(p2(obj))
https://www.sqlite.org/c3ref/open.html
int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
What is the syntax to get the address of that pointer in DTrace?
Im using the pid$target::sqlite3_open:return probe to read from the arg1 that was set from the entry probe.
Im currently using:
// Copy pointer bytes from arg1 to kernel, cast to pointer.
(uintptr_t *)copyin(arg1, sizeof(uintptr_t))
Which results in: invalid kernel access in action.
Im on MacOS with SIP enabled, is this the issue?
I may be misunderstanding your question, but what I suspect is that you've misunderstood how sqlite3_open works.
To call sqlite3_open you should have a code that looks like this:
sqlite3 * pDB = NULL;
/* ... */
int result = sqlite3_open("file:database.db", &pDB);
As you see, there's no "pointer to pointer" variable in my code. Instead, sqlite3_ope takes the address of of a pointer variable I allocated on the stack.
To copy that pointer is as simple as:
sqlite3 * pDB2 = pDB
The reason for this is simple:
The sqlite3_open function wants to return two variable, which is impossible in C.
Instead of returning two variables, sqlite3_open returns only one variable directly and returns the second variable indirectly.
In order to return the second, it takes a pointer to a variable of the same type it wants to return. Then, by dereferencing the address and filling in the value, it provides you with the second variable's value.
However, the second variable sqlite3_open returns is a pointer. This is why, in order to return a pointer as a second variable, sqlite3_open requires a pointer to a pointer variable.
Reading the address
In the example above, the pDB variable holds the address for the sqlite3 object (the one allocated by sqlite3_open).
The address, as you know, is simply a number representing a location in the memory. To read the pointer value as a number, simply cast the pointer to a uintptr_t. i.e.:
uintptr_t db_mem_addr_value = (uintptr_t)pDB;
Of course, numbers (and memory addresses) can't be printed as hex strings directly, they need a function that will convert them into hex notation.
Consider that in C you would print the memory address in Hex notation by using printf i.e.,
fprintf(stderr, "%p\n", (void *)pDB);
Using dtrace would be the same. You might want to convert the pointer address to a number, for example, using the lltostr dtrace function:
lltostr((uintptr_t)*(void**)arg1, 16)
Not a dtrace pro, but here are some observations.
uintptr_t is defined to be large enough to hold any pointer converted to an integer. Note that this does not imply that sizeof(uintptr_t) == sizeof(void*). It is perfectly valid (and on some platforms, necessary) for uintptr_t to be strictly larger than a pointer. That means your copyin call might be copying more bytes than are actually there. Try using a size of sizeof(sqlite**) instead.
Also, it's possible that some of OSX's internal protection mechanisms are causing you problems. See the answer on this related question for a good explanation.
I have a struct declared and set in memory, I have a global constant pointer to this struct and throughout my program I dereference this pointer to access the different parts of the struct. However, there are times when the pointer memory address changes when dereferenced from a specific function.
My struct
typedef struct configData_t
{
uint8_t version[4];
inputConfig_t inputModuleConfig [MAX_INPUT];
outputConfig_t outputModuleConfig [MAX_OUTPUT];
notificationConfig_t notificationConfig [MAX_NOTIFICATIONS];
functionConfig_t autoFunctionConfig [MAX_FUNCTIONS];
uint16_t Crc16;
} configData_t;
The constant pointer is declared by setting the memory address of the data (externally loaded and outside of the applications memory)
//Pointer points to memory location on uC (data already in memory)
const configData_t* theConfigData = (configData_t*)0x0460000;
To get a notification from the 'notificationConfig' array I dereference 'theConfigData' by [1]:
const notificationConfig_t *pNotificationConfig = theConfigData->notificationConfig + notificationID;
The following occurs when stepping through the code on the uC:
In function A, get notification from struct by using [1], pointer address is 0x463e18
In function A call function B, dereference the struct using [1] the address changes to 0x463e2a (This is the wrong memory address, 0x12 difference)
Function B finishes and returns to A, dereferencing theConfigData again using [1] gives 0x463e18
Every other function in the program that uses [1] always returns the correct (0x463e18) address.
Function B does not alter 'theConfigData' in any way. In the debuggers memory view, the data in 0x0460000 + sizeOf(configData_t) is not altered in any way.
How is the 'pNotificationConfig' pointer changing address when going from function A to B?
You need to make sure that :
the definition of configData_t is exactly the same in both the function A and function B compilation units
the struct padding of configData_t is exactly the same for both the function A and function B compilation units
Red flags of the above for your specific issue would be eg. :
sizeof(configData_t) is different
offsetof(configData_t, notificationConfig) is different
sizeof(notificationConfig_t) is different
If one or more of these red flags are raised (and in a comment, you confirm that), you need to determine which of the two earlier options causes it :
a difference in definition can be caught by verifying the source code :
make sure the same struct definitions are used throughout the code (typically with the use of an include file)
make sure supporting compile time values are the same (eg. array dimensions MAX_INPUT, MAX_OUTPUT, ... in your case)
a difference in padding can be caused by the use of different compilers and/or different compiler flags - refer to your compiler's documentation for details (specifically wrt. struct padding/packing)
I was watching this video about calling the bootloader using software by assigning the address of the beginning of the system memory into a function pointer and then calling it, the expression for storing the address :
sysMemBootJump = (void(*)(void))(*(u32*)0x1fff0004);
"sysMemBootJump" is the function pointer.
But what I don't understand is, why did he dereference the address of the memory before casting it to void(*)(void) ?
Because the 'real' entry point is stored at that address. Think of it as being a pointer-to-pointer-to-function, by dereferencing you get just the pointer-to-function.
This is equivalent to:
u32 ad = *(u32*)0x1fff0004;
this is fetching a word located at address 0x1fff0004
then
sysMemBootJump = (void(*)(void))ad;
So 0x1fff0004 is the address of a word containing the routine's address.
And notice that the code is very unportable. A more portable integral type castable to/from addresses is uintptr_t from <stdint.h> ....
You can typedef function signatures, like here, to write more readable code.
I reading the code below, the first segment calls read_temperature, which reads a temperature sensor.
I'm trying to understand it.
Is read_temperature() a pointer to a function? What is the benefit of this?
read_temperature takes the address of length?
Why is it necessary to initialise tempbuff[] to all zeros using memset().
What does temp_reading&0xff do?
Why is it necessary to do *templength = 5; at the end?
static int length;
static unsigned address
address = (unsigned int)read_temperature(& length);
PRINTF("Temperature [%x] and its length is [%d] \r\n",address,length);
Second segment:
uint8_t tempbuff[8];
uint8_t * read_temperature(int *templength)
{
}
No, read_temperature is an ordinary function that returns a pointer.
templength is passed as a pointer so that read_temperature can change the target in the caller, as it does at the bottom when it sets it to 5.
Since the first 5 elements are being manually set, the memset call is really only needed for the last 3 elements. It also makes it easier to adjust the portion being set without worrying about the other elements.
temp_reading&0xff is masking the low-order 8 bits of temp_reading, forcing the rest of it to 0. It's a bitwise AND operation.
As mentioned earlier, it's telling the caller how much of tempbuff is defined. The caller passes the address of an int variable, and upon return that variable contains 5.
No, read_temperature is a function that returns a pointer to an uint8_t.
As for the argument, passing arguments in C is done by value, meaning the value is copied into the argument variable. To emulate pass by reference a pointer to a variable is used, that way the function can dereference the pointer to access what the pointer is pointing to (the variable in the calling function). So when the function is doing *templength = 5 it is setting the variable length in the calling function to the value 5.
The initialization of the buffer is probably so it's no values from previous calls or calls to other functions that uses the same global buffer.
I have a
LS_Led* LS_vol_leds[10];
declared in one C module, and the proper externs in the other modules that access it.
In func1() I have this line:
/* Debug */
LS_Led led = *(LS_vol_leds[0]);
And it does not cause an exception. Then
I call func2() in another C module (right after above line), and do the same line, namely:
/* Debug */
LS_Led led = *(LS_vol_leds[0]);`
first thing, and exception thrown!!!
I don't think I have the powers to debug this one on my own.
Before anything LS_vol_leds is initialized in func1() with:
LS_vol_leds[0] = &led3;
LS_vol_leds[1] = &led4;
LS_vol_leds[2] = &led5;
LS_vol_leds[3] = &led6;
LS_vol_leds[4] = &led7;
LS_vol_leds[5] = &led8;
LS_vol_leds[6] = &led9;
LS_vol_leds[7] = &led10;
LS_vol_leds[8] = &led11;
LS_vol_leds[9] = &led12;
My externs look like
extern LS_Led** LS_vol_leds;
So does that lead to disaster and I how do I prevent disaster?
Thanks.
This leads to disaster:
extern LS_Led** LS_vol_leds;
You should try this instead:
extern LS_Led *LS_vol_leds[];
If you really want to know why, you should read Expert C Programming - Deep C Secrets, by Peter Van Der Linden (amazing book!), especially chapter 4, but the quick answer is that this is one of those corner cases where pointers and arrays are not interchangeable: a pointer is a variable which holds the address of another one, whereas an array name is an address. extern LS_Led** LS_vol_leds; is lying to the compiler and generating the wrong code to access LS_vol_leds[i].
With this:
extern LS_Led** LS_vol_leds;
The compiler will believe that LS_vol_leds is a pointer, and thus, LS_vol_leds[i] involves reading the value stored in the memory location that is responsible for LS_vol_leds, use that as an address, and then scale i accordingly to get the offset.
However, since LS_vol_leds is an array and not a pointer, the compiler should instead pick the address of LS_vol_leds directly. In other words: what is happening is that your original extern causes the compiler to dereference LS_vol_leds[0] because it believes that LS_vol_leds[0] holds the address of the pointed-to object.
UPDATE: Fun fact - the back cover of the book talks about this specific case:
So that's why extern char *cp isn't the same as extern char cp[]. I
knew that it didn't work despite their superficial equivalence, but I
didn't know why. [...]
UPDATE2: Ok, since you asked, let's dig deeper. Consider a program split into two files, file1.c and file2.c. Its contents are:
file1.c
#define BUFFER_SIZE 1024
char cp[BUFFER_SIZE];
/* Lots of code using cp[i] */
file2.c
extern char *cp;
/* Code using cp[i] */
The moment you try to assing to cp[i] or use cp[i] in file2.c will most likely crash your code. This is deeply tight into the mechanics of C and the code that the compiler generates for array-based accesses and pointer-based accesses.
When you have a pointer, you must think of it as a variable. A pointer is a variable like an int, float or something similar, but instead of storing an integer or a float, it stores a memory address - the address of another object.
Note that variables have addresses. When you have something like:
int a;
Then you know that a is the name for an integer object. When you assign to a, the compiler emits code that writes into whatever address is associated with a.
Now consider you have:
char *p;
What happens when you access *p? Remember - a pointer is a variable. This means that the memory address associated with p holds an address - namely, an address holding a character. When you assign to p (i.e., make it point to somewhere else), then the compiler grabs the address of p and writes a new address (the one you provide it) into that location.
For example, if p lives at 0x27, it means that reading memory location 0x27 yields the address of the object pointed to by p. So, if you use *p in the right hand side of an assignment, the steps to get the value of *p are:
Read the contents of 0x27 - say it's 0x80 - this is the value of the pointer, or, equivalently, the address of the pointed-to object
Read the contents of 0x80 - this finally gives you *p.
What if p is an array? If p is an array, then the variable p itself represents the array. By convention, the address representing an array is the address of its first element. If the compiler chooses to store the array in address 0x59, it means that the first element of p lives at 0x59. So when you read p[0] (or *p), the generated code is simpler: the compiler knows that the variable p is an array, and the address of an array is the address of the first element, so p[0] is the same as reading 0x59. Compare this to the case for which p is a pointer.
If you lie to the compiler, and tell it you have a pointer instead of an array, the compiler will (wrongly) generate code that does what I showed for the pointer case. You're basically telling it that 0x59 is not the address of an array, it's the address of a pointer. So, reading p[i] will cause it to use the pointer version:
Read the contents of 0x59 - note that, in reality, this is p[0]
Use that as an address, and read its contents.
So, what happens is that the compiler thinks that p[0] is an address, and will try to use it as such.
Why is this a corner case? Why don't I have to worry about this when passing arrays to functions?
Because what is really happening is that the compiler manages it for you. Yes, when you pass an array to a function, a pointer to the first element is passed, and inside the called function you have no way to know if it is a "real" array or a pointer. However, the address passed into the function is different depending on whether you're passing a real array or a pointer. If you're passing a real array, the pointer you get is the address of the first element of the array (in other words: the compiler immediately grabs the address associated to the array variable from the symbol table). If you're passing a pointer, the compiler passes the address that is stored in the address associated with that variable (and that variable happens to be the pointer), that is, it does exactly those 2 steps mentioned before for pointer-based access. Again, note that we're discussing the value of the pointer here. You must keep this separated from the address of the pointer itself (the address where the address of the pointed-to object is stored).
That's why you don't see a difference. In most situations, arrays are passed around as function arguments, and this rarely raises problems. But sometimes, with some corner cases (like yours), if you don't really know what is happening down there, well.. then it will be a wild ride.
Personal advice: read the book, it's totally worth it.