kk Blog —— 通用基础


date [-d @int|str] [+%s|"+%F %T"]
netstat -ltunp
sar -n DEV 1

kdump el5 --dump-dmesg 错误

原因:

http://vault.centos.org/5.11/os/SRPMS/kexec-tools-1.102pre-165.el5.src.rpm
这个包的一个patch(kexec-tools-1.102pre-makedumpfile-dump-dmesg.patch)是为了得到dmesg的,
但是它判断dmesg的结束是用logged_chars(看kernel/printk.c),logged_chars应该是输出的结束,所以不对。
改成log_end就行,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
diff --git a/kexec-tools-1.102pre-makedumpfile-dump-dmesg.patch b/kexec-tools-1.102pre-makedumpfile-dump-dmesg.patch
index 3938280..76c402a 100644
--- a/kexec-tools-1.102pre-makedumpfile-dump-dmesg.patch
+++ b/kexec-tools-1.102pre-makedumpfile-dump-dmesg.patch
@@ -68,7 +68,7 @@ diff -up kexec-tools-testing-20070330/makedumpfile/makedumpfile.c.orig kexec-too
 +dump_dmesg()
 +{
 +      int log_buf_len, length_log, length_oldlog, ret = FALSE;
-+      unsigned long log_addr, logged_chars, index;
++      unsigned long log_addr, logged_chars, log_end, index;
 +      char *log_buffer = NULL;
 +
 +      if (!open_files_for_creating_dumpfile())
@@ -101,10 +101,15 @@ diff -up kexec-tools-testing-20070330/makedumpfile/makedumpfile.c.orig kexec-too
 +               printf("Failed to get logged_chars.\n");
 +               return FALSE;
 +      }
++      if (!readmem(VADDR, SYMBOL(log_end), &log_end, sizeof(log_end))) {
++               printf("Failed to get log_end.\n");
++               return FALSE;
++      }
 +      DEBUG_MSG("\n");
 +      DEBUG_MSG("log_addr     : %lx\n", log_addr);
 +      DEBUG_MSG("log_buf_len  : %d\n", log_buf_len);
 +      DEBUG_MSG("logged_chars : %ld\n", logged_chars);
++      DEBUG_MSG("log_end      : %ld\n", log_end);
 +
 +      if ((log_buffer = malloc(log_buf_len)) == NULL) {
 +               ERRMSG("Can't allocate memory for log_buf. %s\n",
@@ -112,21 +117,16 @@ diff -up kexec-tools-testing-20070330/makedumpfile/makedumpfile.c.orig kexec-too
 +               return FALSE;
 +       }
 +
-+      if (logged_chars < log_buf_len) {
++      if (log_end < log_buf_len) {
 +               index = 0;
-+               length_log = logged_chars;
++               length_log = log_end;
 +
 +               if(!readmem(VADDR, log_addr, log_buffer, length_log)) {
 +                        printf("Failed to read dmesg log.\n");
 +                        goto out;
 +               }
 +      } else {
-+               if (!readmem(VADDR, SYMBOL(log_end), &index, sizeof(index))) {
-+                        printf("Failed to get log_end.\n");
-+                        goto out;
-+               }
-+               DEBUG_MSG("log_end      : %lx\n", index);
-+               index &= log_buf_len - 1;
++               index = log_end & (log_buf_len - 1);
 +               length_log = log_buf_len;
 +               length_oldlog = log_buf_len - index;
 +


如果不修改上面bug,kdump得到vmcore后用 makedumpfile –dump-dmesg 无法解得dmesg,补救办法如下:

kdump得到vmcore后
1、vmlinux没有debuginfo,crash不能运行
2、makedumpfile -F –dump-dmesg vmcore > dmesg 只能显示开头一下部分dmesg (不懂为什么)
解决:

方法一、

通过/boot/System.map 或者 /proc/kallsyms 找到 log_buf 地址,例如 0xffffffff81a9ac30

1
2
3
4
5
6
7
8
9
10
11
12
13
14
gdb vmlinux vmcore

set print repeats 100
set print elements 0
set logging file XXX
set pagination off
set logging on
p {char*} 0xffffffff81a9ac30
quit

---

vi XXX
:%s/\\n/\r/g
方法二、

是另一命令,但不好用

1
2
3
4
5
6
7
8
9
10
11
cat /proc/kallsyms | grep log_end
ffffffff81e30de0 b log_end

x/1dw 0xffffffff81e30de0
0xffffffff81e30de0:     85689

x/1xg 0xffffffff81a9ac30
0xffffffff81a9ac30:     0xffffffff81e30ee0

显示最后4000字符
x/5s 0xffffffff81e30ee0+85689-4000

gdb 没有debug信息step单步调试

一、如果有函数调用,他会进入该函数

1
step <count>

单步跟踪,如果有函数调用,他会进入该函数。进入函数的前提是,此函数被编译有 debug信息。很像 VC等工具中的 step in。后面可以加 count也可以不加,不加表示一条条地执行,加表示执行后面的 count条指令,然后再停住。

二、如果有函数调用,他不会进入该函数

1
next <count>

同样单步跟踪,如果有函数调用,他不会进入该函数。很像 VC等工具中的 step over。后面可以加 count也可以不加,不加表示一条条地执行,加表示执行后面的 count条指令,然后再停住。

三、无debuginfo时需要set step-mode [on/off]

1
2
3
4
5
6
set step-mode [on/off]
set step-mode on
#打开 step-mode模式,于是,在进行单步跟踪时,程序不会因为没有 debug信息而不停住。这个参数有很利于查看机器码。

set step-mode off
关闭 step-mode模式。

四、跟踪子进程

使用gdb调试的时候,gdb只能跟踪一个进程。

可以在fork函数调用之前,通过指令设置gdb调试工具跟踪父进程或子进程。

默认情况下gdb是跟踪父进程的。

1
2
set follow-fork-mode child   # 命令设置gdb在fork之后跟踪子进程。
set follow-fork-mode parent  # 设置跟踪父进程。

五、修改值

1
2
3
4
5
6
set $rax=0   # 寄存器

set m=6       # 变量,需要debuginfo

p $rsp+0x714  # 内存
set *0x7f962c1fa564 = 0x6

gdb x命令语法

可以使用examine命令(简写是x)来查看内存地址中的值。x命 令的语 法如下所示:

1
x/<n/f/u> <addr>  

n、f、u是可选的参数。
n是一个正整数,表示需要显示的内存单元的个数, 也就是说从当前地址向后显示几个 内存单元的内容,一个内存单元的大小由后面的u定义。
f 表示显示的格式,参见下面。如果地址所指的是字符串,那么格式可以是s,如果地十是指令地址,那么格式可以是i。
u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字 节,g表示八字节。当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。
表示一个内存地址。

注意:严格区分n 和u的关系,n表示单元个数,u表示每个单元的大小。

n/f/u三个参数可以一起使用。例如:
命令:x/3uh 0x54320 表示,从内存地址0x54320读取内容,h表示以双字节为一个单位,3表示输出三个单位,u表示按十六进制显示。

输出格式

一般来说,GDB会根据变量的类型输出变量的值。但你也可以自定义GDB的输出的格式。例如,你想输出一个整数的十六进制,或是二进制来查看这个整型变量 的中的位的情况。要做到这样,你可以使用GDB的数据显示格式:

1
2
3
4
5
6
7
8
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十六进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
c 按字符格式显示变量。
f 按浮点数格式显示变量。

(gdb) help x Examine memory: x/FMT ADDRESS. ADDRESS is an expression for the memory address to examine. FMT is a repeat count followed by a format letter and a size letter. Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal), t(binary), f(float), a(address), i(instruction), c(char) and s(string). Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes). The specified number of objects of the specified size are printed according to the format.

Defaults for format and size letters are those previously used. Default count is 1. Default address is following last thing printed with this command or “print”.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
(gdb) p f1
$4 = 8.25
(gdb) p f2
$5 = 125.5
(gdb) x/x &f1
0xbffff380:   0x41040000
(gdb) x/xw &f1
0xbffff380:   0x41040000
(gdb) x/xw &f2
0xbffff384:   0x42fb0000
(gdb) x/2xw &f1
0xbffff380:   0x41040000   0x42fb0000
(gdb) x/4xw &f1
0xbffff380:   0x41040000   0x42fb0000   0xbffff408   0x00bcba66
(gdb) x/tw &f1
0xbffff380:   01000001000001000000000000000000
(gdb) x/2tw &f1
0xbffff380:   01000001000001000000000000000000   01000010111110110000000000000000
(gdb) p record
$10 = {12, 76, 48, 62, 94, 17, 32, 37, 52, 69}
(gdb) p &record
$11 = (int (*)[10]) 0x8049740
(gdb) x/4uw 0x8049740
0x8049740 <record>:   12   76   48   62
(gdb) x/6ow 0x8049740
0x8049740 <record>:   014   0114   060   076
0x8049750 <record+16>:   0136   021