02.驅動調試

来源:http://www.cnblogs.com/Lwd-linux/archive/2017/01/31/6358448.html
-Advertisement-
Play Games

驅動程式的調試一. 列印: printk, 自製proc文件UBOOT傳入console=ttySAC0(串口) console=tty1(LCD)1. 內核處理UBOOT傳入的參數console_setup add_preferred_console // 我想用名為"ttySAC0"的控制台,先 ...


驅動程式的調試
一. 列印: printk, 自製proc文件
UBOOT傳入console=ttySAC0(串口) console=tty1(LCD)
1. 內核處理UBOOT傳入的參數
console_setup
    add_preferred_console // 我想用名為"ttySAC0"的控制台,先記錄下來

2. 硬體驅動的入口函數里:
    drivers/serial/s3c2410.c
        register_console(&s3c24xx_serial_console);        

3. printk
        vprintk
            /* Emit the output into the temporary buffer */
            // 先把輸出信息放入臨時BUFFER
            vscnprintf
            
            // Copy the output into log_buf.
            // 把臨時BUFFER里的數據稍作處理,再寫入log_buf
            // 比如printk("abc")會得到"<4>abc", 再寫入log_buf
            // 可以用dmesg命令把log_buf里的數據列印出來重現內核的輸出信息
            
            
            // 調用硬體的write函數輸出
            release_console_sem();
                call_console_drivers(_con_start, _log_end);
                    // 從log_buf得到數據,算出列印級別
                    _call_console_drivers(start_print, cur_index, msg_level);            
                        // 如果可以級別夠格列印
                        if ((msg_log_level < console_loglevel
                            __call_console_drivers
                                con->write(con, &LOG_BUF(start), end - start);

4.語句

    printk(KERN_DEBUG"%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
//將列印出 絕對路徑,函數,行數

  cat /proc/sys/kernel/printk       //查看預設的列印級別console_loglevel

  echo “8 4 17”>/proc/sys/kernel/printk            //修改預設的列印級別console_loglevel

  set bootargs loglevel=0                      //不列印任何東西

  set bootargs loglevel=10                      //列印所有東西
  執行dmsg本質是讀取/proc/kmsg文件

5.列印到proc虛擬文件

要列印的信息會存放在log_buf中,通過文件/proc/kmsg可以來訪問這個buf,然後將信息列印出來。由此我們就想了,我們是否可以構造這樣一個mylog_buf,裡面存放我們所需要的列印信息,通過一個/proc/kmsg文件可以訪問該buf,然後列印出來?答案是肯定的!

5.1 proc機制分析

 

1 #ifdef CONFIG_PRINTK
2     {
3         struct proc_dir_entry *entry;
4         entry = create_proc_entry("kmsg", S_IRUSR, &proc_root);
5         if (entry)
6             entry->proc_fops = &proc_kmsg_operations;
7     }
8 #endif

 

創建一個proc入口,並設置操作函數

其操作函數如下:

1 const struct file_operations proc_kmsg_operations = {
2     .read        = kmsg_read,
3     .poll        = kmsg_poll,
4     .open        = kmsg_open,
5     .release    = kmsg_release,
6 };

所以我們可以仿照該文件寫出我們自己的mymsg

 

 

  1 #include <linux/module.h>
  2 #include <linux/kernel.h>
  3 #include <linux/fs.h>
  4 #include <linux/init.h>
  5 #include <linux/delay.h>
  6 #include <asm/uaccess.h>
  7 #include <asm/irq.h>
  8 #include <asm/io.h>
  9 #include <asm/arch/regs-gpio.h>
 10 #include <asm/hardware.h>
 11 #include <linux/proc_fs.h>
 12 
 13 #define MYLOG_BUF_LEN 1024
 14 
 15 struct proc_dir_entry *myentry;
 16 
 17 static char mylog_buf[MYLOG_BUF_LEN];
 18 static char tmp_buf[MYLOG_BUF_LEN];
 19 static int mylog_r = 0;
 20 static int mylog_r_for_read = 0;
 21 static int mylog_w = 0;
 22 
 23 static DECLARE_WAIT_QUEUE_HEAD(mymsg_waitq);
 24 
 25 static int is_mylog_empty(void)
 26 {
 27     return (mylog_r == mylog_w);
 28 }
 29 
 30 static int is_mylog_empty_for_read(void)
 31 {
 32     return (mylog_r_for_read == mylog_w);
 33 }
 34 
 35 static int is_mylog_full(void)
 36 {
 37     return ((mylog_w + 1)% MYLOG_BUF_LEN == mylog_r);
 38 }
 39 
 40 static void mylog_putc(char c)
 41 {
 42     if (is_mylog_full())
 43     {
 44         /* 丟棄一個數據 */
 45         mylog_r = (mylog_r + 1) % MYLOG_BUF_LEN;
 46 
 47         if ((mylog_r_for_read + 1) % MYLOG_BUF_LEN == mylog_r)
 48         {
 49             mylog_r_for_read = mylog_r;
 50         }
 51     }
 52 
 53     mylog_buf[mylog_w] = c;
 54     mylog_w = (mylog_w + 1) % MYLOG_BUF_LEN;
 55 
 56     /* 喚醒等待數據的進程 */    
 57     wake_up_interruptible(&mymsg_waitq);   /* 喚醒休眠的進程 */    
 58 }
 59 
 60 static int mylog_getc(char *p)
 61 {
 62     if (is_mylog_empty())
 63     {
 64         return 0;
 65     }
 66     *p = mylog_buf[mylog_r];
 67     mylog_r = (mylog_r + 1) % MYLOG_BUF_LEN;
 68     return 1;
 69 }
 70 
 71 static int mylog_getc_for_read(char *p)
 72 {
 73     if (is_mylog_empty_for_read())
 74     {
 75         return 0;
 76     }
 77     *p = mylog_buf[mylog_r_for_read];
 78     mylog_r_for_read = (mylog_r_for_read + 1) % MYLOG_BUF_LEN;
 79     return 1;
 80 }
 81 
 82 
 83 int myprintk(const char *fmt, ...)
 84 {
 85     va_list args;
 86     int i;
 87     int j;
 88 
 89     va_start(args, fmt);
 90     i = vsnprintf(tmp_buf, INT_MAX, fmt, args);
 91     va_end(args);
 92     
 93     for (j = 0; j < i; j++)
 94         mylog_putc(tmp_buf[j]);
 95         
 96     return i;
 97 }
 98 
 99 static ssize_t mymsg_read(struct file *file, char __user *buf,
100              size_t count, loff_t *ppos)
101 {
102     int error = 0;
103     int i = 0;
104     char c;
105 
106     /* 把mylog_buf的數據copy_to_user, return */
107     if ((file->f_flags & O_NONBLOCK) && is_mylog_empty_for_read())
108         return -EAGAIN;
109 
110     //printk("%s %d\n", __FUNCTION__, __LINE__);
111     //printk("count = %d\n", count);
112     //printk("mylog_r = %d\n", mylog_r);
113     //printk("mylog_w = %d\n", mylog_w);
114 
115     error = wait_event_interruptible(mymsg_waitq, !is_mylog_empty_for_read());
116 
117     //printk("%s %d\n", __FUNCTION__, __LINE__);
118     //printk("count = %d\n", count);
119     //printk("mylog_r = %d\n", mylog_r);
120     //printk("mylog_w = %d\n", mylog_w);
121 
122     /* copy_to_user */
123     while (!error && (mylog_getc_for_read(&c)) && i < count) {
124         error = __put_user(c, buf);
125         buf++;
126         i++;
127     }
128     
129     if (!error)
130         error = i;
131     
132     return error;
133 }
134 
135 static int mymsg_open(struct inode *inode, struct file *file)
136 {
137     mylog_r_for_read = mylog_r;
138     return 0;
139 }
140 
141 const struct file_operations proc_mymsg_operations = {
142     .open = mymsg_open,
143     .read = mymsg_read,
144 };
145 
146 static int mymsg_init(void)
147 {    
148     myentry = create_proc_entry("mymsg", S_IRUSR, &proc_root);
149     if (myentry)
150         myentry->proc_fops = &proc_mymsg_operations;
151     return 0;
152 }
153 
154 static void mymsg_exit(void)
155 {
156     remove_proc_entry("mymsg", &proc_root);
157 }
158 
159 module_init(mymsg_init);
160 module_exit(mymsg_exit);
161 
162 EXPORT_SYMBOL(myprintk);
163 
164 MODULE_LICENSE("GPL");
列印到proc虛擬文件

可以直接使用myprintk,然後用cat /proc/mymsg指令查到我們的列印信息。

小結:在本文件裡面我們做了兩件事情,一件事情是定義了一個寫函數,當我們在用戶空間使用命令:cat /proc/mymsg的時候,就會調用到這個讀函數,這個讀函數會將mylog_buf中的數據拷貝到用戶空間,那麼mylog_buf裡面的數據哪裡來的呢?這就是我們做的另外一件事情,我們定義了一個列印函數,這個列印函數會將要列印的數據寫入一個臨時緩衝區,然後又從臨時緩衝區裡面取出數據放入mylog_buf中。cat /proc/mymsg的候就會將mylog_buf中的數據拷貝到用戶空間,就可以顯示出來了!


二. 根據內核列印的段錯誤信息分析
a. 作為模塊:
1. 根據pc值確定該指令屬於內核還是外加的模塊
pc=0xbf000018 它屬於什麼的地址?是內核還是通過insmod載入的驅動程式?
先判斷是否屬於內核的地址: 看System.map確定內核的函數的地址範圍:c0004000~c03265a4

如果不屬於System.map里的範圍,則它屬於insmod載入的驅動程式

2. 假設它是載入的驅動程式引入的錯誤,怎麼確定是哪一個驅動程式?
先看看載入的驅動程式的函數的地址範圍
cat /proc/kallsyms  (內核函數、載入的函數的地址)
從這些信息里找到一個相近的地址, 這個地址<=0xbf000018
比如找到了:
bf000000 t first_drv_open    [first_drv]

3. 找到了first_drv.ko
在PC上反彙編它: arm-linux-objdump -D first_drv.ko > frist_drv.dis
在dis文件里找到first_drv_open

    first_drv.dis文件里              insmod後
00000000 <first_drv_open>:       bf000000 t first_drv_open    [first_drv]
00000018                         pc = bf000018
                                 



./firstdrvtest on
Unable to handle kernel paging request at virtual address 56000050
內核使用56000050來訪問時發生了錯誤

pgd = c3eb0000
[56000050] *pgd=00000000
Internal error: Oops: 5 [#1]
Modules linked in: first_drv
CPU: 0    Not tainted  (2.6.22.6 #1)
PC is at first_drv_open+0x18(該指令的偏移)/0x3c(該函數的總大小) [first_drv]
PC就是發生錯誤的指令的地址
大多時候,PC值只會給出一個地址,不到指示說是在哪個函數里

LR is at chrdev_open+0x14c/0x164
LR寄存器的值

pc = 0xbf000018

pc : [<bf000018>]    lr : [<c008d888>]    psr: a0000013
sp : c3c7be88  ip : c3c7be98  fp : c3c7be94
r10: 00000000  r9 : c3c7a000  r8 : c049abc0
r7 : 00000000  r6 : 00000000  r5 : c3e740c0  r4 : c06d41e0
r3 : bf000000  r2 : 56000050  r1 : bf000964  r0 : 00000000
執行這條導致錯誤的指令時各個寄存器的值

Flags: NzCv  IRQs on  FIQs on  Mode SVC_32  Segment user
Control: c000717f  Table: 33eb0000  DAC: 00000015
Process firstdrvtest (pid: 777, stack limit = 0xc3c7a258)
發生錯誤時當前進程的名稱是firstdrvtest


Stack: (0xc3c7be88 to 0xc3c7c000)
be80:                   c3c7bebc c3c7be98 c008d888 bf000010 00000000 c049abc0
bea0: c3e740c0 c008d73c c0474e20 c3e766a8 c3c7bee4 c3c7bec0 c0089e48 c008d74c
bec0: c049abc0 c3c7bf04 00000003 ffffff9c c002c044 c3d10000 c3c7befc c3c7bee8
bee0: c0089f64 c0089d58 00000000 00000002 c3c7bf68 c3c7bf00 c0089fb8 c0089f40
bf00: c3c7bf04 c3e766a8 c0474e20 00000000 00000000 c3eb1000 00000101 00000001
bf20: 00000000 c3c7a000 c04a7468 c04a7460 ffffffe8 c3d10000 c3c7bf68 c3c7bf48
bf40: c008a16c c009fc70 00000003 00000000 c049abc0 00000002 bec1fee0 c3c7bf94
bf60: c3c7bf6c c008a2f4 c0089f88 00008520 bec1fed4 0000860c 00008670 00000005
bf80: c002c044 4013365c c3c7bfa4 c3c7bf98 c008a3a8 c008a2b0 00000000 c3c7bfa8
bfa0: c002bea0 c008a394 bec1fed4 0000860c 00008720 00000002 bec1fee0 00000001
bfc0: bec1fed4 0000860c 00008670 00000002 00008520 00000000 4013365c bec1fea8
bfe0: 00000000 bec1fe84 0000266c 400c98e0 60000010 00008720 00000000 00000000

Backtrace: (回溯)
[<bf000000>] (first_drv_open+0x0/0x3c [first_drv]) from [<c008d888>] (chrdev_open+0x14c/0x164)
[<c008d73c>] (chrdev_open+0x0/0x164) from [<c0089e48>] (__dentry_open+0x100/0x1e8)
 r8:c3e766a8 r7:c0474e20 r6:c008d73c r5:c3e740c0 r4:c049abc0
[<c0089d48>] (__dentry_open+0x0/0x1e8) from [<c0089f64>] (nameidata_to_filp+0x34/0x48)
[<c0089f30>] (nameidata_to_filp+0x0/0x48) from [<c0089fb8>] (do_filp_open+0x40/0x48)
 r4:00000002
[<c0089f78>] (do_filp_open+0x0/0x48) from [<c008a2f4>] (do_sys_open+0x54/0xe4)
 r5:bec1fee0 r4:00000002
[<c008a2a0>] (do_sys_open+0x0/0xe4) from [<c008a3a8>] (sys_open+0x24/0x28)
[<c008a384>] (sys_open+0x0/0x28) from [<c002bea0>] (ret_fast_syscall+0x0/0x2c)
Code: e24cb004 e59f1024 e3a00000 e5912000 (e5923000)
Segmentation fault
#

b. 編入內核
Modules linked in:
CPU: 0    Not tainted  (2.6.22.6 #2)
PC is at first_drv_open+0x18/0x3c
LR is at chrdev_open+0x14c/0x164
pc : [<c014e6c0>]    lr : [<c008638c>]    psr: a0000013
sp : c3a03e88  ip : c3a03e98  fp : c3a03e94
r10: 00000000  r9 : c3a02000  r8 : c03f3c60
r7 : 00000000  r6 : 00000000  r5 : c38a0c50  r4 : c3c1e780
r3 : c014e6a8  r2 : 56000050  r1 : c031a47c  r0 : 00000000
Flags: NzCv  IRQs on  FIQs on  Mode SVC_32  Segment user
Control: c000717f  Table: 339f0000  DAC: 00000015
Process firstdrvtest (pid: 750, stack limit = 0xc3a02258)

1. 根據pc值確定該指令屬於內核還是外加的模塊
pc=c014e6c0 屬於內核(看System.map)

2. 反彙編內核: arm-linux-objdump -D vmlinux > vmlinux.dis
在dis文件里搜c014e6c0
c014e6a8 <first_drv_open>:
c014e6a8:       e1a0c00d        mov     ip, sp
c014e6ac:       e92dd800        stmdb   sp!, {fp, ip, lr, pc}
c014e6b0:       e24cb004        sub     fp, ip, #4      ; 0x4
c014e6b4:       e59f1024        ldr     r1, [pc, #36]   ; c014e6e0 <.text+0x1276e0>
c014e6b8:       e3a00000        mov     r0, #0  ; 0x0
c014e6bc:       e5912000        ldr     r2, [r1]
c014e6c0:       e5923000        ldr     r3, [r2] // 在此出錯 r2=56000050



3. 根據棧信息分析函數調用過程
# ./firstdrvtest on
Unable to handle kernel paging request at virtual address 56000050
pgd = c3e78000
[56000050] *pgd=00000000
Internal error: Oops: 5 [#1]
Modules linked in: first_drv
CPU: 0    Not tainted  (2.6.22.6 #48)
PC is at first_drv_open+0x18/0x3c [first_drv]
LR is at chrdev_open+0x14c/0x164
pc : [<bf000018>]    lr : [<c008c888>]    psr: a0000013
3.1 根據PC確定出錯位置
bf000018 屬於 insmod的模塊
bf000000 t first_drv_open       [first_drv]

3.2 確定它屬於哪個函數
反彙編first_drv.ko






sp : c3e69e88  ip : c3e69e98  fp : c3e69e94
r10: 00000000  r9 : c3e68000  r8 : c0490620
r7 : 00000000  r6 : 00000000  r5 : c3e320a0  r4 : c06a8300
r3 : bf000000  r2 : 56000050  r1 : bf000964  r0 : 00000000
Flags: NzCv  IRQs on  FIQs on  Mode SVC_32  Segment user
Control: c000717f  Table: 33e78000  DAC: 00000015
Process firstdrvtest (pid: 752, stack limit = 0xc3e68258)
Stack: (0xc3e69e88 to 0xc3e6a000)
9e80:                   c3e69ebc c3e69e98 c008c888 bf000010 00000000 c0490620
                        first_drv_open'sp    lr             chrdev_open'sp

9ea0: c3e320a0 c008c73c c0465e20 c3e36cb4 c3e69ee4 c3e69ec0 c0088e48 c008c74c
                                                            lr    
                                                                                 
9ec0: c0490620 c3e69f04 00000003 ffffff9c c002b044 c06e0000 c3e69efc c3e69ee8
      __dentry_open'sp

9ee0: c0088f64 c0088d58 00000000 00000002 c3e69f68 c3e69f00 c0088fb8 c0088f40
      lr                nameidata_to_filp'sp                lr
      
9f00: c3e69f04 c3e36cb4 c0465e20 00000000 00000000 c3e79000 00000101 00000001
      do_filp_open'sp

9f20: 00000000 c3e68000 c04c1468 c04c1460 ffffffe8 c06e0000 c3e69f68 c3e69f48
9f40: c008916c c009ec70 00000003 00000000 c0490620 00000002 be94eee0 c3e69f94
9f60: c3e69f6c c00892f4 c0088f88 00008520 be94eed4 0000860c 00008670 00000005
               lr                do_sys_open'sp

9f80: c002b044 4013365c c3e69fa4 c3e69f98 c00893a8 c00892b0 00000000 c3e69fa8
                                          lr                sys_open'sp

9fa0: c002aea0 c0089394 be94eed4 0000860c 00008720 00000002 be94eee0 00000001
      lr                ret_fast_syscall'sp
                        
9fc0: be94eed4 0000860c 00008670 00000002 00008520 00000000 4013365c be94eea8
9fe0: 00000000 be94ee84 0000266c 400c98e0 60000010 00008720 00000000 00000000


三. 自製工具—寄存器編輯器
當我們調試驅動程式的時候,可能要調整寄存器的設置。按照我們之前的作法就是直接在程式裡面修改,然後重新編譯程式。但是這種方法比較麻煩,我們可以編寫一個工具,可以直接對寄存器進行修改,這就是我們說的寄存器編輯器。

  1 #include <linux/module.h>
  2 #include <linux/kernel.h>
  3 #include <linux/fs.h>
  4 #include <linux/init.h>
  5 #include <linux/delay.h>
  6 #include <linux/irq.h>
  7 #include <asm/uaccess.h>
  8 #include <asm/irq.h>
  9 #include <asm/io.h>
 10 #include <asm/arch/regs-gpio.h>
 11 #include <asm/hardware.h>
 12 #include <linux/poll.h>
 13 #include <linux/device.h>
 14 
 15 #define KER_RW_R8      0
 16 #define KER_RW_R16     1
 17 #define KER_RW_R32     2
 18 
 19 #define KER_RW_W8      3
 20 #define KER_RW_W16     4
 21 #define KER_RW_W32     5
 22 
 23 
 24 static int major;
 25 static struct class *class;
 26 static struct class_device    *ker_dev;
 27 
 28 
 29 static int ker_rw_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 30 {
 31     volatile unsigned char  *p8;
 32     volatile unsigned short *p16;
 33     volatile unsigned int   *p32;
 34     unsigned int val;
 35     unsigned int addr;
 36 
 37     unsigned int buf[2];
 38 
 39     copy_from_user(buf, (const void __user *)arg, 8);
 40     addr = buf[0];
 41     val  = buf[1];
 42     
 43     p8  = (volatile unsigned char *)ioremap(addr, 4);
 44     p16 = p8;
 45     p32 = p8;
 46 
 47     switch (cmd)
 48     {
 49         case KER_RW_R8:
 50         {
 51             val = *p8;
 52             copy_to_user((void __user *)(arg+4), &val, 4);
 53             break;
 54         }
 55 
 56         case KER_RW_R16:
 57         {
 58             val = *p16;
 59             copy_to_user((void __user *)(arg+4), &val, 4);
 60             break;
 61         }
 62 
 63         case KER_RW_R32:
 64         {
 65             val = *p32;
 66             copy_to_user((void __user *)(arg+4), &val, 4);
 67             break;
 68         }
 69 
 70         case KER_RW_W8:
 71         {
 72             *p8 = val;
 73             break;
 74         }
 75 
 76         case KER_RW_W16:
 77         {
 78             *p16 = val;
 79             break;
 80         }
 81 
 82         case KER_RW_W32:
 83         {
 84             *p32 = val;
 85             break;
 86         }
 87     }
 88 
 89     iounmap(p8);
 90     return 0;
 91 }
 92 
 93 static struct file_operations ker_rw_ops = {
 94     .owner   = THIS_MODULE,
 95     .ioctl   = ker_rw_ioctl,
 96 };
 97 
 98 static int ker_rw_init(void)
 99 {
100     major = register_chrdev(0, "ker_rw", &ker_rw_ops);
101 
102     class = class_create(THIS_MODULE, "ker_rw");
103 
104     /* 為了讓mdev根據這些信息來創建設備節點 */
105     ker_dev = class_device_create(class, NULL, MKDEV(major, 0), NULL, "ker_rw"); /* /dev/ker_rw */
106     
107     return 0;
108 }
109 
110 static void ker_rw_exit(void)
111 {
112     class_device_unregister(ker_dev);
113     class_destroy(class);
114     unregister_chrdev(major, "ker_rw");
115 }
116 
117 module_init(ker_rw_init);
118 module_exit(ker_rw_exit);
119 
120 
121 MODULE_LICENSE("GPL");
自製寄存器修改器
  1 #include <sys/types.h>
  2 #include <sys/stat.h>
  3 #include <fcntl.h>
  4 #include <stdio.h>
  5 #include <poll.h>
  6 #include <signal.h>
  7 #include <sys/types.h>
  8 #include <unistd.h>
  9 #include <fcntl.h>
 10 #include <stdlib.h>
 11 #include <string.h>
 12 
 13 #define KER_RW_R8      0
 14 #define KER_RW_R16     1
 15 #define KER_RW_R32     2
 16 
 17 #define KER_RW_W8      3
 18 #define KER_RW_W16     4
 19 #define KER_RW_W32     5
 20 
 21 
 22 /* Usage:
 23  * ./regeditor r8  addr [num]
 24  * ./regeditor r16 addr [num]
 25  * ./regeditor r32 addr [num]
 26  *
 27  * ./regeditor w8  addr val
 28  * ./regeditor w16 addr val 
 29  * ./regeditor w32 addr val
 30  */
 31 
 32 void print_usage(char *file)
 33 {
 34     printf("Usage:\n");
 35     printf("%s <r8 | r16 | r32> <phy addr> [num]\n", file);
 36     printf("%s <w8 | w16 | w32> <phy addr> <val>\n", file);
 37 }
 38 
 39 int main(int argc, char **argv)
 40 {
 41     int fd;
 42     unsigned int buf[2];
 43     unsigned int i;
 44     unsigned int num;
 45     
 46     if ((argc != 3) && (argc != 4))
 47     {
 48         print_usage(argv[0]);
 49         return -1;
 50     }
 51 
 52     fd = open("/dev/ker_rw", O_RDWR);
 53     if (fd < 0)
 54     {
 55         printf("can't open /dev/ker_rw\n");
 56         return -2;
 57     }
 58 
 59     /* addr */
 60     buf[0] = strtoul(argv[2], NULL, 0);
 61 
 62     if (argc == 4)
 63     {
 64         buf[1] = strtoul(argv[3], NULL, 0);
 65         num    = buf[1];
 66     }
 67     else
 68     {
 69         num = 1;
 70     }
 71 
 72     if (strcmp(argv[1], "r8") == 0)
 73     {
 74         for ( i = 0; i < num; i++)
 75         {
 76             ioctl(fd, KER_RW_R8, buf);  /* val = buf[1] */
 77             printf("%02d. [%08x] = %02x\n", i, buf[0], (unsigned char)buf[1]);
 78             buf[0] += 1;
 79         }
 80     }
 81     else if (strcmp(argv[1], "r16") == 0)
 82     {
 83         for ( i = 0; i < num; i++)
 84         {
 85             ioctl(fd, KER_RW_R16, buf);  /* val = buf[1] */
 86             printf("%02d. [%08x] = %02x\n", i, buf[0], (unsigned short)buf[1]);
 87             buf[0] += 2;
 88         }
 89     }
 90     else if (strcmp(argv[1], "r32") == 0)
 91     {
 92         for ( i = 0; i < num; i++)
 93         {
 94             ioctl(fd, KER_RW_R32, buf);  /* val = buf[1] */
 95             printf("%02d. [%08x] = %02x\n", i, buf[0], (unsigned int)buf[1]);
 96             buf[0] += 4<

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、背景 公司在用kettle做數據etl,每做完一個job或transformation發佈上線想要立即執行看數據效果的話每次都是找運維同學登陸伺服器打開kettle找到對應的文件點擊執行,整個過程效率低下,不僅占用運維時間,期間自己也在白白等待,浪費生命。 google “kettle remo ...
  • 最近工作中遇到了一個問題,需要根據保存的流程數據,構建流程圖。資料庫中保持的流程數據是樹形結構的,表結構及數據如下圖: 仔細觀察表結構,會發現其樹形結構的特點: FFIRSTNODE:標記是否為根節點 FSTABLENAME:標記來源單據名稱 FSID:標記來源單據分錄ID FTTABLENAME ...
  • SQL Server 2014記憶體優化表的使用場景 最近一個朋友找到走起君,咨詢走起君記憶體優化表如何做高可用的問題 大家知道,記憶體優化表作為In-Memory OLTP功能是從SQL Server 2014開始引入,用來對抗Oracle 12C的In-Memory OLTP選件 不過SQL Serv ...
  • 根目錄 大小:60G~100G(用來安裝程式) 新分區的類型:主分區 新分區的位置:空間起始位置 用於:EXT4日誌文件系統 掛載點:"/" 大小:4G 新分區的類型:邏輯分區 新分區的位置:空間起始位置 用於:交換空間 掛載點:不設置 大小:500MB 新分區的類型:邏輯分區 新分區的位置:空間起 ...
  • 最近想再看看PCL,所以進行了安裝,在之前的接觸的過程中,由於之前的網路存在問題,導致以下三個命令: 老是會出先問題,一般會在linux 命令視窗中提示:公鑰或者私鑰比匹配之類的錯誤,或者乾脆找不到源 這個是因為在國內去找v-launchpad-jochen-sprickerhof-de/pcl這個 ...
  • 用了一段時間的MONO,現在MONO也支持了ENTITY FRAMEWORK 6。但是實際上在LINUX環境里用MYSQL還是會有很多坑。並且之前在網路游戲服務端SCUT上擴展一些功能時候也遇到了一些因為MONO和.NET行為方式不一致的坑耗掉了不少時間。使用mono雖然可以節約性能開銷,但是犧牲掉 ...
  • 今天在騰訊雲領取了一個免費試用的windows伺服器,我在deepin下想使用遠程桌面來連接windows,找到了這個工具rdesktop,感覺挺好用的所以分享一下。 安裝rdesktop 使用方法 ...
  • 安裝 啟動 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...