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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...