【摘要】 在Linux開發中着實用到的調試工具並非不少。devmem的方式是提供給驅動開發人員,在應用層可以偵測內存地址中的數據變化,以此來檢測驅動中對內存或者相關配置的正確性驗證。node
這個工具的原理也比較簡單,就是應用程序經過mmap函數實現對/dev/mem驅動中mmap方法的使用,映射了設備的內存到用戶空間,實現對這些物理地址的讀寫操做。app
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <signal.h> #include <fcntl.h> #include <ctype.h> #include <termios.h> #include <sys/types.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) #define MAP_SIZE 4096UL #define MAP_MASK (MAP_SIZE - 1) int main(int argc, char **argv) { int fd; void *map_base, *virt_addr; unsigned long read_result, writeval; off_t target; int access_type = 'w'; if(argc < 2) {//若參數個數少於兩個則打印此工具的使用方法 fprintf(stderr, "\nUsage:\t%s { address } [ type [ data ] ]\n" "\taddress : memory address to act upon\n" "\ttype : access operation type : [b]yte, [h]alfword, [w]ord\n" "\tdata : data to be written\n\n", argv[0]); exit(1); } target = strtoul(argv[1], 0, 0); if(argc > 2) access_type = tolower(argv[2][0]); if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL; printf("/dev/mem opened.\n"); fflush(stdout); /* Map one page */ //將內核空間映射到用戶空間 map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK); if(map_base == (void *) -1) FATAL; printf("Memory mapped at address %p.\n", map_base); fflush(stdout); virt_addr = map_base + (target & MAP_MASK); //針對不一樣的參數獲取不一樣類型內存數據 switch(access_type) { case 'b': read_result = *((unsigned char *) virt_addr); break; case 'h': read_result = *((unsigned short *) virt_addr); break; case 'w': read_result = *((unsigned long *) virt_addr); break; default: fprintf(stderr, "Illegal data type '%c'.\n", access_type); exit(2); } printf("Value at address 0x%X (%p): 0x%X\n", target, virt_addr, read_result); fflush(stdout); //若參數大於3個,則說明爲寫入操做,針對不一樣參數寫入不一樣類型的數據 if(argc > 3) { writeval = strtoul(argv[3], 0, 0); switch(access_type) { case 'b': *((unsigned char *) virt_addr) = writeval; read_result = *((unsigned char *) virt_addr); break; case 'h': *((unsigned short *) virt_addr) = writeval; read_result = *((unsigned short *) virt_addr); break; case 'w': *((unsigned long *) virt_addr) = writeval; read_result = *((unsigned long *) virt_addr); break; } printf("Written 0x%X; readback 0x%X\n", writeval, read_result); fflush(stdout); } if(munmap(map_base, MAP_SIZE) == -1) FATAL; close(fd); return 0; }
memdev:直接讀寫內存。 能夠在busybox的雜項中找到: CONFIG_USER_BUSYBOX_DEVMEM: devmem is a small program that reads and writes from physical memory using /dev/mem. Symbol: USER_BUSYBOX_DEVMEM [=y] Prompt: devmem Defined at ../user/busybox/busybox-1.14.3/miscutils/Kconfig:216 Depends on: USER_BUSYBOX_BUSYBOX Location: -> BusyBox (USER_BUSYBOX_BUSYBOX [=y]) -> Miscellaneous Utilities [用法] Usage: devmem ADDRESS [WIDTH [VALUE]] 讀取:在地址0x97000000讀取32bit值(WIDTH默認等於32, 可選值爲[8, 16, 32, 64]) /dev # devmem 0x97000000 0x11111111 讀取:在地址0x97000000讀取16bit值 /dev # devmem 0x97000000 16 0x1111 寫入:在地址0x97000000寫入32bit值0x7777ABCD /dev # devmem 0x97000000 32 0x7777ABCD /dev # devmem 0x97000000 0x7777ABCD 注意:若是/dev下沒有mem這個node,會出現錯誤: /dev # devmem 0x97000000 devmem: can't open '/dev/mem': No such file or directory 這時能夠在Host系統中手動建立一個(例如在NFS root filesystem模式): host@host-laptop:~/embedded/tftpboot/nfsroot/dev$ sudo mknod mem -m666 c 1 1 注意這裏的權限是666,容許任何人任意讀寫,能夠很好的配合程序debug。 /dev # devmem 0x97000000 0x7777ABCD