-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.xml
5577 lines (4359 loc) · 472 KB
/
index.xml
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Tacy - Notes</title>
<link>http://tacy.github.io/</link>
<description>Recent content on Tacy - Notes</description>
<generator>Hugo -- gohugo.io</generator>
<language>en</language>
<lastBuildDate>Sun, 20 Aug 2017 21:38:52 +0800</lastBuildDate>
<atom:link href="http://tacy.github.io/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>About</title>
<link>http://tacy.github.io/about/</link>
<pubDate>Sun, 20 Aug 2017 21:38:52 +0800</pubDate>
<guid>http://tacy.github.io/about/</guid>
<description><p>IT老民工,一个女儿的爸爸,会点编程,喜欢Linux和开源,什么都会点,什么都不精通,喜欢解决技术问题,对新教育兴趣浓厚。</p>
<p>工作环境: archlinux/emacs/mbp/vscode/android</p>
<p>这个blog用hugo和github page支撑,emacs编写</p>
<p>就这样。</p>
<p>我的社交信息都在下面,欢迎关注</p>
</description>
</item>
<item>
<title>Jetty接入异常</title>
<link>http://tacy.github.io/post/java-cause-accept-except/</link>
<pubDate>Thu, 19 Sep 2019 00:00:00 +0000</pubDate>
<guid>http://tacy.github.io/post/java-cause-accept-except/</guid>
<description>
<h1 id="故障现象">故障现象</h1>
<p>客户现场测试,部署的一个集成平台,Java,基于RHEL,在自己机器上测试一切正常,部署到客户机器怎么都无法调通,后台也没有任何日志。</p>
<h1 id="分析解决">分析解决</h1>
<p>现场反馈是在k8s容器里面部署不行,后面了解到的情况是即使直接部署在虚拟机上也是无法调通,也就可以排除容器网络的问题。</p>
<p>首先怀疑是网络问题,同事的反馈显示,端口是能正常telnet的,curl也能看到连接正常:
<img src="http://tacy.github.io/img/jetty2.jpg" alt="jetty curl" /></p>
<p>上图能看到连接已经建立了,但是server端迟迟没有返回。由于这里已经是直接本地调用了,查看了一下iptables,没发现有rule会影响29090端口的服务调用,自然怀疑是集成平台本身出了问题。</p>
<p>接着就查看了一下集成平台的java线程栈,没有发现有线程挂住的情况,里面的线程都是空的,结合日志情况看,服务是没有被调用的。</p>
<p>用抓包<code>tcpdump -i lo tcp -w esb.pcap</code>分析了一下,确认请求是已经收到了:
<img src="http://tacy.github.io/img/jetty3.jpg" alt="jetty wireshark" /></p>
<p>也就是说从tcp协议层,包已经被接收了,为什么会出现这样的情况呢?按理来说,接收到包,中断,然后应用介入,acceptor读取请求,但是从线程栈看,没发现有什么异常情况。</p>
<p>用<code>ss -tni -o &quot;dport = :29090</code>确认一下
<img src="http://tacy.github.io/img/jetty4.jpg" alt="jetty ss" /></p>
<p>从输出看,recv-q里面有88字节待读取。结合抓包截图,看到我们的请求大小就是88字节,也就是说,协议层面没有问题,包已经送达了,也没有overflow drop问题,问题确认出现在java层面,怀疑nio问题,我的最初怀疑是jdk,最后通过降低jetty版本解决,时间有限,没有再做更多分析。</p>
</description>
</item>
<item>
<title>java应用未关闭的http连接分析</title>
<link>http://tacy.github.io/post/java-http-connect-unclose/</link>
<pubDate>Thu, 18 Jul 2019 00:00:00 +0000</pubDate>
<guid>http://tacy.github.io/post/java-http-connect-unclose/</guid>
<description><p>正常情况下,我们创建的http连接都需要主动关闭(也有很多http连接池管理的实现帮助你,你也需要release回到池中)。但依然有些丑陋的代码,忘记主动关闭,这些没有关闭的连接最终都会被回收,用不同的方式。</p>
<p>存在两种方式:</p>
<p>一种是连接发起端垃圾回收。由于http对象没有任何引用,gc会把它回收掉,这种情况下,连接不是采用四次挥手的正常端口模式,而是通过发送RESET包断开,没有处理的数据也会直接扔掉。</p>
<p>一种是服务端断开。由于keepalive存在,一般服务端都会有keepalive超时设置。如果到了超时时间,客户端没有断开连接,服务端会主动断开。这种情况下,服务端会采用四次挥手方式断开连接,但是由于客户端对象已经没有任何引用,不会调用close方法,客户端虽然接收到了服务端发过来的fin包,但是不会回fin包,所以连接无法正常断开:客户端将处于close-wait状态,等待gc回收,服务端将处于fin-wait-2状态,并等待超时,进入time-wait状态。</p>
<p>如果你在系统中看到大量的reset包,或者看到tcp连接处于close-wait/fin-wait-2状态,一般情况下都是连接没有正常关闭导致。</p>
</description>
</item>
<item>
<title>Axis2 performance improve</title>
<link>http://tacy.github.io/post/axis2-performance-improve/</link>
<pubDate>Thu, 28 Mar 2019 00:00:00 +0000</pubDate>
<guid>http://tacy.github.io/post/axis2-performance-improve/</guid>
<description><p>上面一篇关于连接超时的文章,就是由于axis2客户端实现导致,下面是我用测试代码(启了4个线程,每个线程做4次调用)运行过程中的抓包:
<img src="http://tacy.github.io/img/axis2-1.png" alt="axis2 client" />
可以看到,每次调用都会新建立一个连接,无法重用</p>
<p>优化了一下,下面是修改过后的代码运行的抓包
<img src="http://tacy.github.io/img/axis2-2.png" alt="axis2 client" />
连接都被重用了</p>
<p>下面是实现代码片段:</p>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java"> <span class="kd">private</span> <span class="kd">static</span> <span class="n">ConfigurationContext</span> <span class="n">defaultConfigurationContext</span> <span class="o">=</span> <span class="n">createDefaultConfigurationContext</span><span class="o">();</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="n">ConfigurationContext</span> <span class="nf">createDefaultConfigurationContext</span><span class="o">(){</span>
<span class="c1">// reuse HTTP connections if possible.
</span><span class="c1"></span> <span class="n">MultiThreadedHttpConnectionManager</span> <span class="n">mgr</span> <span class="o">=</span> <span class="k">new</span> <span class="n">MultiThreadedHttpConnectionManager</span><span class="o">();</span>
<span class="n">HttpConnectionManagerParams</span> <span class="n">params</span> <span class="o">=</span> <span class="n">mgr</span><span class="o">.</span><span class="na">getParams</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">params</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">params</span> <span class="o">=</span> <span class="k">new</span> <span class="n">HttpConnectionManagerParams</span><span class="o">();</span>
<span class="n">mgr</span><span class="o">.</span><span class="na">setParams</span><span class="o">(</span><span class="n">params</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">params</span><span class="o">.</span><span class="na">setMaxTotalConnections</span><span class="o">(</span><span class="n">40</span><span class="o">);</span>
<span class="n">params</span><span class="o">.</span><span class="na">setDefaultMaxConnectionsPerHost</span><span class="o">(</span><span class="n">20</span><span class="o">);</span>
<span class="n">IdleConnectionTimeoutThread</span> <span class="n">ict</span> <span class="o">=</span> <span class="k">new</span> <span class="n">IdleConnectionTimeoutThread</span><span class="o">();</span>
<span class="n">ict</span><span class="o">.</span><span class="na">addConnectionManager</span><span class="o">(</span><span class="n">mgr</span><span class="o">);</span>
<span class="n">ict</span><span class="o">.</span><span class="na">setConnectionTimeout</span><span class="o">(</span><span class="n">15000</span><span class="o">);</span>
<span class="n">ict</span><span class="o">.</span><span class="na">start</span><span class="o">();</span>
<span class="n">HttpClient</span> <span class="n">httpClient</span> <span class="o">=</span> <span class="k">new</span> <span class="n">HttpClient</span><span class="o">(</span><span class="n">mgr</span><span class="o">);</span>
<span class="n">ConfigurationContext</span> <span class="n">defaultConfigurationContext</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">defaultConfigurationContext</span> <span class="o">=</span> <span class="n">ConfigurationContextFactory</span><span class="o">.</span><span class="na">createDefaultConfigurationContext</span><span class="o">();</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// TODO Auto-generated catch block
</span><span class="c1"></span> <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="n">defaultConfigurationContext</span><span class="o">.</span><span class="na">setProperty</span><span class="o">(</span><span class="n">HTTPConstants</span><span class="o">.</span><span class="na">CACHED_HTTP_CLIENT</span><span class="o">,</span> <span class="n">httpClient</span><span class="o">);</span>
<span class="k">return</span> <span class="n">defaultConfigurationContext</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="n">ServiceClient</span> <span class="n">sender</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ServiceClient</span><span class="o">(</span><span class="n">defaultConfigurationContext</span><span class="o">,</span><span class="kc">null</span><span class="o">);</span>
<span class="n">OMElement</span> <span class="n">result</span> <span class="o">=</span> <span class="n">sender</span><span class="o">.</span><span class="na">sendReceive</span><span class="o">(</span><span class="n">method</span><span class="o">);</span>
<span class="n">sender</span><span class="o">.</span><span class="na">cleanupTransport</span><span class="o">();</span></code></pre></div></description>
</item>
<item>
<title>tcp connect can't establish</title>
<link>http://tacy.github.io/post/network-troubleshooting-tcp-connect-cant-established/</link>
<pubDate>Tue, 12 Mar 2019 00:00:00 +0000</pubDate>
<guid>http://tacy.github.io/post/network-troubleshooting-tcp-connect-cant-established/</guid>
<description>
<p>最近碰到一起网络故障,有代表意义,记录下过程</p>
<h1 id="故障现象">故障现象</h1>
<p>客户系统频繁报调用超时,检查后端服务提供方日志,并没有发现服务调用异常情况,服务调用时长都控制在5S以内。</p>
<h1 id="故障分析">故障分析</h1>
<p>分析调用方日志,由于我们在sdk里面提供了uuid作为requestid,调用方的异常日志都记录了该字段。我们通过该字段去查后端服务的日志,在日志中并没有发现该requestid。也就是会说,请求并没有调用到后端服务,问题应该出现在网络上。</p>
<p>由于网络环境比较复杂,中间有防火墙和F5以及多层交换设备,我们先是在客户端进行了简单的抓包。</p>
<p>通过异常日志中的requestid,在捕获包中查找(通过tcp contains过滤),结果却找不到对应的数据包,也就是说请求并没有发出去,怀疑tcp连接应该是没有建立。</p>
<p>继续分析,发现网络中存在大量的syn包重传,下面截取了一个典型的例子:
<img src="http://tacy.github.io/img/tcp-tw-reuse-1.png" alt="wireshark sack" /></p>
<p>可以看到,tcp进行了5次syn包重传(linux默认),花了60多秒的时间,而调用方的服务调用超时设置的是60秒,也就是说连接没有建立,请求直接超时了。这也就解释了为什么在后台服务提供方的日志中并没有发现对应的requestid。</p>
<p>检查调用方和服务提供方网络,并没有发现明显的异常,为什么偏偏只丢syn包呢?接下来又在F5端和服务提供方网络进行抓包分析,发现异常。</p>
<p>先来看看F5的包:</p>
<div class="highlight"><pre class="chroma"><code class="language-text" data-lang="text">140994 689.875661 10.24.20.249 → 10.24.20.26 TCP 0 0 0.000000000 0 29200 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3135523389 TSecr=0 WS=128
144871 719.924532 10.24.20.26 → 10.24.20.249 TCP 1 887 30.048871000 0 220 [TCP ACKed unseen segment] 8080 → 57011 [FIN, ACK] Seq=1 Ack=887 Win=220 Len=0 TSval=2612910209 TSecr=3135523404
144872 719.924548 10.24.20.51 → 10.24.18.13 TCP 1 1 0.000000000 0 220 8080 → 57011 [FIN, ACK] Seq=1 Ack=1 Win=220 Len=0 TSval=2612910209 TSecr=3135523404
144877 719.963860 10.24.18.13 → 10.24.20.51 TCP 1 2 0.039312000 0 625 57011 → 8080 [ACK] Seq=1 Ack=2 Win=625 Len=0 TSval=3135553478 TSecr=2612910209
144878 719.963869 10.24.20.249 → 10.24.20.26 TCP 887 2 0.039337000 0 80000 [TCP Previous segment not captured] 57011 → 8080 [ACK] Seq=887 Ack=2 Win=80000 Len=0 TSval=3135553478 TSecr=2612910209
148017 741.416886 10.24.18.13 → 10.24.20.51 TCP 1 2 21.453026000 0 625 57011 → 8080 [FIN, ACK] Seq=1 Ack=2 Win=625 Len=0 TSval=3135574931 TSecr=2612910209
148018 741.416892 10.24.20.249 → 10.24.20.26 TCP 887 2 21.453023000 0 80000 57011 → 8080 [FIN, ACK] Seq=887 Ack=2 Win=80000 Len=0 TSval=3135574931 TSecr=2612910209
148021 741.417014 10.24.20.26 → 10.24.20.249 TCP 2 888 0.000122000 0 220 [TCP ACKed unseen segment] 8080 → 57011 [ACK] Seq=2 Ack=888 Win=220 Len=0 TSval=2612931702 TSecr=3135574931
148022 741.417047 10.24.20.51 → 10.24.18.13 TCP 2 2 0.000161000 0 220 8080 → 57011 [ACK] Seq=2 Ack=2 Win=220 Len=0 TSval=2612931702 TSecr=3135574931
150058 750.708540 10.24.20.249 → 10.24.20.26 TCP 0 0 0.000000000 0 29200 [TCP Port numbers reused] 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3134415069 TSecr=0 WS=128
150136 751.711154 10.24.18.14 → 10.24.20.51 TCP 0 0 0.000000000 0 29200 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3134416072 TSecr=0 WS=128
150137 751.711159 10.24.20.249 → 10.24.20.26 TCP 0 0 1.002619000 0 29200 [TCP Retransmission] 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3134416072 TSecr=0 WS=128
150545 753.715177 10.24.18.14 → 10.24.20.51 TCP 0 0 2.004023000 0 29200 [TCP Retransmission] 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3134418076 TSecr=0 WS=128
150546 753.715187 10.24.20.249 → 10.24.20.26 TCP 0 0 2.004028000 0 29200 [TCP Retransmission] 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3134418076 TSecr=0 WS=128
151292 757.719161 10.24.18.14 → 10.24.20.51 TCP 0 0 4.003984000 0 29200 [TCP Retransmission] 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3134422080 TSecr=0 WS=128
151293 757.719183 10.24.20.249 → 10.24.20.26 TCP 0 0 4.003996000 0 29200 [TCP Retransmission] 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3134422080 TSecr=0 WS=128
152398 765.735191 10.24.18.14 → 10.24.20.51 TCP 0 0 8.016030000 0 29200 [TCP Retransmission] 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3134430096 TSecr=0 WS=128
152399 765.735201 10.24.20.249 → 10.24.20.26 TCP 0 0 8.016018000 0 29200 [TCP Retransmission] 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3134430096 TSecr=0 WS=128
158405 781.783166 10.24.18.14 → 10.24.20.51 TCP 0 0 16.047975000 0 29200 [TCP Retransmission] 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3134446144 TSecr=0 WS=128
158406 781.783177 10.24.20.249 → 10.24.20.26 TCP 0 0 16.047976000 0 29200 [TCP Retransmission] 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3134446144 TSecr=0 WS=128
175385 881.982585 10.24.20.51 → 10.107.209.51 TCP 1 1 0.000000000 0 229 8080 → 57011 [FIN, ACK] Seq=1 Ack=1 Win=229 Len=0 TSval=2613072267 TSecr=333623407
175394 882.059551 10.107.209.51 → 10.24.20.51 TCP 1 2 0.076966000 0 5988 57011 → 8080 [ACK] Seq=1 Ack=2 Win=5988 Len=0 TSval=333653945 TSecr=2613072267</code></pre></div>
<p>249代表F5地址,26是服务提供方服务器地址,上面信息显示,F5重用了端口(包150058)和26进行连接,连发了5个syn包,看起来是丢包了。</p>
<p>但是我们来看看服务提供方包:</p>
<div class="highlight"><pre class="chroma"><code class="language-text" data-lang="text">136316 654.713264 10.24.20.249 → 10.24.20.26 TCP 0 0 0.000000000 0 29200 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3135523389 TSecr=0 WS=128
136317 654.713292 10.24.20.26 → 10.24.20.249 TCP 0 1 0.000028000 0 28960 8080 → 57011 [SYN, ACK] Seq=0 Ack=1 Win=28960 Len=0 MSS=1460 SACK_PERM=1 TSval=2612880161 TSecr=3135523389 WS=128
136318 654.713558 10.24.20.249 → 10.24.20.26 TCP 1 1 0.000266000 0 29312 57011 → 8080 [ACK] Seq=1 Ack=1 Win=29312 Len=0 TSval=3135523390 TSecr=2612880161
136319 654.713747 10.24.20.249 → 10.24.20.26 HTTP 1 1 0.000189000 182 29312 POST /default/WSWorkItemManagerService?wsdl HTTP/1.1
136320 654.713759 10.24.20.26 → 10.24.20.249 TCP 1 183 0.000012000 0 28800 8080 → 57011 [ACK] Seq=1 Ack=183 Win=28800 Len=0 TSval=2612880161 TSecr=3135523390
136321 654.713814 10.24.20.249 → 10.24.20.26 HTTP 183 1 0.000055000 704 29312 Continuation
136322 654.713824 10.24.20.26 → 10.24.20.249 TCP 1 887 0.000010000 0 28160 8080 → 57011 [ACK] Seq=1 Ack=887 Win=28160 Len=0 TSval=2612880161 TSecr=3135523390
136323 654.727617 10.24.20.26 → 10.24.20.249 HTTP 1 887 0.013793000 8192 28160 HTTP/1.1 200 OK [Unreassembled Packet]
136324 654.727706 10.24.20.26 → 10.24.20.249 HTTP 8193 887 0.000089000 5792 28160 Continuation
136325 654.727915 10.24.20.249 → 10.24.20.26 TCP 887 8193 0.000209000 0 45696 57011 → 8080 [ACK] Seq=887 Ack=8193 Win=45696 Len=0 TSval=3135523404 TSecr=2612880175
136326 654.727928 10.24.20.26 → 10.24.20.249 HTTP 13985 887 0.000013000 11386 28160 Continuation
136327 654.728040 10.24.20.249 → 10.24.20.26 TCP 887 11089 0.000112000 0 51456 57011 → 8080 [ACK] Seq=887 Ack=11089 Win=51456 Len=0 TSval=3135523404 TSecr=2612880175
136328 654.728049 10.24.20.249 → 10.24.20.26 TCP 887 11089 0.000009000 0 54272 [TCP Window Update] 57011 → 8080 [ACK] Seq=887 Ack=11089 Win=54272 Len=0 TSval=3135523404 TSecr=2612880175 SLE=12537 SRE=13985
136329 654.728056 10.24.20.249 → 10.24.20.26 TCP 887 13985 0.000007000 0 57216 57011 → 8080 [ACK] Seq=887 Ack=13985 Win=57216 Len=0 TSval=3135523404 TSecr=2612880175
136330 654.728202 10.24.20.249 → 10.24.20.26 TCP 887 25371 0.000146000 0 80000 57011 → 8080 [ACK] Seq=887 Ack=25371 Win=80000 Len=0 TSval=3135523404 TSecr=2612880175
142165 684.762029 10.24.20.26 → 10.24.20.249 TCP 25371 887 30.033827000 0 28160 8080 → 57011 [FIN, ACK] Seq=25371 Ack=887 Win=28160 Len=0 TSval=2612910209 TSecr=3135523404
142174 684.801477 10.24.20.249 → 10.24.20.26 TCP 887 25372 0.039448000 0 80000 57011 → 8080 [ACK] Seq=887 Ack=25372 Win=80000 Len=0 TSval=3135553478 TSecr=2612910209
146703 706.254510 10.24.20.249 → 10.24.20.26 TCP 887 25372 21.453033000 0 80000 57011 → 8080 [FIN, ACK] Seq=887 Ack=25372 Win=80000 Len=0 TSval=3135574931 TSecr=2612910209
146704 706.254518 10.24.20.26 → 10.24.20.249 TCP 25372 888 0.000008000 0 28160 8080 → 57011 [ACK] Seq=25372 Ack=888 Win=28160 Len=0 TSval=2612931702 TSecr=3135574931
148567 715.546271 10.24.20.249 → 10.24.20.26 TCP 0 0 0.000000000 0 29200 [TCP Port numbers reused] 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3134415069 TSecr=0 WS=128
148568 715.546299 10.24.20.26 → 10.24.20.249 TCP 1 3942326266 0.000028000 0 220 8080 → 57011 [ACK] Seq=1 Ack=3942326266 Win=220 Len=0 TSval=2612940994 TSecr=3135574931
148672 716.548784 10.24.20.249 → 10.24.20.26 TCP 0 0 1.002485000 0 29200 [TCP Retransmission] 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3134416072 TSecr=0 WS=128
148673 716.548800 10.24.20.26 → 10.24.20.249 TCP 1 3942326266 0.000016000 0 220 [TCP Dup ACK 148568#1] 8080 → 57011 [ACK] Seq=1 Ack=3942326266 Win=220 Len=0 TSval=2612941996 TSecr=3135574931
149153 718.552810 10.24.20.249 → 10.24.20.26 TCP 0 0 2.004010000 0 29200 [TCP Retransmission] 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3134418076 TSecr=0 WS=128
149154 718.552831 10.24.20.26 → 10.24.20.249 TCP 1 3942326266 0.000021000 0 220 [TCP Dup ACK 148568#2] 8080 → 57011 [ACK] Seq=1 Ack=3942326266 Win=220 Len=0 TSval=2612944000 TSecr=3135574931
150128 722.556839 10.24.20.249 → 10.24.20.26 TCP 0 0 4.004008000 0 29200 [TCP Retransmission] 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3134422080 TSecr=0 WS=128
150129 722.556858 10.24.20.26 → 10.24.20.249 TCP 1 3942326266 0.000019000 0 220 [TCP Dup ACK 148568#3] 8080 → 57011 [ACK] Seq=1 Ack=3942326266 Win=220 Len=0 TSval=2612948004 TSecr=3135574931
151923 730.572850 10.24.20.249 → 10.24.20.26 TCP 0 0 8.015992000 0 29200 [TCP Retransmission] 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3134430096 TSecr=0 WS=128
151924 730.572871 10.24.20.26 → 10.24.20.249 TCP 1 3942326266 0.000021000 0 220 [TCP Dup ACK 148568#4] 8080 → 57011 [ACK] Seq=1 Ack=3942326266 Win=220 Len=0 TSval=2612956020 TSecr=3135574931
155688 746.620837 10.24.20.249 → 10.24.20.26 TCP 0 0 16.047966000 0 29200 [TCP Retransmission] 57011 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3134446144 TSecr=0 WS=128
155689 746.620857 10.24.20.26 → 10.24.20.249 TCP 1 3942326266 0.000020000 0 220 [TCP Dup ACK 148568#5] 8080 → 57011 [ACK] Seq=1 Ack=3942326266 Win=220 Len=0 TSval=2612972068 TSecr=3135574931</code></pre></div>
<p>tcp连接正常终止在包(142165,142174,146703,146704),接下来249在9秒之后,重用了同样的端口向26发起连接(包148567),26接收到syn包之后,回了一个ack包?不是一个syn/ack包?而且ack number = 3942326266</p>
<p>其实容易理解,由于26是active close一方,当连接终止之后,依然处于time_wait状态,这个时候,249重用了端口进行新的连接,可是这个连接在26上依然存在(处于time_wait状态),看到249发过来的syn包,和自己目前连接的sequence number一比,发现比自己目前的sequence number小,直接回一个ACK包告诉对方你给我发什么乱七八糟的东西,我期待下一个包的sequence number是3942326266,然后默默的把249发过来的SYN包扔掉了。。。</p>
<h1 id="解决思路">解决思路</h1>
<p>tcp连接的time_wait状态是用来保护连接的,linux把这个值写死在代码中(TCP_TIMEWAIT_LEN=60秒),除非自己编译源代码修改(不建议缩短这个值,容易导致连接损坏,或者连接关闭不完全)</p>
<p>在本系统中,由于服务提供方(26)设置的线程keepalive时间为30S,30S之后,会主动断开连接,连接就会进入time_wait状态;客户端连接被释放之后,很快用这个端口再次发起连接,导致了连接无法建立正常,我们简单的把keepalive参数设置为不超时,暂时缓解了该问题。</p>
<h1 id="后续">后续</h1>
<p>由于系统中,前端和后端调用量很大,中间的F5很容易导致类似问题,优化方向参考:</p>
<ol>
<li>增加客户端的可用端口数量(net.ipv4.ip_local_port_range)</li>
<li>增加F5的出口ip数量,缓解端口问题</li>
<li>增加服务端的server监听ip,缓解端口重用问题</li>
<li>修改调用端代码,重用tcp连接</li>
</ol>
<h1 id="参考">参考</h1>
<ol>
<li>TCP连接的状态变化参考下图:
<img src="http://tacy.github.io/img/tcp-state-diagram-v2.svg" alt="tcp state diagram" /></li>
</ol>
<p>2.</p>
</description>
</item>
<item>
<title>binary notes</title>
<link>http://tacy.github.io/post/binary/</link>
<pubDate>Sat, 05 Jan 2019 00:00:00 +0000</pubDate>
<guid>http://tacy.github.io/post/binary/</guid>
<description>
<p>编译之后产生的二进制文件,有很多种不同的格式,一般在linux下,elf是最常用的,如果没有特殊说明,这里指的都是elf格式的二进制文件</p>
<h1 id="elf">ELF</h1>
<h2 id="readelf">readelf</h2>
<ul>
<li>To retrieve a section header table:<code>readelf -S &lt;object&gt;</code></li>
<li>To retrieve a program header table: <code>readelf -l &lt;object&gt;</code></li>
<li>To retrieve a symbol table: <code>readelf -s &lt;object&gt;</code></li>
<li>To retrieve the ELF file header data: <code>readelf -e &lt;object&gt;</code></li>
<li>To retrieve relocation entries: <code>readelf -r &lt;object&gt;</code></li>
<li>To retrieve a dynamic segment: <code>readelf -d &lt;object&gt;</code></li>
</ul>
<h1 id="little-endian-big-endian">little endian &amp; big endian</h1>
<p>little endian: 9A9B9C9D =&gt; (9D-&gt;0x1000, 9C-&gt;0x1001, 9B-&gt;0x1002, 9A-&gt;0x1003)
big endian则相反,存储成 (9A-&gt;0x1000, 9B-&gt;0x1001, 9C-&gt;0x1002, 9D-&gt;0x1003)</p>
<p>x86架构用的是little endian</p>
<h1 id="stack-frame">stack frame</h1>
<h2 id="x86-1">x86<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup></h2>
<p>x86在调用的时候,参数不会入register,都是压在栈里面,callee直接通过esp偏移找参数,简单代码示例:</p>
<div class="highlight"><pre class="chroma">void
bar(int a, int b)
{
int x, y;
x = 555;
y = a+b;
}
void
foo(void) {
bar(111,222);
}</pre></div>
<p>foo被调用的时候,会把111,222存入到当前自己的stack frame,注意是从右到做入栈,所以他会做如下操作:</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell"><span class="nv">esp</span> <span class="o">=</span> 当前esp - <span class="m">8</span>
<span class="m">222</span> 存入esp-4
<span class="m">111</span> 存入esp-8
开始调用bar,之前先把返回地址存入栈 <span class="o">(</span>4bytes<span class="o">)</span></code></pre></div>
<p>接下来,调用bar:</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">保存foo的ebp <span class="o">(</span>4bytes<span class="o">)</span>
把esp塞入ebp,目前esp在的位置就是bar的ebp
<span class="nv">esp</span> <span class="o">=</span> 当前esp - <span class="m">16</span>
<span class="m">555</span> 存入当前esp - <span class="m">4</span>
取出a的值从<span class="o">(</span>%ebp<span class="o">)</span>+8, 放入%eax
取出b的值从<span class="o">(</span>%ebp<span class="o">)</span>+12,放入%edx
求和放入ebp-8
弹出保存的ebp,放入%ebp,重设esp为返回地址</code></pre></div>
<h2 id="x64-2">x64<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup></h2>
<p>看看下面代码,基本上你就大概知道x64是使用寄存器和栈一起在函数调用之间传递参数:</p>
<div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="kt">int</span> <span class="nf">foobar</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">,</span> <span class="kt">int</span> <span class="n">c</span><span class="p">,</span> <span class="kt">int</span> <span class="n">d</span><span class="p">,</span> <span class="kt">int</span> <span class="n">e</span><span class="p">,</span> <span class="kt">int</span> <span class="n">f</span><span class="p">,</span> <span class="kt">int</span> <span class="n">g</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">int</span> <span class="n">aa</span> <span class="o">=</span> <span class="n">a</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">bb</span> <span class="o">=</span> <span class="n">b</span> <span class="o">+</span> <span class="mi">2</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">cc</span> <span class="o">=</span> <span class="n">c</span> <span class="o">+</span> <span class="mi">3</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">dd</span> <span class="o">=</span> <span class="n">d</span> <span class="o">+</span> <span class="mi">4</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">ee</span> <span class="o">=</span> <span class="n">e</span> <span class="o">+</span> <span class="mi">5</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">ff</span> <span class="o">=</span> <span class="n">f</span> <span class="o">+</span> <span class="mi">6</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">gg</span> <span class="o">=</span> <span class="n">g</span> <span class="o">+</span> <span class="mi">6</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">sum</span> <span class="o">=</span> <span class="n">aa</span> <span class="o">+</span> <span class="n">bb</span> <span class="o">+</span> <span class="n">cc</span> <span class="o">+</span> <span class="n">dd</span> <span class="o">+</span> <span class="n">ee</span> <span class="o">+</span> <span class="n">ff</span> <span class="o">+</span> <span class="n">gg</span><span class="p">;</span>
<span class="k">return</span> <span class="n">aa</span> <span class="o">*</span> <span class="n">bb</span> <span class="o">*</span> <span class="n">cc</span> <span class="o">*</span> <span class="n">dd</span> <span class="o">*</span> <span class="n">ee</span> <span class="o">*</span> <span class="n">ff</span> <span class="o">*</span> <span class="n">gg</span> <span class="o">+</span> <span class="n">sum</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
<span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="n">foobar</span><span class="p">(</span><span class="mi">33</span><span class="p">,</span> <span class="mi">44</span><span class="p">,</span> <span class="mi">55</span><span class="p">,</span> <span class="mi">66</span><span class="p">,</span> <span class="mi">77</span><span class="p">,</span> <span class="mi">88</span><span class="p">,</span> <span class="mi">99</span><span class="p">);</span>
<span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>汇编代码<code>gcc -fno-asynchronous-unwind-tables -masm=intel -S simple.c -o simple.s</code></p>
<div class="highlight"><pre class="chroma"><code class="language-assembly" data-lang="assembly"> .file &#34;simple.c&#34;
.intel_syntax noprefix
.text
.globl foobar
.type foobar, @function
foobar:
push rbp
mov rbp, rsp
mov DWORD PTR -36[rbp], edi
mov DWORD PTR -40[rbp], esi
mov DWORD PTR -44[rbp], edx
mov DWORD PTR -48[rbp], ecx
mov DWORD PTR -52[rbp], r8d
mov DWORD PTR -56[rbp], r9d
mov eax, DWORD PTR -36[rbp]
add eax, 1
mov DWORD PTR -32[rbp], eax
mov eax, DWORD PTR -40[rbp]
add eax, 2
mov DWORD PTR -28[rbp], eax
mov eax, DWORD PTR -44[rbp]
add eax, 3
mov DWORD PTR -24[rbp], eax
mov eax, DWORD PTR -48[rbp]
add eax, 4
mov DWORD PTR -20[rbp], eax
mov eax, DWORD PTR -52[rbp]
add eax, 5
mov DWORD PTR -16[rbp], eax
mov eax, DWORD PTR -56[rbp]
add eax, 6
mov DWORD PTR -12[rbp], eax
mov eax, DWORD PTR 16[rbp]
add eax, 6
mov DWORD PTR -8[rbp], eax
mov edx, DWORD PTR -32[rbp]
mov eax, DWORD PTR -28[rbp]
add edx, eax
mov eax, DWORD PTR -24[rbp]
add edx, eaxn
mov eax, DWORD PTR -20[rbp]
add edx, eax
mov eax, DWORD PTR -16[rbp]
add edx, eax
mov eax, DWORD PTR -12[rbp]
add edx, eax
mov eax, DWORD PTR -8[rbp]
add eax, edx
mov DWORD PTR -4[rbp], eax
mov eax, DWORD PTR -32[rbp]
imul eax, DWORD PTR -28[rbp]
imul eax, DWORD PTR -24[rbp]
imul eax, DWORD PTR -20[rbp]
imul eax, DWORD PTR -16[rbp]
imul eax, DWORD PTR -12[rbp]
imul eax, DWORD PTR -8[rbp]
mov edx, eax
mov eax, DWORD PTR -4[rbp]
add eax, edx
pop rbp
ret
.size foobar, .-foobar
.globl main
.type main, @function
main:
push rbp
mov rbp, rsp
sub rsp, 16
push 99
mov r9d, 88
mov r8d, 77
mov ecx, 66
mov edx, 55
mov esi, 44
mov edi, 33
call foobar
add rsp, 8
mov DWORD PTR -4[rbp], eax
mov eax, DWORD PTR -4[rbp]
add eax, 1
leave
ret
.size main, .-main
.ident &#34;GCC: (GNU) 8.2.1 20180831&#34;
.section .note.GNU-stack,&#34;&#34;,@progbits</code></pre></div>
<p>caller负责把前面六个参数入寄存器(整型和指针类型,其他类型请参考规范calling conventions),依次是edi,esi,edx,ecx,r8d,r9d,第七个以后的参数入栈。说明一下,由于这里的参数都是整型,4字节,所以寄存器都是用的4字节寄存器,如果是8字节,e改为r,例如rdi</p>
<p>callee会先保存caller的rbp(当前的frame pointer),然后保存当前rsp(strack pointer)为自己栈帧的rbp,接下来移动rsp,分配栈空间给参数或者内部变量使用。</p>
<p>callee会把返回结果放入到eax,如果结果超过8byte,可以增加一个寄存器edx来存放返回结果,如果超过16字节,可能会更复杂点,caller会在自己的栈分配一块空间,然后把指针当成callee的第一个参数放入rdi,其他参数依次往后移一位。caller可以从eax获取到返回结果(或者更复杂)。可以看kernel代码<code>arch/x86/entry/calling.h</code>:</p>
<div class="highlight"><pre class="chroma"><code class="language-assembly" data-lang="assembly"> x86 function call convention, 64-bit:
-------------------------------------
arguments | callee-saved | extra caller-saved | return
[callee-clobbered] | | [callee-clobbered] |
---------------------------------------------------------------------------
rdi rsi rdx rcx r8-9 | rbx rbp [*] r12-15 | r10-11 | rax, rdx [**]
( rsp is obviously invariant across normal function calls. (gcc can &#39;merge&#39;
functions when it sees tail-call optimization possibilities) rflags is
clobbered. Leftover arguments are passed over the stack frame.)
[*] In the frame-pointers case rbp is fixed to the stack frame.
[**] for struct return values wider than 64 bits the return convention is a
bit more complex: up to 128 bits width we return small structures
straight in rax, rdx. For structures larger than that (3 words or
larger) the caller puts a pointer to an on-stack return struct
[allocated in the caller&#39;s stack frame] into the first argument - i.e.
into rdi. All other arguments shift up by one in this case.
Fortunately this case is rare in the kernel.</code></pre></div>
<p>如果编译的时候启用了<code>-fomit-frame-pointer</code>选项,会优化掉rbp的使用,也就是不使用rbp做frame pointer,优化后的结果:</p>
<div class="highlight"><pre class="chroma"><code class="language-assembly" data-lang="assembly">main:
sub rsp, 16
push 99
mov r9d, 88
mov r8d, 77
mov ecx, 66
mov edx, 55
mov esi, 44
mov edi, 33
call foobar
add rsp, 8
mov DWORD PTR 12[rsp], eax
mov eax, DWORD PTR 12[rsp]
add eax, 1
add rsp, 16
ret
.size main, .-main
.ident &#34;GCC: (GNU) 8.2.1 20180831&#34;
.section .note.GNU-stack,&#34;&#34;,@progbits</code></pre></div>
<h1 id="x84-64-date-types">x84-64 date types</h1>
<table>
<thead>
<tr>
<th>C declaration</th>
<th>Intel data type</th>
<th>GAS suffix</th>
<th>x86-64 Size (Bytes)</th>
</tr>
</thead>
<tbody>
<tr>
<td>char</td>
<td>Byte</td>
<td>b</td>
<td>1</td>
</tr>
<tr>
<td>short</td>
<td>Word</td>
<td>w</td>
<td>2</td>
</tr>
<tr>
<td>int</td>
<td>Double word</td>
<td>l</td>
<td>4</td>
</tr>
<tr>
<td>unsigned</td>
<td>Double word</td>
<td>l</td>
<td>4</td>
</tr>
<tr>
<td>long</td>
<td>int</td>
<td>Quad word</td>
<td>q</td>
</tr>
<tr>
<td>unsigned long</td>
<td>Quad word</td>
<td>q</td>
<td>8</td>
</tr>
<tr>
<td>char *</td>
<td>Quad word</td>
<td>q</td>
<td>8</td>
</tr>
<tr>
<td>float</td>
<td>Single precision</td>
<td>s</td>
<td>4</td>
</tr>
<tr>
<td>double</td>
<td>Double precision</td>
<td>d</td>
<td>8</td>
</tr>
<tr>
<td>long double</td>
<td>Extended precision</td>
<td>t</td>
<td>16</td>
</tr>
</tbody>
</table>
<p>char * 指针64bit</p>
<h1 id="pie-pic-3-4-5">PIE / PIC<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup><sup class="footnote-ref" id="fnref:4"><a href="#fn:4">4</a></sup><sup class="footnote-ref" id="fnref:5"><a href="#fn:5">5</a></sup></h1>
<p>在我的archlinux上(2018年12月的更新),gcc默认启用了pic和pie,会导致加载地址随机:</p>
<p>PIC全名Postion Independent Codes,实现共享库的加载地址不固定,地址需要loader在加载时确定。</p>
<p>PIE是指Position Independent Executables, 实现可执行文件的加载地址不固定(没有PIE之前,可执行文件默认会从固定地址加载,例如0x400000作为base加载地址<sup class="footnote-ref" id="fnref:6"><a href="#fn:6">6</a></sup>)。</p>
<div class="highlight"><pre class="chroma">➜ cat simple.c
#include &lt;stdio.h&gt;
int foobar(int *a, int b, int c, int d, int e, int f, int g)
{
int aa = *a + 1;
int bb = b + 2;
int cc = c + 3;
int dd = d + 4;
int ee = e + 5;
int ff = f + 6;
int gg = g + 6;
int sum = aa + bb + cc + dd + ee + ff + gg;
return aa * bb * cc * dd * ee * ff * gg + sum;
}
int main()
{
int b = 111;
int a = foobar(&amp;b, 44, 55, 66, 77, 88, 99);
printf(&#34;hello world&#34;);
return a + 1;
}</pre></div>
<h2 id="默认编译-fpic-fpie">默认编译(-fPIC -fPIE):</h2>
<div class="highlight"><pre class="chroma">➜ binary-study &gt; objdump -t simple|grep text
0000000000001050 l d .text 0000000000000000 .text
0000000000001080 l F .text 0000000000000000 deregister_tm_clones
00000000000010b0 l F .text 0000000000000000 register_tm_clones
00000000000010f0 l F .text 0000000000000000 __do_global_dtors_aux
0000000000001140 l F .text 0000000000000000 frame_dummy
00000000000012e0 g F .text 0000000000000005 __libc_csu_fini
0000000000001149 g F .text 00000000000000a3 foobar
0000000000001270 g F .text 0000000000000065 __libc_csu_init
0000000000001050 g F .text 000000000000002f _start
00000000000011ec g F .text 000000000000007b main
➜ binary-study &gt; gdb simple
...
Reading symbols from simple...(no debugging symbols found)...done.
(gdb) b main
Breakpoint 1 at 0x11f0 # 这个地址不是虚拟地址,真正的地址需要运行时确认
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000000011f0 &lt;main+4&gt;
(gdb) run
Starting program: /home/tacy/workspace/binary-study/simple
Breakpoint 1, 0x00005555555551f0 in main () # 地址确认,替换成真正的虚拟地址
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x00005555555551f0 &lt;main+4&gt;
breakpoint already hit 1 time
(gdb) info address main
Symbol &#34;main&#34; is at 0x5555555551ec in a file compiled without debugging.
➜ binary-study &gt; cat /proc/`pidof simple`/maps # 加载地址,不是传统的0x4000000
555555554000-555555555000 r--p 00000000 08:06 10403523 /home/tacy/workspace/binary-study/simple
555555555000-555555556000 r-xp 00001000 08:06 10403523 /home/tacy/workspace/binary-study/simple
555555556000-555555557000 r--p 00002000 08:06 10403523 /home/tacy/workspace/binary-study/simple
555555557000-555555558000 r--p 00002000 08:06 10403523 /home/tacy/workspace/binary-study/simple
555555558000-555555559000 rw-p 00003000 08:06 10403523 /home/tacy/workspace/binary-study/simple</pre></div>
<p>编译的时候开启pic和pie,symbol的地址需要在运行时确认(必须先运行才知道地址)</p>
<h2 id="禁用pie和pic">禁用PIE和PIC</h2>
<div class="highlight"><pre class="chroma">➜ binary-study gcc -no-pie simple.c -o simple
➜ binary-study objdump -t simple|grep text
0000000000401050 l d .text 0000000000000000 .text
0000000000401090 l F .text 0000000000000000 deregister_tm_clones
00000000004010c0 l F .text 0000000000000000 register_tm_clones
0000000000401100 l F .text 0000000000000000 __do_global_dtors_aux
0000000000401130 l F .text 0000000000000000 frame_dummy
00000000004012d0 g F .text 0000000000000005 __libc_csu_fini
0000000000401136 g F .text 00000000000000a3 foobar
0000000000401260 g F .text 0000000000000065 __libc_csu_init
0000000000401080 g F .text 0000000000000005 .hidden _dl_relocate_static_pie
0000000000401050 g F .text 000000000000002f _start
00000000004011d9 g F .text 0000000000000079 main
➜ binary-study gdb simple
...
Reading symbols from simple...(no debugging symbols found)...done.
(gdb) info address main
Symbol &#34;main&#34; is at 0x4011d9 in a file compiled without debugging.
(gdb) b main
Breakpoint 1 at 0x4011dd
(gdb) run
Starting program: /home/tacy/workspace/binary-study/simple
Breakpoint 1, 0x00000000004011dd in main ()
(gdb)
➜ binary-study cat /proc/`pidof simple`/maps
00400000-00401000 r--p 00000000 08:06 10358659 /home/tacy/workspace/binary-study/simple
00401000-00402000 r-xp 00001000 08:06 10358659 /home/tacy/workspace/binary-study/simple
00402000-00403000 r--p 00002000 08:06 10358659 /home/tacy/workspace/binary-study/simple
00403000-00404000 r--p 00002000 08:06 10358659 /home/tacy/workspace/binary-study/simple
00404000-00405000 rw-p 00003000 08:06 10358659 /home/tacy/workspace/binary-study/simple</pre></div>
<h2 id="启用enable-default-pie编译选项的gcc">启用enable-default-pie编译选项的gcc</h2>
<p>如果你的gcc启用了enable-default-pie,那么你编译程序的时候,默认就带上<code>-fPIC -fPIE</code>参数(可以通过-Q -v观察)</p>
<p>想要禁用pic/pie,按照下面方式编译:</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">➜ binary-study&gt; gcc -mcmodel<span class="o">=</span>large -fno-PIC -c piepic.c -o piepic.o
➜ binary-study&gt; gcc -mcmodel<span class="o">=</span>large -no-pie -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -shared -o libpiepic.so piepic.o
➜ binary-study&gt; file libpiepic.so
libpiepic.so: ELF <span class="m">64</span>-bit LSB shared object, x86-64, version <span class="m">1</span> <span class="o">(</span>SYSV<span class="o">)</span>, dynamically linked, BuildID<span class="o">[</span>sha1<span class="o">]=</span>3b01764ad66d87aa17a43c5cc52ccae070638ad6, not stripped
➜ binary-study readelf -r libpiepic.so
Relocation section <span class="s1">&#39;.rela.dyn&#39;</span> at offset 0x3f8 contains <span class="m">12</span> entries:
Offset Info Type Sym. Value Sym. Name + Addend
0000000010ef <span class="m">000000000008</span> R_X86_64_RELATIVE 400c
0000000010f9 <span class="m">000000000008</span> R_X86_64_RELATIVE <span class="m">2000</span>
<span class="m">000000001114</span> <span class="m">000000000008</span> R_X86_64_RELATIVE <span class="m">2012</span>
000000003e08 <span class="m">000000000008</span> R_X86_64_RELATIVE 10e0
000000003e10 <span class="m">000000000008</span> R_X86_64_RELATIVE <span class="m">1090</span>
<span class="m">000000004000</span> <span class="m">000000000008</span> R_X86_64_RELATIVE <span class="m">4000</span>
<span class="m">000000001108</span> <span class="m">000300000001</span> R_X86_64_64 <span class="m">0000000000000000</span> printf@GLIBC_2.2.5 + <span class="m">0</span>
00000000111e <span class="m">000200000001</span> R_X86_64_64 <span class="m">0000000000000000</span> puts@GLIBC_2.2.5 + <span class="m">0</span>
000000003fe0 <span class="m">000100000006</span> R_X86_64_GLOB_DAT <span class="m">0000000000000000</span> _ITM_deregisterTMClone + <span class="m">0</span>
000000003fe8 <span class="m">000400000006</span> R_X86_64_GLOB_DAT <span class="m">0000000000000000</span> __gmon_start__ + <span class="m">0</span>
000000003ff0 <span class="m">000500000006</span> R_X86_64_GLOB_DAT <span class="m">0000000000000000</span> _ITM_registerTMCloneTa + <span class="m">0</span>
000000003ff8 <span class="m">000600000006</span> R_X86_64_GLOB_DAT <span class="m">0000000000000000</span> __cxa_finalize@GLIBC_2.2.5 + <span class="m">0</span>
➜ binary-study&gt; gcc -no-pie -o client_nopie client_piepic.c libpiepic.so
➜ binary-study ./client_nopie <span class="c1"># ASLR设置为1的情况</span>
shared_v at 0xca3f800c
hello
value at 0x40403c
➜ binary-study ./client_nopie <span class="c1"># ASLR设置为1的情况,设置为2,全部随机加载了</span>
shared_v at 0xa421900c
hello
value at 0x40403c</code></pre></div>
<p>默认情况下的编译方式(启用pie/pic):</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">➜ binary-study gcc -c piepic.c -o piepic.o
➜ binary-study gcc -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -shared -o libpiepic.so piepic.o
➜ binary-study readelf -r libpiepic.so
Relocation section <span class="s1">&#39;.rela.dyn&#39;</span> at offset 0x3f8 contains <span class="m">7</span> entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000003dc8 <span class="m">000000000008</span> R_X86_64_RELATIVE <span class="m">1110</span>
000000003dd0 <span class="m">000000000008</span> R_X86_64_RELATIVE 10c0
<span class="m">000000004000</span> <span class="m">000000000008</span> R_X86_64_RELATIVE <span class="m">4000</span>
000000003fe0 <span class="m">000100000006</span> R_X86_64_GLOB_DAT <span class="m">0000000000000000</span> _ITM_deregisterTMClone + <span class="m">0</span>
000000003fe8 <span class="m">000400000006</span> R_X86_64_GLOB_DAT <span class="m">0000000000000000</span> __gmon_start__ + <span class="m">0</span>
000000003ff0 <span class="m">000500000006</span> R_X86_64_GLOB_DAT <span class="m">0000000000000000</span> _ITM_registerTMCloneTa + <span class="m">0</span>
000000003ff8 <span class="m">000600000006</span> R_X86_64_GLOB_DAT <span class="m">0000000000000000</span> __cxa_finalize@GLIBC_2.2.5 + <span class="m">0</span>
Relocation section <span class="s1">&#39;.rela.plt&#39;</span> at offset 0x4a0 contains <span class="m">2</span> entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000003fd0 <span class="m">000200000007</span> R_X86_64_JUMP_SLO <span class="m">0000000000000000</span> puts@GLIBC_2.2.5 + <span class="m">0</span>
000000003fd8 <span class="m">000300000007</span> R_X86_64_JUMP_SLO <span class="m">0000000000000000</span> printf@GLIBC_2.2.5 + <span class="m">0</span>
➜ binary-study gcc -o client client_piepic.c libpiepic.so
➜ binary-study ./client
shared_v at 0x3d4d900c
hello
value at 0xb29303c
➜ binary-study ./client
shared_v at 0xbbe9700c
hello
value at 0xc892303c</code></pre></div>
<p>不启用pic和pie,symbol的地址在编译的时候就确认了,可以直接使用</p>
<p>0 &gt; /proc/sys/kernel/randomize_va_space</p>
<h1 id="readelf-1">readelf</h1>
<p>elf格式工具,可以用来查看elf文件信息,例如segment,header,relocs等</p>
<h1 id="gcc">gcc</h1>
<h2 id="编译共享库">编译共享库</h2>
<p>gcc -march=x86-64 -mtune=generic -O2 -pipe -fstack-protector-strong -fno-plt -fno-PIC -c piepic.c -o piepic.o</p>
<p>显示编译选项启用情况: gcc -Q -v <input file></p>
<p>有main:
gcc -fno-PIC -no-pie -fno-stack-protector -c simple.c -o simple.o
gcc -shared -no-pie -o libsimple.so simple.o # no-pie必须在shared后面</p>
<h1 id="resource">resource</h1>
<ol>
<li><a href="http://tacy.github.io/resource/x86-64.pdf">Notes on x86-64 programming</a></li>
<li><a href="http://tacy.github.io/resource/asm64-handout.pdf">x86-64 Machine-Level Programming</a></li>
<li><a href="https://blog.k3170makan.com/2018/09/introduction-to-elf-format-elf-header.html">Introduction to the ELF Format</a></li>
</ol>
<div class="footnotes">
<hr />
<ol>
<li id="fn:1"><a href="https://www.cs.rutgers.edu/~pxk/419/notes/frames.html">stack frame for x86</a>
<a class="footnote-return" href="#fnref:1"><sup>[return]</sup></a></li>
<li id="fn:2"><a href="Stack frame layout on x86-64">stack frame for x64</a>
<a class="footnote-return" href="#fnref:2"><sup>[return]</sup></a></li>
<li id="fn:3"><a href="https://codywu2010.wordpress.com/2014/11/29/about-elf-pie-pic-and-else/">about ELF – PIE, PIC and else</a>
<a class="footnote-return" href="#fnref:3"><sup>[return]</sup></a></li>
<li id="fn:4"><a href="https://eli.thegreenplace.net/2011/08/25/load-time-relocation-of-shared-libraries">Load-time relocation of shared libraries</a>
<a class="footnote-return" href="#fnref:4"><sup>[return]</sup></a></li>
<li id="fn:5"><a href="https://eli.thegreenplace.net/2011/11/11/position-independent-code-pic-in-shared-libraries-on-x64">Position Independent Code (PIC) in shared libraries on x64</a>
<a class="footnote-return" href="#fnref:5"><sup>[return]</sup></a></li>
<li id="fn:6"><a href="https://blogs.msdn.microsoft.com/oldnewthing/20141003-00/?p=43923">Why is 0x00400000 the default base address for an executable?</a>
<a class="footnote-return" href="#fnref:6"><sup>[return]</sup></a></li>
</ol>
</div>
</description>
</item>
<item>
<title>Linux trace</title>
<link>http://tacy.github.io/post/trace/</link>
<pubDate>Wed, 02 Jan 2019 00:00:00 +0000</pubDate>
<guid>http://tacy.github.io/post/trace/</guid>
<description>
<p>对于linux下的trace,我建议你参考Brendan Gregg的文章:<a href="http://www.brendangregg.com/blog/2015-07-08/choosing-a-linux-tracer.html">Choosing a linux tracer</a>,里面详细列出了linux下每个tracer的介绍,本文里主要介绍ftrace,讨论function相关的部分,event和计数器不涉及。</p>
<p>下面我们从两个维度来看看ftrace在linux中的使用,首先是根据运行态:分为kernel和userland;其次根据trace方式:分为静态分析和动态分析。</p>
<h2 id="kernel">Kernel</h2>
<p>kernel空间下,静态分析是指tracepoint,动态分析是指kprobe</p>
<h3 id="静态分析">静态分析</h3>
<p>是指代码里面已经埋下了探针(probe),可以对这些探针进行分析,没有探针的地方不能trace,探针列表可以通过perf查看:</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell"><span class="c1">#sudo perf list tracepoint</span>
...
syscalls:sys_enter_getcpu <span class="o">[</span>Tracepoint event<span class="o">]</span>
syscalls:sys_exit_getcpu <span class="o">[</span>Tracepoint event<span class="o">]</span>
tcp:tcp_destroy_sock <span class="o">[</span>Tracepoint event<span class="o">]</span>
tcp:tcp_probe <span class="o">[</span>Tracepoint event<span class="o">]</span>
...</code></pre></div>
<p>静态分析有两种方式:ftrace和perf</p>
<h4 id="ftrace-7-8">ftrace<sup class="footnote-ref" id="fnref:7"><a href="#fn:7">1</a></sup><sup class="footnote-ref" id="fnref:8"><a href="#fn:8">2</a></sup></h4>
<p>ftrace是linux下的主要trace框架,linux实现了一个tracefs文件系统(类似proc的虚文件系统,驻留在内存),挂载在/sys/kernel/debug/tracing目录下,里面包括所有ftrace相关的内容,ftrace就是通过配置该目录下的文件,完成tracing。</p>
<p>ftrace里面涉及到静态分析的除了tracepoint之外,另外还有一个部分叫function,分别介绍</p>
<h5 id="function">function</h5>
<p>traceing目录下,带function字样的文件都和function有关,文件available_filter_functions里面包括了所有能trace的function(在没有添加任何filter的情况下)。如果你需要开启function tracer(更多的tracer,查看文件available_tracers,里面包括了系统支持哪些tracer),只需要执行命令:<code>echo function &gt; current_tracer</code>,启用之后,你能查看function trace的输出和输出格式定义:</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell"><span class="c1">#cat trace|head -10</span>
<span class="c1"># tracer: function</span>
#
<span class="c1"># _-----=&gt; irqs-off</span>
<span class="c1"># / _----=&gt; need-resched</span>
<span class="c1"># | / _---=&gt; hardirq/softirq</span>
<span class="c1"># || / _--=&gt; preempt-depth</span>
<span class="c1"># ||| / delay</span>
<span class="c1"># TASK-PID CPU# |||| TIMESTAMP FUNCTION</span>
<span class="c1"># | | | |||| | |</span>
gdbus-1275 <span class="o">[</span><span class="m">001</span><span class="o">]</span> .... <span class="m">11758</span>.901088: unix_poll &lt;-sock_poll</code></pre></div>
<p>如果你查看trace的内容,你会发现内容太多,你很难找到有价值的东西,绝大部分时候,你不是对整个系统的调用感兴趣,你只想看你关心的内容,ftrace提供了function filter来进行trace过滤:通过设置<code>set_ftrace_filter set_ftrace_notrace set_ftrace_pid</code>三个文件,你能过滤出来需要trace的function。</p>
<p>最简单的做法是看看available_filter_functions里面有些什么,里面的这些function都是可以用,例如我关心tcp_sendmsg:<code>echo tcp_sendmsg &gt; set_ftrace_filter</code>,这样function tracer就只会记录tcp_sendmsg这个function。当然filter也支持“*”号通配符,支持三种写法:“*key/<em>key</em>/key*”。也支持模块过滤“echo :mod:ext3 &gt; set_ftrace_filter”</p>
<p>另外,filter也支持“Format: <function>:<trigger>[:count]”这类的写法,通过它你能实现:某个function调用了,就触发一个预先定义的action(tracingoff/tracingon/stacktrace/snapshot/dump/cpudump),执行相关操作。例如:<code>echo do_trap:traceoff:3 &gt; set_ftrace_filter</code>,do_trap调用三次,执行停止trace操作。</p>
<p>如果你需要看到调用栈,可以设置:<code>echo 1 &gt; options/func_stack_trace</code>,但是必须注意,该操作容易导致问题,务必需要先设置filter,缩小trace范围,否则容易导致系统问题。</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell"><span class="o">[</span>root@tacyArch tracing<span class="o">]</span><span class="c1"># cat available_filter_functions |grep tcp_sendmsg</span>
bpf_tcp_sendmsg
tcp_sendmsg_locked
tcp_sendmsg
<span class="o">[</span>root@tacyArch tracing<span class="o">]</span><span class="c1"># echo tcp_sendmsg &gt; set_ftrace_filter</span>
<span class="o">[</span>root@tacyArch tracing<span class="o">]</span><span class="c1"># echo function &gt; current_tracer</span>
<span class="o">[</span>root@tacyArch tracing<span class="o">]</span><span class="c1"># cat trace</span>
<span class="c1"># tracer: function</span>
#
<span class="c1"># _-----=&gt; irqs-off</span>
<span class="c1"># / _----=&gt; need-resched</span>
<span class="c1"># | / _---=&gt; hardirq/softirq</span>
<span class="c1"># || / _--=&gt; preempt-depth</span>
<span class="c1"># ||| / delay</span>
<span class="c1"># TASK-PID CPU# |||| TIMESTAMP FUNCTION</span>
<span class="c1"># | | | |||| | |</span>
vvv-631 <span class="o">[</span><span class="m">003</span><span class="o">]</span> .... <span class="m">33440</span>.208482: tcp_sendmsg &lt;-sock_sendmsg
NetworkManager-555 <span class="o">[</span><span class="m">002</span><span class="o">]</span> .... <span class="m">33446</span>.836585: tcp_sendmsg &lt;-sock_sendmsg
curl-26180 <span class="o">[</span><span class="m">001</span><span class="o">]</span> .... <span class="m">33449</span>.150367: tcp_sendmsg &lt;-sock_sendmsg
vvv-4083 <span class="o">[</span><span class="m">002</span><span class="o">]</span> .... <span class="m">33456</span>.700836: tcp_sendmsg &lt;-sock_sendmsg
<span class="o">[</span>root@tacyArch tracing<span class="o">]</span><span class="c1"># echo &gt; current_tracer</span>
bash: echo: write error: Invalid argument
<span class="o">[</span>root@tacyArch tracing<span class="o">]</span><span class="c1"># echo nop &gt;current_tracer</span>
<span class="o">[</span>root@tacyArch tracing<span class="o">]</span><span class="c1"># echo &gt; set_ftrace_filter</span>
<span class="o">[</span>root@tacyArch tracing<span class="o">]</span>#</code></pre></div>
<p>总的来说,function tracer最大的问题就是给出的信息太模糊,有用的信息太少,也无法扩展(你只能enable它)。很多时候,虽然知道function被调用,知道调用的pid和comm,但光有这些信息对于解决问题是不够的。</p>
<h5 id="tracepoint">tracepoint</h5>
<p>下面我们来看看tracepoint相关内容。tracing目录下有一个events目录,里面就是所有的kernel tracepoint,包含了所有的tracepoint,每一个tracepoint都以目录存在,目录下面是针对该tracepoint的配置文件。</p>
<p>trace方法就是找到对应的tracepoint,例如tcp_probe,进入到该目录下(events/tcp/tcp_probe),通过命令<code>echo 1 &gt; enable</code>激活该探针,然后你就可以回到tracing目录下,查看trace文件内容,里面能看到trace内容,输出格式可以参考探针目录下的format文件。</p>
<p>另外你也能设置filter,根据条件过滤事件;你也能设置triger,当条件满足的时候,触发定义的action,例如stracktrace,输出栈到trace文件</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell"><span class="o">[</span>root@tacyArch tcp_receive_reset<span class="o">]</span><span class="c1"># ls</span>
<span class="nb">enable</span> filter format hist id trigger
<span class="o">[</span>root@tacyArch tcp_receive_reset<span class="o">]</span><span class="c1"># cat format</span>
name: tcp_receive_reset
ID: <span class="m">1133</span>
format:
field:unsigned short common_type<span class="p">;</span> offset:0<span class="p">;</span> size:2<span class="p">;</span> signed:0<span class="p">;</span>
field:unsigned char common_flags<span class="p">;</span> offset:2<span class="p">;</span> size:1<span class="p">;</span> signed:0<span class="p">;</span>
field:unsigned char common_preempt_count<span class="p">;</span> offset:3<span class="p">;</span> size:1<span class="p">;</span> signed:0<span class="p">;</span>
field:int common_pid<span class="p">;</span> offset:4<span class="p">;</span> size:4<span class="p">;</span> signed:1<span class="p">;</span>
field:const void * skaddr<span class="p">;</span> offset:8<span class="p">;</span> size:8<span class="p">;</span> signed:0<span class="p">;</span>
field:__u16 sport<span class="p">;</span> offset:16<span class="p">;</span> size:2<span class="p">;</span> signed:0<span class="p">;</span>
field:__u16 dport<span class="p">;</span> offset:18<span class="p">;</span> size:2<span class="p">;</span> signed:0<span class="p">;</span>
field:__u8 saddr<span class="o">[</span><span class="m">4</span><span class="o">]</span><span class="p">;</span> offset:20<span class="p">;</span> size:4<span class="p">;</span> signed:0<span class="p">;</span>
field:__u8 daddr<span class="o">[</span><span class="m">4</span><span class="o">]</span><span class="p">;</span> offset:24<span class="p">;</span> size:4<span class="p">;</span> signed:0<span class="p">;</span>
field:__u8 saddr_v6<span class="o">[</span><span class="m">16</span><span class="o">]</span><span class="p">;</span> offset:28<span class="p">;</span> size:16<span class="p">;</span> signed:0<span class="p">;</span>
field:__u8 daddr_v6<span class="o">[</span><span class="m">16</span><span class="o">]</span><span class="p">;</span> offset:44<span class="p">;</span> size:16<span class="p">;</span> signed:0<span class="p">;</span>
field:__u64 sock_cookie<span class="p">;</span> offset:64<span class="p">;</span> size:8<span class="p">;</span> signed:0<span class="p">;</span>
print fmt: <span class="s2">&#34;sport=%hu dport=%hu saddr=%pI4 daddr=%pI4 saddrv6=%pI6c daddrv6=%pI6c sock_cookie=%llx&#34;</span>, REC-&gt;sport, REC-&gt;dport, REC-&gt;saddr, REC-&gt;daddr, REC-&gt;saddr_v6, REC-&gt;daddr_v6, REC-&gt;sock_cookie</code></pre></div>
<p>enable文件用来控制开关,filter可以用来做事件过滤,format是tracepoint的输出内容定义,hist做事件统计,id就是tracepoint的标识,trigger可以条件触发action。</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell"><span class="o">[</span>root@tacyArch tracing<span class="o">]</span><span class="c1"># echo 1 &gt; events/tcp/tcp_receive_reset/enable</span>
<span class="o">[</span>root@tacyArch tracing<span class="o">]</span><span class="c1"># cat trace</span>
<span class="c1"># tracer: nop</span>
#
<span class="c1"># _-----=&gt; irqs-off</span>
<span class="c1"># / _----=&gt; need-resched</span>
<span class="c1"># | / _---=&gt; hardirq/softirq</span>
<span class="c1"># || / _--=&gt; preempt-depth</span>
<span class="c1"># ||| / delay</span>
<span class="c1"># TASK-PID CPU# |||| TIMESTAMP FUNCTION</span>
<span class="c1"># | | | |||| | |</span>
curl-26346 <span class="o">[</span><span class="m">001</span><span class="o">]</span> .... <span class="m">33819</span>.317760: tcp_receive_reset: <span class="nv">sport</span><span class="o">=</span><span class="m">44248</span> <span class="nv">dport</span><span class="o">=</span><span class="m">8080</span> <span class="nv">saddr</span><span class="o">=</span><span class="m">0</span>.0.0.0 <span class="nv">daddr</span><span class="o">=</span><span class="m">0</span>.0.0.0 <span class="nv">saddrv6</span><span class="o">=</span>::1 <span class="nv">daddrv6</span><span class="o">=</span>::1 <span class="nv">sock_cookie</span><span class="o">=</span><span class="m">1</span>
curl-26346 <span class="o">[</span><span class="m">001</span><span class="o">]</span> .... <span class="m">33819</span>.317892: tcp_receive_reset: <span class="nv">sport</span><span class="o">=</span><span class="m">49690</span> <span class="nv">dport</span><span class="o">=</span><span class="m">8080</span> <span class="nv">saddr</span><span class="o">=</span><span class="m">127</span>.0.0.1 <span class="nv">daddr</span><span class="o">=</span><span class="m">127</span>.0.0.1 <span class="nv">saddrv6</span><span class="o">=</span>::ffff:127.0.0.1 <span class="nv">daddrv6</span><span class="o">=</span>::ffff:127.0.0.1 <span class="nv">sock_cookie</span><span class="o">=</span><span class="m">2</span>
<span class="o">[</span>root@tacyArch tracing<span class="o">]</span><span class="c1"># echo 0 &gt; events/tcp/tcp_receive_reset/enable</span>
<span class="o">[</span>root@tacyArch tracing<span class="o">]</span>#</code></pre></div>
<p>上面的输出更友好,基本上你关心的内容都给你输出了:通过上面内容,你能知道curl从127.0.0.1:8080接收到一个reset包。</p>
<p>tracepoint能帮助你解决很多问题,当然tracepoint数量有限,有可能你关心的点正好没有,只能等着看新版本的kernel能否提供</p>
<h4 id="perf">perf</h4>
<p>perf位于kernel源代码的tools下,linux的主要性能分析工具之一,perf提供很多功能,这里我们只谈它和tracepoint有关的部分(perf不能操作ftrace中的function tracer),以tcp_probe这个tracepoint为例,操作也很简单:</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell"><span class="o">[</span>root@tacyArch ~<span class="o">]</span><span class="c1"># perf record -e &#39;tcp:tcp_probe&#39; -a</span>
^C<span class="o">[</span> perf record: Woken up <span class="m">1</span> <span class="nb">times</span> to write data <span class="o">]</span>
<span class="o">[</span> perf record: Captured and wrote <span class="m">1</span>.460 MB perf.data <span class="o">(</span><span class="m">3</span> samples<span class="o">)</span> <span class="o">]</span>
<span class="o">[</span>root@tacyArch ~<span class="o">]</span><span class="c1"># perf script</span>
irq/69-brcmf_pc <span class="m">19366</span> <span class="o">[</span><span class="m">003</span><span class="o">]</span> <span class="m">99975</span>.473448: tcp:tcp_probe: <span class="nv">src</span><span class="o">=</span><span class="m">192</span>.168.1.21:44404 <span class="nv">dest</span><span class="o">=</span><span class="m">203</span>.208.xx.xx:443 <span class="nv">mark</span><span class="o">=</span><span class="m">0</span> <span class="nv">data_len</span><span class="o">=</span><span class="m">0</span> <span class="nv">snd_nxt</span><span class="o">=</span>0x66d5014 <span class="nv">snd_una</span><span class="o">=</span>0x66d5014 <span class="nv">snd_cwnd</span><span class="o">=</span><span class="m">16</span> <span class="nv">ssthresh</span><span class="o">=</span><span class="m">21</span>&gt;
irq/69-brcmf_pc <span class="m">19366</span> <span class="o">[</span><span class="m">003</span><span class="o">]</span> <span class="m">99977</span>.000673: tcp:tcp_probe: <span class="nv">src</span><span class="o">=</span><span class="m">192</span>.168.1.21:59262 <span class="nv">dest</span><span class="o">=</span>xx.201.xx.119:80 <span class="nv">mark</span><span class="o">=</span><span class="m">0</span> <span class="nv">data_len</span><span class="o">=</span><span class="m">60</span> <span class="nv">snd_nxt</span><span class="o">=</span>0x6ec6b07d <span class="nv">snd_una</span><span class="o">=</span>0x6ec6b07d <span class="nv">snd_cwnd</span><span class="o">=</span><span class="m">55</span> ssthresh&gt;
irq/69-brcmf_pc <span class="m">19366</span> <span class="o">[</span><span class="m">003</span><span class="o">]</span> <span class="m">99977</span>.057786: tcp:tcp_probe: <span class="nv">src</span><span class="o">=</span><span class="m">192</span>.168.1.21:59262 <span class="nv">dest</span><span class="o">=</span>xx.201.xx.119:80 <span class="nv">mark</span><span class="o">=</span><span class="m">0</span> <span class="nv">data_len</span><span class="o">=</span><span class="m">0</span> <span class="nv">snd_nxt</span><span class="o">=</span>0x6ec6b0a1 <span class="nv">snd_una</span><span class="o">=</span>0x6ec6b07d <span class="nv">snd_cwnd</span><span class="o">=</span><span class="m">55</span> <span class="nv">ssthresh</span><span class="o">=</span>&gt;
<span class="o">[</span>root@tacyArch ~<span class="o">]</span>#</code></pre></div>
<h4 id="小结">小结</h4>
<p>静态分析方法比较简单,无需太多代码方面的知识,只需要通过配置即可完成。用户能通过对合适的tracepoint进行分析,找出有用的信息,从而解决一些疑难问题。但是静态分析受限于预先埋下的探针,另外探针输出的内容也无法增加,在一些情况下,满足不了trace的需求。</p>
<h3 id="动态分析">动态分析</h3>
<p>下面我们来看看动态分析,动态分析,顾名思义,就是当某函数没有预先在代码中埋下探针的时候,系统能够动态给它添加探针的分析方式。在kernel中,这些动态添加的探针也被称为kprobe。kernel把所有的symbol输出在/proc/kallsyms文件中,你可以对这里面的所有symbol添加探针。kprobe可以说是linux中最牛逼的trace手段。</p>
<p>动态分析也支持ftrace和perf两种方式。两者的选择:优先选择perf,主要原因是perf会做错误检验,不容易导致问题,ftrace的话就需要你特别小心,这里可是在kernel层面的操作,一个不小心,系统可能会挂起或者中断。</p>
<h4 id="ftrace-6">ftrace<sup class="footnote-ref" id="fnref:6"><a href="#fn:6">3</a></sup></h4>
<p>/proc/kallsyms里面所有的symbol都能添加kprobe,kprobe和function tracer无关,无需启用function tracer。你只需定义好event,写入到traceing目录下的kprobe_events文件即可,ftrace会自动在/sys/kernel/debug/tracing/events下创建kprobe目录,并在该目录下为每个kprobe创建类似tracepoint的目录,之后你只需要通过enable文件来控制启用还是禁用。kprobe event的语法定义如下:</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">Synopsis of kprobe_events
-------------------------
p<span class="o">[</span>:<span class="o">[</span>GRP/<span class="o">]</span>EVENT<span class="o">]</span> <span class="o">[</span>MOD:<span class="o">]</span>SYM<span class="o">[</span>+offs<span class="o">]</span><span class="p">|</span>MEMADDR <span class="o">[</span>FETCHARGS<span class="o">]</span> : Set a probe
r<span class="o">[</span>MAXACTIVE<span class="o">][</span>:<span class="o">[</span>GRP/<span class="o">]</span>EVENT<span class="o">]</span> <span class="o">[</span>MOD:<span class="o">]</span>SYM<span class="o">[</span>+0<span class="o">]</span> <span class="o">[</span>FETCHARGS<span class="o">]</span> : Set a <span class="k">return</span> probe
-:<span class="o">[</span>GRP/<span class="o">]</span>EVENT : Clear a probe
GRP : Group name. If omitted, use <span class="s2">&#34;kprobes&#34;</span> <span class="k">for</span> it.
EVENT : Event name. If omitted, the event name is generated
based on SYM+offs or MEMADDR.
MOD : Module name which has given SYM.
SYM<span class="o">[</span>+offs<span class="o">]</span> : Symbol+offset where the probe is inserted.
MEMADDR : Address where the probe is inserted.
MAXACTIVE : Maximum number of instances of the specified <span class="k">function</span> that
can be probed simultaneously, or <span class="m">0</span> <span class="k">for</span> the default value
as defined in Documentation/kprobes.txt section <span class="m">1</span>.3.1.
FETCHARGS : Arguments. Each probe can have up to <span class="m">128</span> args.
%REG : Fetch register REG
@ADDR : Fetch memory at ADDR <span class="o">(</span>ADDR should be in kernel<span class="o">)</span>
@SYM<span class="o">[</span>+<span class="p">|</span>-offs<span class="o">]</span> : Fetch memory at SYM +<span class="p">|</span>- offs <span class="o">(</span>SYM should be a data symbol<span class="o">)</span>
<span class="nv">$stackN</span> : Fetch Nth entry of stack <span class="o">(</span>N &gt;<span class="o">=</span> <span class="m">0</span><span class="o">)</span>
<span class="nv">$stack</span> : Fetch stack address.
<span class="nv">$retval</span> : Fetch <span class="k">return</span> value.<span class="o">(</span>*<span class="o">)</span>
<span class="nv">$comm</span> : Fetch current task comm.
+<span class="p">|</span>-offs<span class="o">(</span>FETCHARG<span class="o">)</span> : Fetch memory at FETCHARG +<span class="p">|</span>- offs address.<span class="o">(</span>**<span class="o">)</span>
<span class="nv">NAME</span><span class="o">=</span>FETCHARG : Set NAME as the argument name of FETCHARG.
FETCHARG:TYPE : Set TYPE as the <span class="nb">type</span> of FETCHARG. Currently, basic types
<span class="o">(</span>u8/u16/u32/u64/s8/s16/s32/s64<span class="o">)</span>, hexadecimal types
<span class="o">(</span>x8/x16/x32/x64<span class="o">)</span>, <span class="s2">&#34;string&#34;</span> and bitfield are supported.
<span class="o">(</span>*<span class="o">)</span> only <span class="k">for</span> <span class="k">return</span> probe.
<span class="o">(</span>**<span class="o">)</span> this is useful <span class="k">for</span> fetching a field of data structures.</code></pre></div>
<p>我们来创建一个event:</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell"><span class="o">[</span>root@tacyArch tracing<span class="o">]</span><span class="c1"># echo &#39;p:tcp_sendmsg tcp_sendmsg&#39; &gt; /sys/kernel/debug/tracing/kprobe_events</span>
<span class="o">[</span>root@tacyArch tracing<span class="o">]</span><span class="c1"># cat kprobe_events</span>
p:kprobes/tcp_sendmsg tcp_sendmsg
<span class="o">[</span>root@tacyArch tracing<span class="o">]</span><span class="c1"># ls events/kprobes/tcp_sendmsg/</span>
<span class="nb">enable</span> filter format hist id trigger
<span class="o">[</span>root@tacyArch tracing<span class="o">]</span><span class="c1"># cat events/kprobes/tcp_sendmsg/format</span>
name: tcp_sendmsg
ID: <span class="m">1638</span>
format:
field:unsigned short common_type<span class="p">;</span> offset:0<span class="p">;</span> size:2<span class="p">;</span> signed:0<span class="p">;</span>
field:unsigned char common_flags<span class="p">;</span> offset:2<span class="p">;</span> size:1<span class="p">;</span> signed:0<span class="p">;</span>
field:unsigned char common_preempt_count<span class="p">;</span> offset:3<span class="p">;</span> size:1<span class="p">;</span> signed:0<span class="p">;</span>
field:int common_pid<span class="p">;</span> offset:4<span class="p">;</span> size:4<span class="p">;</span> signed:1<span class="p">;</span>
field:unsigned long __probe_ip<span class="p">;</span> offset:8<span class="p">;</span> size:8<span class="p">;</span> signed:0<span class="p">;</span>
print fmt: <span class="s2">&#34;(%lx)&#34;</span>, REC-&gt;__probe_ip</code></pre></div>
<p>定义好之后,启用该probe进行trace(设置enable等于1):</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell"><span class="o">[</span>root@tacyArch tracing<span class="o">]</span><span class="c1"># echo 1 &gt; events/kprobes/tcp_sendmsg/enable</span>
<span class="o">[</span>root@tacyArch tracing<span class="o">]</span><span class="c1"># cat trace |head -10</span>
<span class="c1"># tracer: nop</span>
#
<span class="c1"># _-----=&gt; irqs-off</span>
<span class="c1"># / _----=&gt; need-resched</span>
<span class="c1"># | / _---=&gt; hardirq/softirq</span>
<span class="c1"># || / _--=&gt; preempt-depth</span>
<span class="c1"># ||| / delay</span>