调试方法综述
更新时间:2024-05-04 07:20:01 阅读量: 综合文库 文档下载
- 调试压力的方法推荐度:
- 相关推荐
调试方法综述
目录编号: 文件编号: 版本:1.4T 时间:2002-6-7 修订表
本表包含文档修订历史记录。下面的条目仅用于说明目的。
本文档应当在版本控制下存储,每个版本的简述应当输入版本控制系统。该简述在本段重复记录。修订不需要在文档中其它部分描述除非它们解释开发计划本身。
版本 1.0 1.1 2.0 2.1 2.1b 3.0 4.0 模块ID 模块名字 文档版本号 选用模板版本 主要作者 孙希 孙希 孙希 孙希 孙希 孙希 孙希 联系方式 4055 2152 2068 2068 2068 3125 3125 版本描述 征求意见 根据新输出信息进行修改完善 增加异常信息定位说明,征求意见 增加内存、mblk等管理模块的日志信息 根据贾洪雷指出的错误进行修改 根据4.x.x版本libsys相关信息修改 补充典型问题分析 补充mblk泄漏问题中mblk分配点定位方法 完成日期 2004-4-1 2005-6-27 2007-6-12 2007-6-18 2007-6-28 2011-6-30 2015-7-20 内容
1. 报文缓冲区 ................................................................................................................................. 3
1.1 mblk泄漏的定位 ..................................................................................................................... 3
1.1.1 阅读mblk泄漏日志 .............................................................................................. 3 1.1.2 查看mblk内容 ...................................................................................................... 3 1.1.3 较低版本中查看mblk内容 .................................................................................. 4
2. 内存 ............................................................................................................................................. 5
2.1 内存基本信息 ......................................................................................................................... 5 2.2 内存泄漏 ................................................................................................................................. 6 2.3 内存重复释放 ......................................................................................................................... 6 2.4 内存被非法改写 ..................................................................................................................... 7 2.5 VOS内存管理关键日志信息 ................................................................................................. 7
273935858.doc Version1.4T (错误!未指定书签。) Page 1 of 27
概要设计
2.5.1 严重报错日志 ........................................................................................................ 7 2.5.2 信息提示日志 ........................................................................................................ 8
3. 任务信息显示 ............................................................................................................................. 9
3.1 任务信息 ................................................................................................................................. 9 3.2 特定任务的堆栈 ................................................................................................................... 10
3.2.1 直接使用show task查看特定任务的堆栈 ........................................................ 10 3.2.2 早期版本使用show memory查看特定任务的堆栈 .......................................... 10 3.2.3 与任务有关的日志 .............................................................................................. 12
3.3 任务切换记录 ....................................................................................................................... 12 3.4 热键 ....................................................................................................................................... 14
4. 典型问题分析 ........................................................................................................................... 16
4.1 Console口不响应 .................................................................................................................. 16 4.2 CPU占用率高 ....................................................................................................................... 16 4.3 三层转发引起CPU忙 .......................................................................................................... 18 4.4 Ping不通 ................................................................................................................................ 19 4.5 Arp老化过快 ......................................................................................................................... 21
5. PPC异常处理 ............................................................................................................................ 22
5.1 PPC函数调用原理 ................................................................................................................ 22 5.2 异常信息分析 ....................................................................................................................... 22
5.2.1 异常信息组成 ...................................................................................................... 22 5.2.2 异常调用栈分析 .................................................................................................. 24 5.2.3 PPC背景资料 ....................................................................................................... 25
6. 使用bsa工具分析热键和异常 ................................................................................................ 27
图形列表
采用Caption段落风格的新图将自动加入下表。更新请按F9。 错误!未找到图形项目表。
273935858.doc Version1.4T (错误!未指定书签。) Page 2 of 27
概要设计
1. 报文缓冲区
系统中,所有收到的和要发送的报文都是使用mblk(mblk是message block的简称)在系统内部缓存的。使用show memory mblk命令查看系统mblk的使用情况。如下 Switch#show memory mblk
BUF0 BUF1 BUF2 BUF3 BUF4 BUF5 BUF6 BUF7 BUF8 size 0 104 256 600 1548 curr 3 1 1 0 0 max 9 5 4 2 2 total 1024 512 512 256 1024
size表示该类别mblk的大小;curr为该类别mblk的当前使用数量;max为自从系统启动以来该类别的mblk使用的最大数量;total表示该类别的mblk的最大数量。上面的命令执行例子表示,大小为0的mblk当前使用了3个,最多的时候使用了9个,系统总共有该大小的mblk 1024个,大小为104的mblk当前使用了1个,最多的时候使用了5个,系统总共有该大小的mblk 512个,大小为256的mblk当前使用了1个,最多的时候使用了4个,系统总共有该大小的mblk 512个,以此类推。如果某个类别的curr值与total值接近或相等,说明该类别的mblk当前几乎完全被占用,是一个不正常的信号,可能由于当时网络中报文比较多;如果某个类别的curr值长时间保持在较大的水平上(大于100)或只增不减,而网络中报文又不是很多,说明系统当时可能有问题,可以使用下面的其他手段进一步定位。
1.1 mblk泄漏的定位
1.1.1
阅读mblk泄漏日志
mblk泄漏日志为如下形式:%MBLK-4-OVERTIME: mblk ([hex1]) alloc at pc [hex2] tick [hex3], hold for 30 minutes, maybe leak。
其中hex1表示mblk地址,下面两节查看mblk内容时即以此地址为准。hex2表示mblk分配地址,可以通过3.2节“通过指令地址找到所在的函数”中介绍的方法确定该mblk在哪个函数中中申请。hex3为分配时间,该值供参考。上述三个值都是以16进制形式表示的。
1.1.2 查看mblk内容
当怀疑系统中出现了mblk泄漏时,可以使用show memory msgb查看当前未释放的mblk。例如: Switch#show memory msgb | include alloc
mblk(0x00df4718), alloc at 0x000ef88c datap(0x00e4794c), next 0x00000000 mblk(0x00df5748), alloc at 0x000e2a2c datap(0x00e13d48), next 0x00000000 mblk(0x00df78d0), alloc at 0x000e2a2c datap(0x00e14270), next 0x00000000 mblk(0x00df79f8), alloc at 0x000e2a2c datap(0x00e138d0), next 0x00000000 mblk(0x00e08f78), alloc at 0x0003a380 datap(0x00e1429c), next 0x00000000 mblk(0x00e090a0), alloc at 0x0003a308 datap(0x00e142c8), next 0x00000000 Switch#
其中alloc at后面的值为分配点指令地址。为了更容易定位问题,我们可以查看mblk的内容。我们选取其中一个mblk,查看它的内容。使用show memory msgb address命令: Switch(D)#show mem msgb 0x0f902920
273935858.doc Version1.4T (错误!未指定书签。) Page 3 of 27
概要设计
mblk(0x0f902920), alloc at 0x00537638 datap(0x0f96d3b4), next 0x00000000 mblk 0x0f902920 rptr = 0x0f96d34c wptr = 0x0f96d354 next = 0x00000000 prev = 0x00000000 cont = 0x00000000 last operate tick is 00000000
datab 0x0f96d3b4 base 0x0f96d34c limit 0x0f96d3b4 ref 1 data from base:
0f96d34c: 00000000 94040000 00e00f00 000900e0 0f96d35c: 0f000005 8100e001 c0c00004 00007fff 0f96d36c: fcfaf7fe 5c211201 01000000 0001f7fe 0f96d37c: 5c21107b 00676145 74686572 6e657431
通过查看mblk内容,我们知道这是一条日志信息,这有助于进一步缩小问题范围。
定位mblk泄漏类的问题,很重要的一点是要找到当前持有mblk的模块。Mblk显示的信息中,alloc at、rptr、wptr等信息均可用于定位当前持有mblk的模块:alloc at后面的地址就是分配或记录持有该mblk的指令地址,可以通过该指令地址反汇编找到持有mblk的C代码;有些模块记录或分配mblk后,后续仍然有大量代码处理该mblk,只知道记录或分配mblk的位置仍然难以判断mblk在后续哪个位置中持有或泄漏,这时候可以通过rptr、wptr等辅助判断,其中rptr表示当前程序处理到mblk中哪个位置,一般协议在处理报文时,会随着处理过程将rptr逐渐后移,根据当前rptr指向位置在报文的相对位置也可以推断当前mblk处理的进度,比如说:当前rptr指向以太网报文的mac头部,可以推断为当前mblk正在被物理层或链路层处理;如果指向ip头部,可以推断为网络层;如果指向tcp/udp头部则可以推断为传输层/socket处理,等等。
1.1.3 较低版本中查看mblk内容
当系统模块libsys版本低于1.3.0时,没有show memory msgb命令,此时可以通过show memory命令查看mblk内容。仍然以上节mblk地址0x00df5748为例: 首先使用show memory 0x00df5748显示mblk控制块内容: Switch#show memory 0x00df5748 0x30
00df5740: 0232B03B 00000000 00000000 00000000 .2.;............ 00df5750: 00000000 008C5AB4 008C5B02 00E13D48 ......Z...[...=H 00df5760: 00000000 C0A8D562 C0A8D55B 04280017 .......b...[.(..
mblk地址偏移0x0c和0x10分别是rptr、wptr地址;0x14是对应的datab的地址,即0xe13d48,继续使用show memory命令显示该地址: Switch#show mem 0x00E13D48 0x20
00e13d40: 0232B03B 00000000 00E092F0 008C5AB4 .2.;..........Z. 00e13d50: 008C5B02 01010000 000E27F8 008C5AB4 ..[.......'...Z.
datab地址偏移0x04是base地址,即0x8c5ab4,我们只要再使用show memory 0x8c5ab4即可得到mblk的内容:
Switch#show memory 0x008C5AB4
008c5ab0: 00000000 4A616E20 20352030 363A3039 ....Jan 5 06:09 008c5ac0: 3A323120 5359532D 362D434F 4E464947 :21 SYS-6-CONFIG 008c5ad0: 3A20436F 6E666967 75726564 2066726F : Configured fro 008c5ae0: 6D207674 79203120 62792073 756E7869 m vty 1 by sunxi (下略)
273935858.doc Version1.4T (错误!未指定书签。) Page 4 of 27
概要设计
2. 内存
2.1 内存基本信息
系统内存采用多级内存管理方式。系统使用内存池方式管理小块的分配和释放,内存池中的空闲块是固定尺寸的,不会做空闲块合并操作;系统使用堆方式管理大块内存的分配和释放,堆中的空闲块会做合并操作。“小块”的界限依机型而定,一般是512或2048。 使用show memory region命令可以看出当前内存的使用情况 Switch#show memory region Level 1 Heap:
max block 3979384, free 4946280 bytes, total alloc 2321 blocks(231016632 bytes) Level 2 Heap:
total bytes: 124716456, total blocks 106,
current free bytes: 98285112, max block 81632496
Memory utilization 47%(Image 7%, Region 17%, Heap 38%/87%, Msg buffer 0%/3%) [ 0]Size: 32 Current:22782 Max: 22784 Total: 65536 [ 1]Size: 64 Current:19052 Max: 19052 Total: 65536 [ 2]Size: 128 Current:13489 Max: 13489 Total: 65536 +[ 3]Size: 256 Current:25210 Max: 25211 Total: 37933 [ 4]Size: 512 Current: 2272 Max: 2273 Total: 8192 +[ 5]Size: 1024 Current: 1189 Max: 1195 Total: 7709 +[ 6]Size: 2048 Current: 3142 Max: 3143 Total: 4091 Show memory region的输出分为四个部分。
第一部分Level 1 Heap表示vxworks堆的使用情况,max block表示当前堆中的最大块,free表示当前堆中总共空闲内存;total alloc表示当前已经从level 1 heap分配的总块数和字节数。 第二部分Level 2 Heap表示libsys管理堆的使用情况,max block表示当前堆中的最大块,current free表示当前堆中总共空闲内存;total bytes表示当前堆中总内存。需要说明,有些机型不使用Level 2 Heap,这时会显示“No general purpose heap avaliable.”。
第三部分是系统内存占用率情况,其中Memory utilization是总内存占用率,括号内是分项内存使用情况:其中
Image表示映像占内存总量百分比;
Region表示内存池总尺寸占内存总量百分比; Heap表示Level 1/Level 2 Heap,/号前后的值分别表示堆当前使用量和堆总尺寸占内存总量的百分比;需要说明的是Region是由从Heap中分配得到的巨型内存块划分的,因此Heap当前使用量的百分比包含了Region的百分比;
Msg buffer表示mblk,/号前后的含义与堆相同; 一般来说Image+Heap+Msg buffer的比率接近100%。
第四部分是系统内存池使用情况。其中size表示内存块的尺寸,current表示当前使用的数量,max表示自从系统启动后最大用量,total表示总共数量。目前系统采用扩展内存池的策略,即系统启动时为每个尺寸生成基本内存池,当某个尺寸的基本内存池内的块用光后,会为该尺寸生成扩展内存池,这时会在该尺寸前面显示+号;系统为每个尺寸最多支持32个内存池。上例中系统为尺寸256、1024、2048生成了扩展池,这时可以通过命令show memory region detail来查看系统扩展内存池的使用情况:
273935858.doc Version1.4T (错误!未指定书签。) Page 5 of 27
概要设计
Switch#show memory region detail Level 1 Heap:
max block 3979384, free 4946320 bytes, total alloc 2320 blocks(231016592 bytes) Level 2 Heap:
total bytes: 124716456, total blocks 106,
current free bytes: 98285112, max block 81632496
Memory utilization 47%(Image 7%, Region 17%, Heap 38%/87%, Msg buffer 0%/3%)
[* 0 BASE]Size: 32 Current:22721 Max: 22789 Total: 65536 Range [0xdce8a80,0xdf68a80) [* 1 BASE]Size: 64 Current:19015 Max: 19053 Total: 65536 Range [0xdf68a80,0xe3e8a80) [* 2 BASE]Size: 128 Current:13478 Max: 13489 Total: 65536 Range [0xe3e8a80,0xec68a80) [- 3 BASE]Size: 256 Current: 8192 Max: 8192 Total: 8192 Range [0xec68a80,0xee78a80)
[* EXTEND( 1/ 10)] Current:17018 Max: 17019 Total: 29741 Range [0x73571e8,0x7ad4158)@002c84d4 [* 4 BASE]Size: 512 Current: 2270 Max: 2273 Total: 8192 Range [0xee78a80,0xf288a80) [* 5 BASE]Size: 1024 Current: 1023 Max: 1024 Total: 1024 Range [0xf288a80,0xf38aa80)
[+ EXTEND( 1/ 12)] Current: 165 Max: 171 Total: 6685 Range [0x65bd8f8,0x6c521e8)@002dc1fc [* 6 BASE]Size: 2048 Current: 509 Max: 512 Total: 512 Range [0xf38aa80,0xf48ba80)
[+ EXTEND( 1/ 13)] Current: 2630 Max: 2631 Total: 3579 Range [0x6c521f8,0x73571d8)@00379ee4
每个内存池的信息占一行,相关信息详述如下:
1、行首标记*表示当前使用,即系统收到该尺寸的内存分配请求时,从该池中分配内存,每个尺寸只有一个当前使用的内存池;行首标记-表示该池目前已经没有空闲块可供分配;行首标记+表示备用;
2、EXTEND表示扩展池,BASE表示基本池;
3、Range表示该内存池占用的内存地址,扩展池后的@XXXXXX表示触发创建扩展池的指令地址;
4、扩展池为当前备用状态,并且Current为0时,将被销毁。
max的值超过total的值是正常的;但是在配置没有增加或增加后又删除的情况下,某个大小的内存current alloc值持续大幅度(>10)增长则可能有问题;使用命令show memory region num可以打印出来具体大小的内存块的上一次操作情况。例如show memory region 2表示128字节内存快的使用情况,依此类推: Switch#show mem reg 2 information of rank 2:
Size: 128 Current alloc: 64 Max alloc: 90 Total: 4096
Buffer: 0x033a61e0(128) free at 0x00536e04 Buffer: 0x033a6268(128) free at 0x00536e04 ??
其中free表示上一次操作为释放操作,后面是执行释放操作的指令地址,alloc表示分配操作,其它则表示出现了错误。
2.2 内存泄漏
怀疑某个操作造成内存泄漏时,可以通过不停执行该操作,然后比较前后show memory region rank命令的执行结果来确认是否有内存泄漏出现。当某个region中内存块很多、难以分辨时,可以将操作前后该命令的执行结果保存为文本文件,使用Beyond Compare等比较工具进行比较,判断是否有内存泄漏。
2.3 内存重复释放
内存重复释放错误本质是应用程序释放了内存块后仍然保持着对块的引用。只有记录内存块所
273935858.doc Version1.4T (错误!未指定书签。) Page 6 of 27
概要设计
有历史释放点,才能准确定位内存块重复释放错误。VOS内存管理能够通过记录内存块的上一次释放点和当前状态,可以发现绝大多数重复释放问题:应用程序试图释放一个已经“空闲”的内存块,说明存在重复释放问题,上次释放点和本次释放点具有参考价值。 出现内存重复释放错误时,一般存在下述几种可能的操作序列:
1、 A分配得到a,A释放a,A释放a(错误被挂起:两次free都是A) 2、 A分配得到a,A释放a,B分配得到a,A释放a(错误无法识别),B释放a(正确却被挂
起:last free是A,这次是B)
3、 A分配得到a,A释放a,B分配得到a,B释放a,A释放a(错误被挂起:last free是B,
这次是a)
4、 A分配得到a,A释放a,A修改a指向的内存(破坏了空闲块链表),B试图分配(最坏的
情况,由于链表被破坏而产生异常,可以有限规避)
2.4 内存被非法改写
在我们的系统中目前没有有效办法准确定位内存被改写错误,尤其是“野指针”造成的错误。代码走读、单元测试等软件工程手段能够提高代码质量,从而减少内存被非法改写错误的发生。 某些数组越界访问造成内存被非法改写错误可以通过下列手段寻找线索:
全局变量被非法改写:在map中找到被改写的全局变量的位置,查看它的低地址方向是否有数据变量,有则可以检查该数组是否存在写越界的情况。
VOS内存管理分配得到的内存块被改写:内存块前端保存了内存池管理信息,VOS会定期检查该信息的正确性,当块前端的控制信息错误时,可能是该块低地址相邻的块内存写越界造成,系统会将前一个块的上次操作(分配、释放)以日志形式报告出来,供分析问题。
2.5 VOS内存管理关键日志信息
2.5.1
严重报错日志
%MEM-3-MALLOC_BADLINK [hex]:Bad free list of block [blk], last operated at [pc], previous block last operated at [prevpc]
系统从内存池分配内存时,发现空闲链表被破坏。[hex]表示内存分配操作的指令地址,[blk]表示内存块地址,[pc]表示被破坏的内存块上次操作地址,[prevpc]表示前一内存块上次操作地址。该日志提示系统出现了double free类错误或前一内存块写越界。
%MEM-6-MALLOC_INFO Data from [dig] bytes offset from block: [data1] [data2] [data3] [data4] 本日志伴随上一条日志出现,用于输出被破坏的内存块附近的信息。
%MEM-4-REGION_REBUILD Region [rgn](size = [sz]) was crashed, start rebuilding...
%MEM-4-REGION_REBUILD_COMPLETE Region [rgn] has been successfully rebuilt in [time] seconds, [nbrblks] block(s) found, [nbrfree] block(s) freed during rebuilding
这两条日志提示系统试图重建被破坏的内存池,如果两条日志成对出现,说明系统重建内存池成功,这样系统有较大概率继续正常运行;如果仅出现第一条日志则系统可能出现严重错误。 %MEM-3-FREE [pc]:free error, bad pointer [blk]
本日志提示系统中有应用程序试图释放一个从未分配过的指针。这是一种错误行为,但其释放行为本身不会对系统造成不良影响。
%MEM-3-FREE [pc]:free error, buffer [blk] crashed, alloced from [pc]
本日志提示系统中有应用程序释放内存时,内存块的相关控制信息被非法改写,这一般是前一内存块写越界或非法内存改写导致。
%MEM-6-PREVBLOCK: Block([blk]) previous block last alloc at pc [pc]
273935858.doc Version1.4T (错误!未指定书签。) Page 7 of 27
概要设计
%MEM-6-PREVBLOCK: Block([blk]) previous block last free at pc [pc] 这两条日志伴随free error日志出现,提示前一内存块上次使用地址。
%MEM-3-DOUBLE_FREE [pc]:free error, double free ptr [blk], last time free at [lastpc]
本日志提示系统出现了double free类错误,pc表示本次释放地址,lastpc表示上次释放地址。
2.5.2 信息提示日志
%STATICMEM-6-REFILL:Static memory region refilled at [hex]
本日志用于报告系统静态内存区溢出的情况,hex表示触发静态内存区溢出的内存分配指令地址。报告该日志的目的是收集系统统计信息,以便于更好的优化;触发该日志的事件不会对系统运行产生任何不良影响。
%PARTMEM-4-REFILL:Partion [hex] refilled
本日志用于报告系统分区内存溢出的情况,hex表示溢出的分区id。报告该日志的目的是收集系统统计信息,以便于更好的优化;触发该日志的事件不会对系统运行产生任何不良影响。 %MEM-6-EXT_REGION_CREATE [hex1]: Create extend region for region [dig1] rank [dig2], [dig3] blocks [dig4] bytes
本日志用于报告当前系统创建了一个扩展内存池,hex1是触发创建扩展内存池的指令地址,dig1和dig2代表扩展池索引信息,dig3表示该池包含的块数量,dig4表示该池消耗的总字节数。报告该日志的目的是收集系统统计信息,以便于更好的优化;触发该日志的事件不会对系统运行产生任何不良影响。
%MEM-6-EXT_REGION_DESTORY [hex1]: Destory extend region for region [dig1] rank [dig2] 本日志用于报告当前消耗了一个扩展内存池,hex1是触发销毁扩展内存池的指令地址,dig1和dig2代表扩展池的索引信息。报告该日志的目的是收集系统统计信息,以便于更好的优化;触发该日志的事件不会对系统运行产生任何不良影响。
%MEM-6-EXT_REGION_CREATE_CONCURRENT: Try to create extend region for region [dig1] rank [dig2] cocurrently with another task
当多个任务试图创建相同索引的扩展内存池时,系统会报告本日志,其中dig1和dig2代表扩展池的索引信息。报告该日志的目的是收集系统统计信息,以便于更好的优化;触发该日志的事件不会对系统运行产生任何不良影响。
%MEM-4-EXT_REGION_DECREASING_SIZE: Create extend region[dig1/dig2] for [dig3] blocks failed, total memory [dig4], try half
本日志用于报告当前试图创建扩展内存池时发生失败,这时系统会尝试折半创建,即创建一个包含[dig3]/2个块的内存池。该日志提示系统处于内存不足的压力之下,可尝试减少系统负载以使降低内存消耗;一半在压力测试时容易出现。
273935858.doc Version1.4T (错误!未指定书签。) Page 8 of 27
概要设计
3. 任务信息显示
3.1 任务信息
在系统运行过程中,可能出现一些异常情况,比如说某个功能不再有效,这有可能是某个任务因出现异常情况而不再运行有关。可以使用命令show task来察看任务的情况(为了阅读方便,略去了一些非典型的任务): Switch#show task info
CPU utilization for one second: 1%; one minute: 1%; five minutes: 1%
NAME ENTRY TID PRI PC Stk Ptr SP lmt ERR.NO ST invoked CPU ---------------------------------------------------------------------------- ARL 15c0a4 03c6c538 128 6bc9b8 03c6c488 03c6a648 000000 P 38 0.00 LINK 1477c8 03c6a190 128 6bd0d8 03c6a0d8 03c682a0 3d0004 PD 181334 0.00 STAT 1619a0 03c55798 128 6bc9b8 03c556d8 03c538a8 3d0004 PD 14061 0.00 IDLE 534b38 03d1f078 255 534b44 03d1f020 03d1ec80 000000 R 307346 99.23 _TM_ 53117c 032b0e20 055 6c0e14 032b0db8 032a9240 000000 D 133717 0.00 TLII 11efe8 03268bf8 128 6bc9b8 03268b80 03259018 000000 P 6307 0.11 MYIP 2d7bb8 031c8e68 128 6eed58 031c8d38 031c6a88 000000 P 2679 0.00 SLOG 544ae8 0299a200 128 6eed58 0299a140 02996620 000000 P 40 0.00 L3AG 037480 026c2eb8 180 6c0e14 026c2e78 026bf2d8 000000 D 13356 0.00 THAL 020098 026bec18 128 6eed58 026beb00 026bb038 000000 P 1675 0.00 _QOS 56dcf0 026ba9d8 128 6c0e14 026ba9a8 026b6df8 000000 D 45 0.00 tty0 5498e8 02598948 128 6bd0d8 02598310 02588d68 3d0002 R 3776 0.30 CHCK 534f4c 0257ee28 180 6c0e14 0257ede0 0257d248 000000 D 215 0.00 SNMT 591cfc 0257cc10 128 6c0e14 0257cbc8 02579030 000000 D 45 0.00 INTR 000000 00a60268 000 000000 00000000 00000000 000000 134298 0.03
上面例子中,最上面一行是总CPU占用率,分别是最近1秒、1分钟、5分钟的系统平均占用率;然后是每个任务的信息,其各项含义如下: 名称 含义 NAME 任务名称 ENTRY 任务入口地址 TID 任务的标识符 PRI 任务的优先级 PC 任务的当前指令地址 SP Ptr 任务当前堆栈指针 SP Lmt 任务当前栈顶指针 ERRORNO 当前任务的错误码 ST 任务的当前状态(P表示阻塞、S表示挂起、R表示就绪,D表示有等待时间) invoked 任务切入次数 CPU 任务CPU占用率,只具有定量的意义 不同的版本、不同的设备类型,上面这些值不会相同。系统正常运行的情况下,应满足下列条件:
273935858.doc Version1.4T (错误!未指定书签。) Page 9 of 27
概要设计
a) 只有线卡的NATM任务状态为S;如果其它任何一个任务状态持续为S,该任务就可能有
问题
b) 任何一个任务的SP Ptr都比位于SP Lmt与TID之间。
3.2 特定任务的堆栈
3.2.1
直接使用show task查看特定任务的堆栈
当怀疑某个任务不正常时,可以通过查看该任务的堆栈来帮助定位问题。使用show task
CPU utilization for one second: 2%; one minute: 2%; five minutes: 2%
P - Pending D - Delay R - Ready S - Suspend E - Estimated NAME ENTRY TID PRI PC Stk Ptr SP lmt ERR.NO ST CPU invoked ---------------------------------------------------------------------------- RPCS 36fe00 0a6c75e0 060 7da714 0a6c6c10 0a6b7890 3d0004 PD 0.00 576962 Gauge of sp reset from 0a6c5120 to 0a6c6810,Max stack usage 15 task RPCS pc = 007da714 ra = 0032bc98 call procedure-- 0x007da714-- [PC]
0x007c1b6c-- [SP 0a6c6c70] 0x0032cc1c-- [SP 0a6c6cb0] 0x0036fe88-- [SP 0a6c6ce0] 0x0032f4bc-- [SP 0a6c73e0] 0x007993ac-- [SP 0a6c7590]
last switched in at f75abda, now f75ac1c Stack for task RPCS(512 bytes)
0a6c6c10: 00000000 00000000 00000000 01110000 0a6c6c20: 00000000 0a8c7900 00000000 0a8c7900
系统记录了每个任务堆栈使用的最大深度,每次show task时如果当前堆栈深度低于最大深度,则会清空最大深度记录,这时会输出“Gauge of sp reset from xxx to xxx”;“Max stack usage 15”表示之前最大堆栈深度为总堆栈的15%。
3.2.2 早期版本使用show memory查看特定任务的堆栈
早期libsys版本不支持show task
031c8d30: 0290AACC 00000000 031C8D70*006EED58 ...........p.n.X 031c8d40: 00000000 00000000 00000000 00000000 ................ 031c8d50: 08000000 00000000 00000000 031C8DB0 ................ 031c8d60: 00000010 FFFFFFFF 0290AAC8 031C8DA0 ................ 031c8d70: 031C8D90*006BB694 00000000 00000000 .....k.......... 031c8d80: 00000000 00840000 0290AAC8 031C8DA0 ................
273935858.doc Version1.4T (错误!未指定书签。) Page 10 of 27
概要设计
031c8d90: 031C8DA0*005335C0 00000000 031C8DA0 .....S5......... 031c8da0: 031C8E60*002D7C4C 00000000 EEEEEEEE ...`.-|L........ 031c8db0: 09000008 00000000 00000000 00000000 ................ 031c8dc0: EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE ................ 031c8dd0: EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE ................ 031c8de0: EEEEEEEE EEEEEEEE 031C8DF0 EEEEEEEE ................ 031c8df0: 031C8E00 006C103C 031C8E00 002D7BB8 .....l.<.....-{. 031c8e00: 031C8E10 006B30F0 0000B030 002D7BB8 .....k0....0.-{. 031c8e10: 031C8E28 006B1F34 00000000 0000001F ...(.k.4........ 031c8e20: 00000000 002D7BB8 031C8E60 006B1EB8 .....-{....`.k.. 031c8e30: 0053306C 00000000 00000000 EEEEEEEE .S0l............ 031c8e40: 00000000 00000000 031C8E50 EEEEEEEE ...........P.... 031c8e50: 031C8E60 006AC8FC 00000000 002D7BB8 ...`.j.......-{. 031c8e60: 031C8F88*00533F04 031C8E68 002D7BB8 .....S?....h.-{. 031c8e70: FFFFFFFF 33889808 A0140000 95044010 ....3.........@. 031c8e80: 0A020000 00000000 08000000 031C8FE0 ................ 031c8e90: 00000002 00000000 00000000 00000000 ................ 堆栈结构:对于PowerPC体系结构的设备,堆栈含义如下: back chain SP Ptr current LR(主调函数PC) 参数区 局部变量区 寄存器保存区 next back chain SP Ptr previous LR ?? 两个SP之间的内存区称作一个堆栈frame,如上文中蓝色字体的部分就是一个frame。 通过指令地址找到所在的函数:map中只有每个函数(或标号)起始点的地址,所以直接在map中搜索这些PC很难找到;一般来说当PC值位于两个函数起始地址之间,则属于地址小的那个函数:例如PC为0x12345,函数fun1、fun2在map中地址分别为0x12340、0x12350且它们之间没有其它函数,则该PC属于函数fun1。
当前函数指任务TCB中保存的PC值所在的函数。
栈顶frame一般属于当前函数;若该函数没有压栈,则属于它的调用者。若某函数扇出为零并且没有局部变量或局部变量全部可以放在寄存器中时,编译器不会生成压栈代码。判断一个函数是否压栈的方法是将函数反汇编,若第一条指令不是stwu则未压栈。
堆栈frame中第一个字(0x031c8d38指向的字)表示当前上下文上一级堆栈指针;后面一个字则有两种情况:
1、 当本frame是该任务顶级frame时,表示栈顶函数本次执行至此时调用最后一个函数的
调用点地址,根据该地址即可找到栈顶函数,例如006EED58;若栈顶函数本次执行中尚未调用过其它函数,则是无效值,需要通过下一级frame中(LR-4)指向的指令推断当前栈顶函数
2、 当本frame不是栈顶时表示当前函数的主调函数PC指针,例如006BB694等
依此类推可以得到该任务到目前位置的调用函数PC指针列表,通过查找map文件即可得到函数调用序列。对于上例,函数调用PC指针列表为:
273935858.doc Version1.4T (错误!未指定书签。) Page 11 of 27
概要设计
006EED58<-006BB694<-005335C0<-002D7C4C<-00533F04(为了便于说明,我在每个SP Ptr后面打了星号)
3.2.3 与任务有关的日志
%SYS-3-CPUHOG: Task [name] run for [time] ticks(start at [tick])
%SYS-6-CPUHOG_INFO: Task [name] call procedure [pc1]--[pc2]--[pc3]--[pc4]-- 该日志表示系统中名为[name]的任务连续运行了[time]时间而未切出;CPUHOG_INFO表示了该任务被检测到CPU_HOG的时候的调用栈。
当某个任务连续36秒未切出时,系统会认为该任务陷入死循环,并重启整个系统。
%SYS-3-TASK_EXCEPTION_HANDLE: Task [name] suspended, system will reboot after 10 seconds
该日志表示系统中名为[name]的进入挂起状态,鉴于该任务属于系统关键任务,整个系统将在10秒后重启。重启前,系统会尝试把该任务的调用栈打出来以便于收集信息定位问题原因,调用栈输出格式与show break中的格式相同。
%SYS-3-CRITICAL_TASK_DEAD: Critical task [name] hasn't scheduled for [time] secods(lasttime switch [hex1] now [hex2]), maybe deadlock.
%SYS-3-CRITICAL_TASK_DEAD: Critical task [name] was dead, system will reboot in 10 seconds 上述两条日志通常同时出现。它们表示系统中的关键任务长时间未被调度到,可能发生了死锁。其中name是任务名字,time为任务未被调度的时间,hex1、hex2为两个16进制数,分别表示该任务上次切入时的tick值和当前的tick值。 系统将在10秒钟之后重新启动,重启动之前会把该任务的调用栈输出出来以便于收集信息定位问题原因,调用栈输出格式与show task中的格式相同。
%SYS-2-STACK_OVERFLOW: Stack for task [name](tid = [tid], sp = [sp], stack limit = [stklmt]) overflow, system maybe crashed
该日志表示系统中名为[name]的任务出现堆栈溢出的错误,此后任务将会挂起。
%SYS-4-STACK_LOW: Stack for task [name](tid = [tid], sp = [sp], stack limit = [stklmt]) is low 该日志表示系统中名为[name]的任务堆栈使用率超过80%。建议使用show task 0x[tid]查看该任务的调用栈使用情况以便于定位问题。
3.3 任务切换记录
任务切换记录用于记录交换机软件中各个任务切换情况。可以使用命令show task switch-record命令察看实时任务切换轨迹,如下例 Switch#show task switch-record ????(省略部分)????
Task # 14: id 392a948 name : _TM_ switch tick 6b42be entry pt 152610 Task # 15: id 27af510 name : tty0 switch tick 6b42be entry pt 16570c Task # 16: id 392a948 name : _TM_ switch tick 6b42bf entry pt 152610 Task # 17: id 27af510 name : tty0 switch tick 6b42bf entry pt 16570c Task # 18: id 392a948 name : _TM_ switch tick 6b42c0 entry pt 152610 Task # 19: id 27af510 name : tty0 switch tick 6b42c0 entry pt 16570c Task # 20: id 392a948 name : _TM_ switch tick 6b42c1 entry pt 152610
273935858.doc Version1.4T (错误!未指定书签。) Page 12 of 27
概要设计
Task # 21: id 27af510 name : tty0 switch tick 6b42c1 entry pt 16570c 上面的显示中Task #是任务切换记录的序号,id是任务的id,name是任务的名称,switch tick是一个时间单位(0.01秒),表示本行这个任务开始切入的时间,同时也是上一行的任务切出的时间,entry pt表示这个任务的入口函数。例如,上面的例子中第一行表示任务_TM_在系统启动后0x6b42be个tick的时候切入,下一行表示在相同的tick内切出。
如果系统发生异常复位,那么在系统重新启动之后使用show task switch-record命令就可以知道系统重启动时哪个任务在运行(注意系统重新启动后不要断电)。如下例: Switch#reb n Please wait...
System Bootstrap, Version 0.2.3, Serial num:S32000315 SWITCH-S3224 Processor MPC8245 @ 200Mhz The current time: 2004-4-1 10:11:30
SDRAM Fast Test...............................PASS! Flash Fast Test...............................PASS! RTC Test......................................PASS! Switch Internal Loopback Test.................PASS! Loading switch.bin...... Start Decompress switch.bin
######################################################################################################################################################################################################################################################################################################################################################################################################### Decompress 1867675 byte,Please wait system up.. System startup OK
Switch console 0 is now available
Press RETURN to get started
2004-4-1 10:12:03 Switch System started --
2004-4-1 10:12:03 %LINK-5-UPDOWN: Line on Interface VLAN1, changed state to up
Welcome to SWITCH S3224 Ethernet Switch
Switch>ena
Switch#2004-4-1 10:12:12 User DEFAULT enter privilege mode from console 0, level = 15 show task switch-record
Task # 0: id 392a948 name : _TM_ switch tick 4e3109 entry pt 152610
273935858.doc Version1.4T (错误!未指定书签。) Page 13 of 27
概要设计
Task # 1: id 3d2c0b0 name : IDLE switch tick 4e3109 entry pt 1547a0 Task # 2: id 392a948 name : _TM_ switch tick 4e310a entry pt 152610 Task # 3: id 3d2c0b0 name : IDLE switch tick 4e310a entry pt 1547a0 Task # 4: id 392a948 name : _TM_ switch tick 4e310b entry pt 152610 Task # 5: id 3d2c0b0 name : IDLE switch tick 4e310b entry pt 1547a0 Task # 6: id 392a948 name : _TM_ switch tick 4e310c entry pt 152610 Task # 7: id 38a1200 name : GVRP switch tick 4e310c entry pt 5f23c Task # 8: id 3d2c0b0 name : IDLE switch tick 4e310c entry pt 1547a0 Task # 9: id 392a948 name : _TM_ switch tick 4e310d entry pt 152610 Task # 10: id 3d2c0b0 name : IDLE switch tick 4e310d entry pt 1547a0 Task # 11: id 392a948 name : _TM_ switch tick 4e310e entry pt 152610 Task # 12: id 3d2c0b0 name : IDLE switch tick 4e310e entry pt 1547a0 Task # 13: id 392a948 name : _TM_ switch tick 4e310f entry pt 152610 Task # 14: id 3d2c0b0 name : IDLE switch tick 4e310f entry pt 1547a0 Task # 15: id 3d2c0b0 name : IDLE switch tick 4e30dc entry pt 1547a0 Task # 16: id 392a948 name : _TM_ switch tick 4e30dd entry pt 152610 Task # 17: id 3d2c0b0 name : IDLE switch tick 4e30dd entry pt 1547a0 ????(略)????
第14行任务IDLE切入时间是4e310f,下一个任务切换记录第15行切入时间是4e30dc,比上一个切入时间小,说明切换记录14是系统复位前最后一个任务,也就是说在IDLE任务中系统发生了复位。总结:系统复位后的任务切换记录中,如果某一行切换记录的switch tick比上一行的大,说明该行的任务发生异常情况,引起系统复位。
当系统CPU占用率达到阈值(一般是100%)时,也会记录当前的任务切换记录,以便于分析CPU占用率高的原因。系统会保留最近20次系统忙时的任务切换序列,使用命令show task switch-record busy
3.4 热键
当系统console口长时间没有反应,怀疑系统出现异常时,可以使用ctrl+\\键呼叫系统热键功能,此时系统会把所有任务的堆栈信息打印出来,便于错误分析。系统热键的输出为show task以及系统中每一个任务(包括中断)的调用栈,其格式和上文中讲到的相同。其中中断的调用栈有特别的意义,例如下列中断调用栈中(为了便于说明,我在每个SP Ptr后面打了星号): Stack for INTR context(512 bytes), Stack base is a60268 00a60020: 00a60148*00535fb8 03a6e160 00000800 00a60030: 00000002 00a60090 00037284 00009030 00a60040: 00000000 0000013d 034afb08 00a60050 00a60050: 00a60070 0053a7c4 03a6e160 00000800 00a60060: 00000002 00a60090 00a60080 03a6e160 00a60070: 00a600b8 000372b4 00a60090 02598ac0 00a60080: 00a60090 006c32d8 00000000 00000000 00a60090: 00037114 03a6e160 00000000 00000000 00a600a0: 03e0b5d4 000188f8 00009030 03a6e160 00a600b0: 00000801 026c3248 00a600d8 0014c6a4 00a600c0: 00000000 00000000 00000000 007de168 00a600d0: 00a600e8 00000000 00a600f0 006b9980
273935858.doc Version1.4T (错误!未指定书签。) Page 14 of 27
概要设计
00a600e0: 006c5fec 00009030 00a60100 03c6a190 00a600f0: 00a60100 006c32d8 00009030 006bc80c 00a60100: 00a60110 006bc808 000186a0 03c6c7c8 00a60110: 00a60128 006bd3e0 00a60130 006bd3ec 00a60120: 00a60128 007de808 00a60140 006b9980 00a60130: 00a60148 032b0f98 00a60140 10000003 00a60140: 00000000 007c83b4 00a60150*00014c90 00a60150: 00a60158*0068e8c4 00a60170*0068e99c 00a60160: 04e40001 00000000 00a60180 03d1a4b8 00a60170: 00a60180*0001096c 00000000 00000008 00a60180: 00a60198*000109d0 00a60190 00016014 00a60190: 00000000 00534b38 00a601a8*00000518 00a601a0: eeeeeeee eeeeeeee 03d1f020*eeeeeeee ??
00a60250: 00000000 00000000 eeeeeeee eeeeeeee 00a60260: eeeeeeee eeeeeeee 00000000 00000008 Stack for task tExcTask(512 bytes) ??(stacks for task)
大家可以看到,最后一级堆栈指针(3d1f020)与前面的相差比较远,在中断的堆栈中找不到这个地址;实际上它就是被中断的任务的当前堆栈指针;通过它与(后面的)其它任务堆栈指针进行比较,可以知道哪个任务过于繁忙导致系统无法响应其它输入。
273935858.doc Version1.4T (错误!未指定书签。) Page 15 of 27
概要设计
4. 典型问题分析
4.1 Console口不响应
设备使用和测试过程中经常遇到系统console口不响应的问题,这有可能是多种原因造成的,首先要排除使用不当的因素。
有可能是之前做了telnet、ssh等远程登录操作登录到其它系统,然后因为某些原因远端系统不响应,这时候在console口按任何键都不会看到回显。这时候可以试图通过“终端切换键”切回设备控制台,方法是:先按住CTRL+SHIFT+6三个键,然后松手再按x键,中间不要插入其它任何键。如果属于这种情况,输入“终端切换键”后应该能够回到设备控制台,并且用where命令可以看到刚才登出的线路,使用disconnect命令可以断开外出连接(注意按键的顺序,大部分人都不能熟练掌握终端切换键,建议先找一台正常的机器体验一下这个组合,避免误判)。
分布式系统或堆叠系统中,有可能是从主控设备通过through-pass命令登录到线卡/成员设备等情况,这时候可以通过CTRL+X能够退回设备控制台。
不属于上述两种情况的,则有可能属于软件故障。这时应该先试图telnet设备,看看能否telnet上去。如果能,则可能是出现了死锁的情况,导致tty0无法运行。这时获得tty0(注意大小写敏感!)任务的调用栈并分析,如果tty0停在正常等待用户输入的位置,那有可能是console口驱动的问题,需要请驱动开发人员继续定位。如果tty0在等待互斥量或event,那就需要查看本应发出事件或可能占有互斥量的任务的调用栈,依次检查这些任务停在什么位置,判断是否存在任务间互相等待的情况,如果存在那么就属于死锁,否则属于互斥量泄漏或漏发了event,这时候都可以请相关模块的维护人员继续定位。如果不能telnet,那就只能呼出系统热键,然后采用与telnet类似的方法依次查看tty0以及其它有关任务的调用栈并分析。假设当前tty0任务在等待A模块的互斥量,那么就需要查看A模块有关的任务,找到当前持有互斥量的任务a并查看它阻塞的原因,这样得到的最终结果有几种可能:任何任务都不可能持有该互斥量,这时可能是互斥量泄漏;持有互斥量的任务又在等待另外的互斥量,这可能是死锁。判断哪个任务持有一个给定的互斥量,有两种方法:1、vx系统互斥量结构semaphore中有一个域owner(目前除vx6.5外的vxworks中owner都位于互斥量id偏移0x18字节)表示持有该互斥量的任务,找到owner值就可以;2、根据任务调用栈当前调用的函数判断当前可能进入了哪个互斥量,这主要是基于对相关业务的经验作出判断(例如看到当前任务停在routing的函数中,那么它可能已经持有了路由的信号量rt_semaphore)。
另外一种可能造成console口不响应的可能是CPU忙,这可以从热键信息中分辨:热键中包含CPU占用率信息,如果看到CPU占用率为100%,那么就有可能导致console口不响应。这时应该查看两个信息:分任务CPU占用率(show taks信息)中,某任务CPU占用率较高并且与当前环境中正在运行相关业务,那么该任务有较高嫌疑造成CPU100%;在分任务CPU占用率最后会显示\,这里的任务名称具有较高嫌疑。
这里介绍的定位死锁等方法也适用于其它类似的情况。
综上,遇到console口不响应的问题,先排除telnet出去、登录到线卡等误操作,然后尝试telnet查看tty0等任务的调用栈,或直接通过热键查看所有任务调用栈信息;考虑到出现console口不响应的情况时,系统可能已经处于高度不稳定状态,在非用户现场情况下优先考虑热键。
4.2 CPU占用率高
先clear task,然后再show task查看CPU占用率和分任务占用率。看看哪个任务CPU占用率比
273935858.doc Version1.4T (错误!未指定书签。) Page 16 of 27
概要设计
较高,忽略IDLE任务。这种情况下一般来说某个任务占用率超过10%就应该关注了,超过50%就说明该任务很忙了。
CPU一列是每个任务的CPU占用率,后缀为E的表示该任务的占用率为“估计值”。 invoked一列是每个任务的调用次数。
分任务的CPU和invoked值,均为从系统启动(或者上次clear task)至今的统计值。
如果CPU比较忙的时候console口仍然有响应,可以直接查看忙任务的调用栈,并分析;一般需要多看几次。如果任务调用栈比较长(例如超过5行),就说明这个任务可能在处理自己的业务。这时候可以通过异常解析工具(bsa或winbsa)等解析调用栈,然后分析该任务忙的原因(也可以将调用栈以及解析结果提交给对应模块的维护人员处理)。
几个典型的可能忙的任务有:
INTR,这不是一个任务,而是模糊统计中断占用的时间,一般INTR占用比较高,说明可能有较多的报文收发操作,因为报文接收是系统中断最主要的来源。
L2Tx、bcmR、INTR三个任务忙,系统肯定是忙于接收报文。报文多有几种可能,即ipv4报文、ipv6报文、二层报文。这时候可以通过间隔5秒连续查看命令show ip traffic两次的方式得知是否是ipv4报文过多,该命令输出如下: Switch#show ip traffic IP statistics:
Rcvd: 31158449 total, 2550455 local destination, 2432184 delivered 主要关注两次执行中Rcvd值是否增长得比较快,如果平均每秒钟有几k个报文的增量,那么就可以认为是ip报文比较多,这时候请参考《三层转发引起CPU占用率高》中描述的方法来定位。类似的可以使用show ipv6 traffic来判断是否属于ipv6报文太多引起的CPU忙。
如果排除ipv4、ipv6报文,那么就只可能是普通二层报文过忙。这时候可以通过在console口上输入debug l2 rx raw octets 64来获取有关调试信息,看看是哪种二层报文比较多,并找到相应模块维护人员继续定位。
RPCS,此任务是RPC服务端。一般线卡上可能会出现RPCS比较高的情况,原因是主控向线卡发送了大量的RPC请求。比较常见的情况是主控hal下发了大量的调用,线卡收到后忙于处理并向交换芯片下发表项,也有其它可能,这里提供几种手段来排查:
1、show task 0x
2、如果show task显示当时RPCS任务不忙,那么可以通过debug rpc event来看看哪些服务号的rpc比较频繁,需要注意这个调试输出中既有发出的RPC请求也有收到的,而这里我们只需要关注那些收到的。典型的收到RPC的输出如下:
[RPC] EVENT REQ received ([type]) from slot [dig1], service code [hex1] seq [dig2], call user's rountine [hex2] to handle
其中type可能是SYNC或ASYNC,分别表示同步或异步调用;dig1是发起调用的槽位号,线卡上看到通常是0,主控上看到是线卡槽位号;hex1是16进制的服务号;dig2是调用序列号,hex2是用于处理此调用的处理函数。
假设某个调用号的RPC收到得特别频繁,那么可以结合现场业务分析为何会有大量调用。通常根据服务号的值来查找相对困难,可以在map中查找对应的处理函数(hex2)来获知rpc服务的信息。
注意:debug rpc event可能信息比较多,需要随时做好关闭调试的准备。
3、debug rpc event也找不到有用的信息,可以进入诊断模式,间隔一段时间执行命令show rpc
273935858.doc Version1.4T (错误!未指定书签。) Page 17 of 27
概要设计
service两次,检查两次之间哪些rpc服务调用次数或者消耗时间(ticks)增长较多。
ARPT,此任务是arp定时器处理。这个任务主要的工作是分时检查系统每个arp对应的mac地址是否发生了老化或迁移,如果发生了就需要更新相关的转发表项。ARPT任务忙的概率并不大,但是如果出现忙,其主要原因可能有两个:
1、检查mac地址是否迁移本身消耗了过多的时间,这有可能是交换芯片sdk的原因,以前在盛科的芯片上出现过这样的问题。
2、Mac地址频繁的出现迁移的情况,这时候arp会将迁移事件通知给相关模块并更新邻接表,这时会占用大量时间。可以打开debug arp packet、debug arp adj-table查看是否有大量调试输出,尤其有大量[ADJ]开头的调试信息,或者有大量下面的调试信息“IP ARP: Physical port of [addr] changed to [ifindex], notify routing”,则可能出现了频繁更新的情况。
Arp频繁更新,一般是因为生成树震荡的原因导致了mac地址老化,以后我们会专门描述如何定位生成树震荡问题。
MYIP,此任务主要用于ip有关的各种处理,最可能引起任务忙的几类操作有:单播cache操作、多播cache操作、路由操作等,这三种操作分别对应于调试开关debug ip flow、debug ip mroute-cache、debug ip exf,可以依次试着打开这几个调试开关看一下,看看哪种调试开关中的输出信息最多,那么就有可能是相应的功能繁忙。
如果是单播cache操作繁忙,建议参考文档《三层转发引起CPU占用率高》。 其它两种情况则需要ip/路由模块的维护人员继续定位。
EGRP,此任务用于邻接表流水线处理ipv4的cache、路由、egress等表项加入硬件表的操作。最可能引起任务忙的可能是路由压力测试时,大量路由灌入,将这些路由加入硬件表时引起CPU忙,这是正常的。其它情况需要ip模块的维护人员继续处理。
DHSN、DH6S,此任务用于dhcp snooping和dhcpv6 snooping业务。这里存在一些情况需要操作交换芯片的FP表,而频繁的FP表项操作可能引起任务繁忙。需要此模块维护人员继续处理。 IG-S,此任务是igmp-snooping的主任务。这个任务忙,有可能是因为设备收到了大量的igmp报文引起处理繁忙,可以debug ip igmp-snooping packet看看,如果出现大量收到报文的调试信息,建议先排查一下收到igmp报文的原因;如果不属于这种情况就需要此模块维护人员处理。 SNMP,此任务忙可能是收到了大量的SNMP请求,建议检查网络中是否存在网管软件在访问该设备。
其它任务忙,建议结合《交换机系统任务不完全列表》找到相关模块的维护人员定位问题。
4.3 三层转发引起CPU忙
首先clear task、show task,查看show task中CPU一列,看看哪个任务偏高。如果是L2Tx、INTR、bcmR等任务忙,则说明可能是收到了过多的报文导致的,首先通过show ip traffic命令看一下其中的Rcvd统计(命令输出第一行)是否增长较快,如果每秒钟增长小于一千,那么应该不属于这种情况;否则需要通过调试命令查看哪些报文较多。
如果使用console口连接到设备上,直接使用debug ip packet打开调试命令;如果使用telnet方式连接,则必须在debug的时候配置访问列表,去掉从PC到设备的ip报文,比如我的PC机地址是192.168.25.24而telnet的设备地址是192.168.25.254,那么我们需要配置这样一个扩展访问列表: !
ip access-list extended mydebug
deny ip 192.168.25.254 255.255.255.255 192.168.25.24 255.255.255.255 deny ip 192.168.25.24 255.255.255.255 192.168.25.254 255.255.255.255 permit ip any any
273935858.doc Version1.4T (错误!未指定书签。) Page 18 of 27
概要设计
!
然后telnet到设备上之后使用debug ip packet access-group mydebug,后面这个access-group mydebug特别重要,不加这个会导致debug信息非常多。在telnet线路上查看debug信息,需要先打开terminal monitor命令。
查看debug信息中哪些ip报文比较多,因为设备在跑业务可能流量较大,随时做好准备输入no debug all以免过多调试影响业务。
几种典型的调试信息如下:
IP:
说明系统从接口sintf收到源地址sip、目的地址dip的报文,从接口dintf发出,下一跳网关是gateway-addr。
这样调试说明系统在三层转发报文,通常三层转发都是硬件完成的,软件转发仅限于硬件表还没生成的时候。如果这种报文出现得非常多说明系统出现了软件转发的情况,这时候请检查: 1.gateway-addr与dip是否一致,
1.1如果一致则说明该转发命中了直接路由,这时候应该为dip加硬件cache。现在出现很多打印输出说明硬件cache可能没加成功,这有两种可能,arp没学到或cache表满。先检查一下dip的arp是否学到。
1.1.1 show arp时dip的arp已经存在,其interface包含物理端口信息,例如v20(g2/1),说明arp学习已经完成,这时候请检查sintf与dintf是否相同:
1.1.1.1 sintf与dintf相同,这说明三层转发的报文从相同的接口进出,首先结合网络情况判断这种报文是否合理,如果合理请show running interface
1.1.1.2 show ip cache查看当前有多少条ip cache,是否超出了硬件表的规模。如果超出硬件表规模,则说明此设备不满足现网需求,需要通过优化网络或配置等方案解决现网问题。
1.1.2 show arp时dip的arp已经存在,但interface只有vlan,例如VLAN20则不能成功加入硬件表,这种情况一般是因为用户配置了静态arp,但是arp的mac地址不正确或者主机不存在,而这时候却有其他主机(sip)向该主机发送报文,导致CPU占用率升高。这时建议取消静态arp配置,或者排查网络确定流量的合法性。
1.1.3 show arp时dip的arp是未完全项,这时候调试信息中应该会伴有大量的encapsulation failed:
1.1.3.1 dip不存在但有主机向它发送报文,这与1.1.2的情况有些类似,请排查网络确定流量的合法性。
1.1.3.2 dip存在但因为其他原因导致arp刚刚学到就被老化,导致ip cache会不停地被加入硬件表然后从硬件表中删除。这时候可以debug ip flow看看是否有大量相同地址的ip cache反反复复的在硬件表中添加和删除,例如有非常频繁的\to software cache\、\to hardware cache\和\from hardware\的字样,这种情况最大可能是生成树震荡导致mac地址不停老化最终引起arp和cache删除,建议通过debug span topo等手段检查生成树的有关情况。
1.2 gateway-addr与dip不一致,这时候这些流应该是命中exf的,但这些报文全都被送到软件转发,说明硬件exf表没有添加成功,这也有两大类原因,gateway-addr没学到或这exf表满,可以参考上述方法检查gateway-addr的arp为什么没学到。
4.4 Ping不通
Ping不通大致有几类原因:
1、ping出端icmp echo request报文没能正常发出去,这可能是因为没有路由、没有arp或硬件
273935858.doc Version1.4T (错误!未指定书签。) Page 19 of 27
概要设计
故障导致没发出去;
2、被ping端没收到报文,这可能是交换芯片表项设置不正确,例如defip表不正确,导致直连路由没送到CPU,fp表不正确,导致报文被重定向,vlan设置不正确,导致报文被vlan过滤,生成树状态不正确,导致报文被丢掉,等等;
3、被ping端icmp echo reply(下文称为ping请求)未能正确发出,原因一般与1相同; 4、Ping出端icmp echo reply未能收到,原因一般与2相同;
5、Ping出端收到icmp echo reply(下文称为ping应答)时超时。
出现ping不通时,需要打开一些调试命令来判断ping不通的原因,建议在console口使用全部调试命令,如果需要在telnet线路上使用ip调试命令,需要使用访问列表过滤掉无关报文,不能在telnet线路上使用l2、hal的调试命令。下列所有ip调试信息中A表示ping出设备的ip地址,B表示被ping设备的ip地址,G表示报文发出的网关,可能与A/B之一相同。 建议依次进行下列调试步骤: 1、检查ping出设备是否将ping请求报文发出:在ping出端打开debug ip packet,然后开始ping,并检查日志:
类似“IP: 0,src=A (local), dst=B (VLAN2), len=84, gate=G, sending”的日志,并且后面没有跟着其它日志(如下面的封装失败),说明ip层面已经正确的将报文发出;
类似“IP: 0,src=0.0.0.0 (local), dst=B, len=84, route failed”的日志,说明没找到路由,这时应该通过show ip route查看被ping的地址是否有路由;
类似“IP: 0,s=A (local), d=B (VLAN2), g=G, len 84, encapsulation failed”的日志,说明没有学到下一跳地址的arp,这时建议检查g=后面的ip地址对应的arp是否存在,这里需要说明只有连续ping出至少两个报文的情况下才可能看到“封装失败”的输出,对每个封装失败的报文会依次报告“sending”、“encapsulation failed”。
如果调试信息显示ip层面已经正确的将报文发出,那么可以使用debug ip tx multi-tx raw error查看l2层面的发送结果,查看是否有失败信息(注意检查失败信息是否对应着发出的ping报文);如果l2层未输出失败日志,可以使用debug hal send查看hal的输出。
2、如果上述调试信息都未报告失败,那么我们应该认为报文正确的从ping出端发出了,需要检查被ping设备软件层面是否收到ping请求报文。这时候我们应该查看被ping端的有关日志信息,需要说明的是如果被ping的设备是85、95等分布式交换机,所有下面这些调试信息都需要在与ping出设备相连的线卡上查看(例如被ping设备通过G2/1端口连接ping出设备,那么应该在slot 2上查看调试信息):
在被ping端打开debug ip packet,保持ping出端的ping操作,并检查日志:
类似“IP: 0,src=A (VLAN2), dst=B (VLAN2), len=84, rcvd”说明收到了ip报文,这时可以通过检查源、目的ip地址、报文长度等方式确认是否是ping请求报文;也可以通过debug ip raw使系统详细输出报文格式来确认。 如果被ping端未输出上述日志,需要在诊断模式下使用debug l2 rx raw error命令查看l2层收到报文的情况,并根据输出的报文内容判断是否收到了ping请求报文。如果l2调试信息显示l2也未收到ping请求报文,那么建议检查vlan配置、生成树状态、交换芯片上路由表项等信息,确认未收到报文的原因;或者先确认ping出设备是否正确的将报文发出来。 如果被ping端日志显示它收到了ping请求报文,那么应该继续检查是否将ping应答报文发出,这里的调试方法与“检查ping出设备是否将ping请求报文发出”相同。
3、如果上述调试信息说明被ping设备收到了ping请求报文,需要检查被ping设备是否发出了ping应答报文。
首先使用debug ip icmp命令,检查是否有类似“ICMP: rcvd echo from A, len 40”的调试信息,如果有则说明被ping设备的icmp层面收到了ping请求报文,这时继续检查是否有类似“ICMP:
273935858.doc Version1.4T (错误!未指定书签。) Page 20 of 27
概要设计
sent echo reply, src B, dst A, len 40”的报文,如果有则说明被ping设备的icmp层面发出了ping应答报文,这时候需要继续检查ip以及以下层面是否将报文发出,具体方法与步骤1“检查ping出设备是否将ping请求报文发出”类似。
4、如果上述调试信息说明被ping端发出了ping应答报文,需要检查ping出设备是否收到了ping应答报文,这与步骤2“检查被ping设备软件层面是否收到ping请求报文”类似,但具体操作分为两部分,其中分布式系统中从步骤a开始调试,非分布式系统从步骤b开始调试:
a) 分布式系统中:ping应答报文被线卡收到后,线卡会将报文递交给主控处理,这时在
线卡上debug ip packet时应该看到类似“IP: 0,src=B (VLAN32), dst=A (VLAN32), len=78, rcvd”和“IP: 0,src=B (VLAN32), dst=A, len=78, pass to msu”的调试信息,这表示线卡收到了报文并把报文送到了主控板。如果没有看到“rcvd”日志,则说明ping出设备的线卡没有收到被ping设备发出的ping应答报文,这时需要参考步骤2中的方法检查l2、vlan、生成树、交换芯片等有关信息;如果有“rcvd”日志但没有“pass to msu”日志,则说明ip处理出现了故障。
b) 分布式系统中看到了“pass to msu”日志,或者非分布式系统中,需要在被ping设备
主控板上查看报文接收情况,这时与步骤2的调试方法完全相同。如果收到正确的ping应答报文仍然ping不通,有可能是因为收到icmp应答时ping已经超时,这种情况建议增加主ping端的超时时间(-w选项)重新尝试,看看能否ping通。
4.5 Arp老化过快
在设备使用中有时会出现arp学到后立即消失的情况,例如debug arp时看到了收到arp应答的调试信息,但马上有看到了arp被删除的信息,或者show arp看不到相应的arp信息。出现这种情况,最有可能的原因就是mac地址老化,三层交换机中arp会定期检查mac地址的情况,如果对应的mac地址老化,arp将被删除,而mac地址再次学到时arp却未必能够立即学到,因为mac地址学习直接由交换芯片完成,而arp学习必须通过软件层面收发arp报文完成。这也导致了arp学到后立即被删除,但show mac addr时看到mac地址仍然存在。
这种故障通常使用全局命令arp retry-allarp通常可以规避,该命令的原理是,arp发现mac地址老化时并不立即删除arp条目,而是发送一个arp请求,如果一定时间(默认是45秒)内未能收到应答才会删除arp;因为arp对应的主机仍然在网络中存在,因而它会应答arp,从而避免arp被删除。
上述规避方法的弊端是会导致网络中出现大量的arp报文,因此我们还是需要彻底解决问题。mac地址频繁被老化的根本原因一般是网络中生成树震荡,例如经常从其他交换机收到topo change报文,这时应该从生成树方面查找原因。
273935858.doc Version1.4T (错误!未指定书签。) Page 21 of 27
概要设计
5. PPC异常处理
5.1 PPC函数调用原理
为了更好的分析异常现场信息,我们有必要先介绍一下PowerPC处理器在函数调用等方面的工作原理。PPC使用bl(blrl、bctrl等)类指令实现函数调用,它的作用是跳转至目的(bl:操作数/blrl:lr寄存器/bctrl:ctr寄存器)指令,并将返回地址(一般是主调函数中跳转指令的下一条指令地址)装入寄存器lr。这时根据被调函数可以分为两种情况: 1、 被调函数扇出非零,则在被调函数入口处会将lr寄存器的值保存在主调函数堆栈中LR的位
置,此时根据该值即可找到对应的函数
2、 被调函数扇出为零,这种情况只能发生在栈顶函数,此时堆栈frame中LR值是无效的 无论上述何种情况,show break显示的异常调用栈中顶级堆栈frame中LR的值都没有参考意义。 结合本节中描述的两种情况和3.2节中描述的两种情况,异常共分为下面三种情况: 1、 当前函数(即出现异常的函数)扇出为零
2、 当前函数扇出非零,但本次执行至异常时尚未调用过其它函数 3、 当前函数扇出非零,且本次执行至异常时已经调用过其它函数
我们假设函数main调用了函数sub,那么在sub的本次执行过程中尚未调用其它函数时LR保存了main中调用sub的指令地址,此时LR与PC不属于同一个函数;在sub调用其它函数后LR则保存了sub内上次调用点的地址,此时LR与PC属于同一个函数。
根据PC与LR是否属于同一个函数,我们可以忽略函数的扇出而将异常简化为两种情况: 1、 当前函数本次执行至出现异常时,尚未调用其它函数 2、 当前函数本次执行至出现异常时,已经调用了其它函数
5.2 异常信息分析
5.2.1
异常信息组成
系统出现异常后,会有如下信息打印出来:
System Exception 0x300 Offset fffe000 Num 3 Task PIMD suspend
Exception 0x300 at program counter 00220118 , r1:04dbbd10 Link address is 002203f0
Machine status word is 00029230 Data address register is 00921f28
exception syndrome register is 00000000
instruction address resume register is 00000000
这表示系统出现了0x300异常,指令00220118执行了非法操作:它表示系统访问数据时试图执
行非法寻址操作(试图操作无法映射的地址、试图写只读地址,如指令段),dar表示试图非法操作的地址,本例中试图对00921f28地址进行操作。最后一行显示了任务名:PIMD。
当系统重新启动后,可以使用show break命令显示更详细的信息(为了说明,红色字体是新增的):
S8510#sho break
=========================================================
273935858.doc Version1.4T (错误!未指定书签。) Page 22 of 27
概要设计
Exception Type:300-Data Access Interrupt BreakNum: 3
date: 2007-5-11 time: 17:6:7
R0 = 00220c4c R1 = 04dbbd10 R2 = 00000000 R3 = a6486190 R4 = 00000000 R5 = 00000000 R6 = 00000005 R7 = 00000000 R8 = 00000000 R9 = 00000064 R10 = 02000000 R11 = 00000000 R12 = 00000000 R13 = 00000000 R14 = 00000000 R15 = 00000000 R16 = 00000000 R17 = 00000000 R18 = 00000000 R19 = 00000000 R20 = 00000000 R21 = 00000000 R22 = 00000000 R23 = 00cf80b4 R24 = 09564fc0 R25 = 0a768888 R26 = 00000005 R27 = 00000000 R28 = 09564d68 R29 = 00764a68 R30 = a6486190 R31 = a6486190 MSR = 00029230 LR = 002203f0 CTR = 00697258 IP = 00220118 LR = ipacl_find IP = hash_char
dear = 00921f28 esr = 00000000 iarr = 00000000 call procedure--
0x00764a68--NOT FOUND 0x00220c4c--ipacl_check
0x001e8d54--kmrt_find_boundary 0x00230ce4--mbr_find_boundary
0x002a7f78--pimdm_state_refresh_timeout 0x002ac73c--pimdm_main
0x0032db3c--_sys_task_entrypt_wrapper 0x00690ba0--vxTaskEntry 0x00000000--NOT FOUND
Stack:
04dbbd10: 04dbbd20*00764a68 04dbbd48 a6486190 04dbbd20: 04dbbd40*00220c4c 00000000 00000000 04dbbd30: 00000000 e1000049 ffffffff 00000000 04dbbd40: 04dbbd70*001e8d54 e1000049 00000000 04dbbd50: 00000000 00000000 00000000 00000000 04dbbd60: 00000000 04dbc1b0 00000000 e1000049 04dbbd70: 04dbbd80*00230ce4 40000040 00cf8038 04dbbd80: 04dbbde0*002a7f78 00000000 00000000 04dbbd90: 00000000 00000000 00000000 00000000 04dbbda0: 00000000 00000000 00000000 00000000 04dbbdb0: ffffffff 04dbc1b0 04dbbdc0 00000000 04dbbdc0: 00000000 00000000 00000000 00000000 04dbbdd0: 00000000 002ac538 00cf8040 00cf8038 04dbbde0: 04dbbe00*002ac73c 1010000a 00000000 04dbbdf0: 00000000 00000000 04dbbf90 00badd08 04dbbe00: 04dbbf30*0032db3c 00000000 00000000
show break信息由三部分组成:前面部分是寄存器信息;中间call procedure部分是由调用栈分析得出的函数调用序列,下文中我们从上到下依次将call procedure中的地址记做CP[0]、CP[1]等,它们的调用关系是CP[i]调用CP[i-1];后面stack部分是任务调用堆栈(格式同3.2节)。
273935858.doc Version1.4T (错误!未指定书签。) Page 23 of 27
概要设计
5.2.2 异常调用栈分析
开发人员对出现异常的模块非常熟悉时,完全可以通过经验和PC值推断出异常时函数调用序列。其它情况下可以通过本节介绍的方法推断出现异常时函数调用序列,进而分析异常的原因。
5.2.2.1 当前函数未调用其它函数
当break信息中LR和PC属于不同的函数时,该异常就属于这种情况,例如5.2.1中的例子。 此时寄存器信息中LR和PC两值含义为:IP表示产生异常的指令;当前函数未调用过其它函数,LR由当前函数的主调函数执行bl指令时保存,因此LR表示调用当前函数的那条指令。通过查找map可以得知IP属于函数hash_char,LR属于函数ipacl_find。
CP[0]由当前函数堆栈记录,由于当前函数未调用其它函数,故CP[0]无效。
若当前函数压栈,CP[1]由LR所在函数堆栈记录,它与LR相同。因此CP[0]、CP[1]是无效的。此时调用序列为CP[i]->CP[i-1]->??->CP[2]->LR->PC。
若当前函数不压栈,CP[0]由LR所在函数堆栈记录,它是无效的;但CP[1]有效。此时调用序列为(前面不变)CP[2]->CP[1]->LR->PC。
本例属于当前函数没有压栈的情况(见3.2,hash_char第一条指令为li而非stwu),这种情况下异常调用序列为??->ipacl_check->ipacl_find->hash_char
5.2.2.2 当前函数已经调用其它函数
当break信息中LR和PC属于相同函数时,该异常就属于这种情况。以下面的异常信息为例 Exception Type:300-Data Access Interrupt BreakNum: 2
date: 1970-1-1 time: 0:0:38
R0 = 00102cac R1 = 04fd11e0 R2 = 00000000 R3 = 00000003 R4 = 04fd16c2 R5 = 00000010 R6 = 00000000 R7 = 0fffffff R8 = 00000080 R9 = 00000000 R10 = fffffff0 R11 = 00102cd8 R12 = 00000010 R13 = 00000000 R14 = 00000000 R15 = 00000000 R16 = 00000000 R17 = 00000004 R18 = 00000000 R19 = 00000000 R20 = 00000000 R21 = 0098ef60 R22 = 00000002 R23 = 00711e58 R24 = 00102b64 R25 = 04fd14bc R26 = 00000000 R27 = 00000000 R28 = 00000000 R29 = 04fd1ac8 R30 = 04fd14bc R31 = 00000002 MSR = 00029230 LR = 00102cb8 CTR = 00102cd8 IP = 00102cdc LR = do_chram_mem_sys_addr IP = do_chram_mem_sys_addr dear = 0094b148 esr = 00000000 iarr = 04f04ec0 call procedure--
0x00102cac--do_chram_mem_sys_addr 0x001645d4--subcmd
0x00102d6c--do_chram_mem_sys 0x00165544--lookupcmd 0x00166150--cmdparse
0x00356978--vty_main_loop 0x00356d8c--vty
0x003333d0--_sys_task_entrypt_wrapper 0x0069dd20--vxTaskEntry
0x00000000--analyse fail: not found Stack:
273935858.doc Version1.4T (错误!未指定书签。) Page 24 of 27
概要设计
04fd11e0: 04fd1200 00102cac 00000010 00000000 04fd11f0: 04fd1ac8 00000000 00000000 00711e58 04fd1200: 04fd1250 001645d4 00000000 04fd1ac8 04fd1210: 04fd1cf0 00000000 00102d2c 00000003 04fd1220: 00000003 04fd14b8 00000000 0098ef60 04fd1230: 00000001 00000000 00000000 04fd1ac8 04fd1240: 00000001 04fd1ac8 04fd14b8 00000003 04fd1250: 04fd1270 00102d6c 00000000 04fd14b8 04fd1260: 00000003 00000000 04fd1ac8 00711ec0 04fd1270: 04fd12c0 00165544 00000023 00000073 04fd1280: 00000000 00000002 00000000 00000000 04fd1290: 00000000 00000000 00bd6e5c ffffffdf 04fd12a0: 0fa48b18 00000000 04fd198c 04fd1ac8 04fd12b0: 00000003 00000030 04fd16c4 00000000 04fd12c0: 04fd1970 00166150 63687200 00000000 04fd12d0: 00000000 00000000 00000000 0094b148
LR由当前函数执行bl指令调用其它函数时保存,故LR不属于调用序列。
若当前函数压栈,CP[0]属于当前函数堆栈frame,故它也是无效的,此时调用序列为??CP[1]->PC;若当前函数不压栈,则CP[0]属于当前函数的主调函数,此时它是有效的,调用序列为??->CP[1]->CP[0]->PC。
5.2.3 PPC背景资料
5.2.3.1 常见异常
0x300:DSI。最常见的情况是:启用了MMU的系统,当CPU进行数据存取操作寻址时,该地址只读而试图执行写操作、该地址不可访问而试图执行读写操作等情况会触发异常。一般指令端、readonly段等为只读。
0x200:machine check。最常见的情况是:未启用MMU的系统,当试图存取映射不到的内存地址时,CPU会触发MC异常。
0x400:ISI。最常见的情况是:启用了MMU的系统,当CPU取指令时,发现指令地址不可访问或不可执行。一般出现在blrl、bctrl等指令执行时lr、ctr寄存器中值错误。 0x600:对齐异常。某些指令要求操作数具有某些对齐要求(如4字节对齐等),当不满足该要求时产生。一般出现于这种情况:Gcc编译的代码进行64位数赋值时会借用双精度浮点寄存器中转,此时使用指令lfd、stfd等就要求操作数是4字节对齐的。为了避免这种情况,我们已经要求使用64位数时一定要使用
0x700:指令异常。CPU取到一条指令解码分析后,发现它不是一条合法指令。常见情况有:blrl、bctrl指令时寄存器中值错误、指令段被改写、常态试图执行管态指令等。
0x800:浮点不可用异常。在MSR[FP]为零的情况下试图执行浮点指令。这种异常极少见。 5.2.3.2 常见汇编代码样式
函数入参传递:r3~r11,寄存器不够则用堆栈 函数返回值传递:r3或r3+r4 取全局变量: lis rx,base lwz ry,offset(rx)
273935858.doc Version1.4T (错误!未指定书签。) Page 25 of 27
正在阅读:
调试方法综述05-04
粪便细菌学规范01-18
2014-2019年中国酚醛树脂行业市场评估及发展可行性研究报告07-18
2018年江西师范大学化学化工学院853有机化学之有机化学考研强化五套模拟题05-08
2019届重庆市西南大学附属中学校高三第十次月考理科综合化学试题03-05
信息安全导论作业11-11
热门小本创业点子适合90后01-08
关于对文化市场综合执法模式的思考11-07
混凝土结构课程设计12-18
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 综述
- 调试
- 方法
- 手卫生知识试题
- 2016年福建事业单位面试题总汇
- 聚氨酯硬泡生产工艺
- (申论宝典)中国特色官方排比句集锦
- 基坑支护方案(改)
- 2015版五信下Scratch教案
- 你的烦恼熄灭了吗
- 北京城市总体规划(2004年-2020年)
- 《逻辑学》练习题及参考答案
- 酸碱盐中考试题
- 2004-2012年注册咨询师《宏观经济政策与发展规划》历年真题及答
- 基于单片机的直流电机调速系统软件设计
- 管理学资料 - 图文
- 新版人教版一年级上册语文全册教案教学设计(2018最新编辑)
- 五层框架结构教学楼 - 施工组织设计
- 年产20万吨啤酒厂设计初稿
- 2014年—2017年北京高考语文真题及答案解析
- 案例分析题
- 浙江省考面试真题解析100道
- 马克思 绪论-5习题及解答