Get size of mmaped shared memory - linux

I'm debugging some odd fails with reading from shared memory, and for debugging purposes I'd like to put some prints that show me currently mmaped size. So, for example, I have this code:
#include <cstdio>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <utility>
std::pair<int, void*> make_shm() {
const int shm = shm_open("foo", O_RDONLY | O_CREAT, S_IRWXO | S_IRWXG | S_IRWXU);
if (shm == -1) {
perror("connect_to_shm: shm_open failed");
return {-1, nullptr};
}
void* shm_ptr = mmap(nullptr, 15360000, PROT_READ, MAP_SHARED, shm, 0);
if (shm_ptr == MAP_FAILED) {
perror("connect_to_shm: mmap failed");
close(shm);
return {-1, nullptr};
}
return {shm, shm_ptr};
}
int main() {
auto [shm, shm_ptr] = make_shm();
// how do I print the mmapped size?
}
How do I derive the 15360000 size from the shm and shm_ptr?
I tried searching, but all results I'm getting for "get size of shared memory" are either about memory limits, or about sizes of pages. The closest I found was this question, but it's for Solaris and unanswered anyway.

Related

Crash system when the module is running

I need to write a module that creates a file and outputs an inscription with a certain frequency. I implemented it. But when this module is running, at some point the system crashes and no longer turns on.
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/timer.h>
MODULE_LICENSE("GPL");
#define BUF_LEN 255
#define TEXT "Hello from kernel mod\n"
int g_timer_interval = 10000;
static struct file *i_fp;
struct timer_list g_timer;
loff_t offset = 0;
char buff[BUF_LEN + 1] = TEXT;
void timer_rest(struct timer_list *timer)
{
mod_timer(&g_timer, jiffies + msecs_to_jiffies(g_timer_interval));
i_fp = filp_open("/home/hajol/Test.txt", O_RDWR | O_CREAT, 0644);
kernel_write(i_fp, buff, strlen(buff), &offset);
filp_close(i_fp, NULL);
}
static int __init kernel_init(void)
{
timer_setup(&g_timer, timer_rest, 0);
mod_timer(&g_timer, jiffies + msecs_to_jiffies(g_timer_interval));
return 0;
}
static void __exit kernel_exit(void)
{
pr_info("Ending");
del_timer(&g_timer);
}
module_init(kernel_init);
module_exit(kernel_exit);
When the system crashes, you should get a very detailed error message from the kernel, letting you know where and why this happened (the "oops" message):
Read that error message
Read it again
Understand what it means (this often requires starting over from step 1 a couple of times :-) )
One thing that jumps out at me is that you're not going any error checking on the return value of filp_open. So you could very well be feeding a NULL pointer (or error pointer) into kernel_write.

Data transfer between Processor and FPGA through GPMC using EDMA

We are working on a board containing AM3359 processor.
SDK we are using is ti-processor-sdk-linux-am335x-evm-05.00.00.15.
Our customer wants to see the throughput of the data transfer between processor (AM3359) and FPGA connected through 8 GPMC lines using EDMA
All we want now is to implement GPMC_EDMA data transfer program as per the below flow.
Processor and FPGA lines
Processor booted ----> Run GPMC_EDMA Data transfer program ----> Complete data transfer ----> Calculate throughput.
Here is my code for transferring data to FPGA through 8 GPMC lines.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <termios.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <sys/mman.h>
#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
__LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)
int verbose = 0;
#define BUF_SIZE 4096
int main(){
int i,fd;char ch;
int buf[BUF_SIZE];
volatile uint8_t *map_base;
int a=1;
for(i=0;i<BUF_SIZE;i++){
if(i%100==0){
a++;
printf("i: %d, a: %d\n",i,a);
}
buf[i]=a;
}
//buf[BUF_SIZE]=43;
if((fd=open("/dev/mem", O_RDWR | O_SYNC)) == -1) {
printf("Error in opening gpmc\n");return 0;
}
printf("Successfully opened\n");
map_base =(uint8_t *) mmap((void*)0x01000000, 0x01000000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x01000000);
if(map_base == (void *) -1) FATAL;
if (verbose) {
printf("Memory mapped at address %p.\n", map_base);
fflush(stdout);
}
volatile uint32_t *p32 = (uint32_t *) &map_base[0x0800];
//while(1/*(ch=getchar())!='\n'*/){
//*p32 = 0x1;
for(i=0;i<BUF_SIZE;i++){
*p32 = buf[i];
}
printf("Sent %d bytes\n",BUF_SIZE);
//}
printf("Closing FD\n");
close(fd);
}
Someone kindly help me to proceed further as we have a severe time restriction and also we are new to this one.
Regards
Vamsi

Linux Memory - Active kernel mappings from virtual to physical

Is there a way to see active mappings from virtual to physical memory in Linux?
To make simpler, let's assume we are on 32 bit system
Kernel Virtual Addresses
>>> 0xffffffff-0xc0000000
1073741823
Userspace Virtual Addresses
>>> 0xc0000000-0x00000000
3221225472
I want to scan Kernel Virtual Addresses for task_struct structure and was wondering if I have to scan the whole range or there is somehow a mapping which kernel virtual addresses are currently used?
Update 1:
How can I read it programatically to view all active mappings?
As I said I want to spare me going though the whole address space:
My code so far:
Here I try to scan the whole address space to look for task_struct and find the process name and PID (based on struct offsets)
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
void main()
{
int fd;
char *retp = NULL;
fd = open("/dev/mem", O_RDWR|O_SYNC);
for(int z=0;z<=0xffffffff;z=z+4096)
{
retp = mmap(NULL, 4096, PROT_READ, MAP_PRIVATE, fd,z);
if (retp == MAP_FAILED)
{
printf("FAILED\n");
}
else
{
printf("PASSED\n");
char task_struct[5760];
int pid;
for(int i=0;i<4096;i++)
{
memcpy(&task_struct,retp+i,5760);
memcpy(&pid,task_struct+768,sizeof(int));
if(strcmp(task_struct+996,"bash")==0)
printf("addr:%p\tname:%s\tpid:%i\n",retp+i,task_struct+996,pid);
}
munmap(retp,4096);
}
}
close(fd);
}

shmget previously created memory segment fails

I'm trying to learn the IPC UNIX APIs, specifically shared memory. I have created this small program that tries to either access the shared memory segment or create one.
This is what I do:
gcc -Wall -Wextra *.c
# in one terminal
./a.out
# in another
/a.out
The shared.mem file you can see in the source IS present in the same directory from which I launch the executable.
However, it seems like I'm never actually accessing a previously created shared memory segment (error is "No such file or directory"). I always create a new one - as seen via the ipcs command line, even though the IPC key stays the same.
What am I doing wrong ?
Below is the code I used, for reference. It compiles at least on Linux.
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define exit_error(what) exit_error_func(what, __FILE__, __LINE__)
#define SHM_SIZE (64)
#define UNUSED(x) (void)(x)
void *shm_addr = NULL;
void exit_error_func(const char *what, const char *file, int line)
{
fprintf(stderr, "Error in %s at line %d: %s. Reason: %s.\n", file, line, what, strerror(errno));
exit(1);
}
void sigint_handler(int sig)
{
shmdt(shm_addr);
UNUSED(sig);
}
int main(void)
{
key_t ipc_key;
int shm_id;
if ((ipc_key = ftok("shared.mem", 1)) == -1)
exit_error("could not get IPC key");
printf("IPC key is %d\n", ipc_key);
if ((shm_id = shmget(ipc_key, SHM_SIZE, 0600)) == -1)
{
printf("could not get SHM id, trying to create one now\n");
if ((shm_id = shmget(ipc_key, SHM_SIZE, IPC_EXCL | IPC_CREAT | 0600)) == -1)
exit_error("could not create or get shared memory segment");
else
printf("created SHM id\n");
}
else
printf("got already existing SHM id\n");
printf("SHM id is %d\n", shm_id);
if ((shm_addr = shmat(shm_id, NULL, 0)) == (void *)-1)
exit_error("could not attach to segment");
signal(SIGINT, sigint_handler);
if (shmctl(shm_id, IPC_RMID, NULL) == -1)
exit_error("could not flag shared memory for deletion");
printf("SHM flagged for deletion\n");
while (1)
sleep(1);
return (0);
}
It appears that it is not possible to shmget a shared memory segment that is flagged for deletion. Therefore, the shared memory segment must be marked for deletion once no process needs to shmget it anymore.
Disclaimer: I am no UNIX expert. Although the proposed solution works for me, I am still learning and cannot guarantee accuracy of the information given here.

Reserve a virtual address range in dynamic linker

Is there a way to reserve a particular range of virtual address space in a process memory map to stop ld.so (dynamic linker) from loading any shared objects into that range. Something like a system wide configuration option that reserves a particular range.
I want to be able to map a region of shared memory into exactly the same virtual address space in several processes so that my pointers in my data-structures will still work. I know I could redesign to use offsets instead of pointers but I don't want to do that.
You can do this by creating a simple shared object and running it via LD_PRELOAD. Compile the following code:
#include <sys/mman.h> // for mmap, munmap, and related constants
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
void my_program_init() __attribute__((constructor));
void *const address = ((void*)0x10000000);
const int size = 0x1000;
void my_program_init() {
printf("Hello from my_program_init!\n");
int fd = shm_open("/mysharedmem", O_CREAT | O_RDWR, 0666);
if (fd == -1) {
printf("shm_open\n");
return;
}
if (ftruncate(fd, size) == -1) {
printf("ftruncate\n");
return;
}
void* shared_mem = mmap(address, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0);
if (shared_mem == MAP_FAILED) {
printf("mmap\n");
return;
}
return;
}
with the following options:
gcc -shared -fPIC -o libmylib.so myso.c
Then you can run your program like this:
LD_PRELOAD=./libmylib.so ./your_prog
The so is then loaded before any runtime linking happens in your program. The function in the so tagged as a constructor runs immediately and uses mmap to reserve the memory you want for your shared block.
You can see this working with the following example program:
#include <sys/mman.h>
#include <string.h>
#include <stdio.h>
int main() {
char *data = (char*)0x10000000;
const char *message = "Hello, world!\n";
memcpy(data, message, strlen(message));
printf("Wrote %ld bytes to memory at address %p %s\n", strlen(message), data, data);
return 0;
}
If you run this without the LD_PRELOAD it will segfault, but if you include the preload the shared block of memory is available as expected.
$ LD_PRELOAD=./libmylib.so ./a.out
Hello from my_program_init!
Wrote 14 bytes to memory at address 0x10000000 Hello, world!
You can construct your own tests to validate that the memory block is actually shared but the easiest check is to recompile the test program again without the memcpy and see that the string is still there from the first run of the program.

Resources