Linux 版 (精华区)

发信人: superman (风雨无阻), 信区: Unix
标  题: gdb文档(中文) [2]
发信站: 紫 丁 香 (Thu Jul  9 06:10:27 1998), 站内信件

【 以下文字转载自 cngnu 讨论区 】
【 原文由 System_Killer@bbs.ustc.edu.cn 所发表 】
结束子进程
=========================

`kill'
     Kill命令结束你程序在gdb下开的子进程
     这个命令当你想要调试(检查)一个core dump文件时更有用。gdb在调试过程中
会忽略所有的core dump。
   在一些操作系统上,一个程序当你在上面加了断点以后就不能离开gdb独立运行。
你可以用kill命令来解决这个问题。
   'kill'命令当你想重新编译和连接你的程序时也很有用。因为有些系统不允许修改
正在执行的可执行程序。这样当你再一次使用'run'命令时gdb会知道你的程序已经被改
变了,那么gdb会重新load新的符号。(而且尽量保持你当前的断点设置。
附加的进程信息
==============================
   一些操作系统提供了一个设备目录叫做'/proc'的,供检查进程映象。如果gdb被在这
样的操作系统下运行,你可以使用命令'info proc'来查询进程的信息。('info proc'命
令只在支持'procfs'的SVR4系统上有用。
`info proc'
     显示进程的概要信息。
`info proc mappings'
     报告你进程所能访问的地址范围。
`info proc times'
     你进程和子进程的开始时间,用户时间(user CPU time),和系统CPU时间。
`info proc id'
     报告有关进程id的信息。
`info proc status'
     报告你进程的一般状态信息。如果进程停止了。这个报告还包括停止的原因和收到的
信号。
`info proc all'
     显示上面这些命令返回的所有信息。
对多线程程序的调试
========================================
   一些操作系统中,一个单独的程序可以有一个以上的线程在运行。线程和进程精确的定义
类似于多进程。除了它们共享同一个地址空间(这意味着线程之间共享变量)另一方面,线程又
有自己的寄存器,运行时堆栈或许还会有私有内存。
   gdb提供了以下供调试多线程的进程的功能:
   * 自动通告新线程。
   * 'thread THREADNO',一个用来在线程之间切换的命令。
   * 'info threads',一个用来查询现存线程的命令。
   * 'thread apply [THREADNO] [ALL] ARGS',一个用来向线程提供命令的命令。
   * 线程有关的断点设置。
   注意:这些特性不是在所有gdb版本都能使用,归根结底要看操作系统是否支持。
   如果你的gdb不支持这些命令,会显示出错信息:

          (gdb) info threads
          (gdb) thread 1
          Thread ID 1 not known.  Use the "info threads" command to
          see the IDs of currently known threads.
   gdb的线程级调试功能允许你观察你程序运行中所有的线程,但无论什么时候
gdb控制,总有一个“当前”线程。调试命令对“当前”进程起作用。
   一旦gdb发现了你程序中的一个新的线程,它会自动显示有关此线程的系统信
息。比如:
     [New process 35 thread 27]
不过格式和操作系统有关。
   为了调试的目的,gdb自己设置线程号。
`info threads'
     显示进程中所有的线程的概要信息。gdb按顺序显示:
       1.线程号(gdb设置)
       2.目标系统的线程标识。
       3.此线程的当前堆栈。
       一前面打'*'的线程表示是当前线程。
     例如:
     (gdb) info threads
       3 process 35 thread 27  0x34e5 in sigpause ()
       2 process 35 thread 23  0x34e5 in sigpause ()
     * 1 process 35 thread 13  main (argc=1, argv=0x7ffffff8)
         at threadtest.c:68
==============================
`thread THREADNO'
     把线程号为THREADNO的线程设为当前线程。命令行参数THREADNO是gdb内定的
线程号。你可以用'info threads'命令来查看gdb内设置的线程号。gdb显示该线程
的系统定义的标识号和线程对应的堆栈。比如:

          (gdb) thread 2
          [Switching to process 35 thread 23]
          0x34e5 in sigpause ()
     "Switching后的内容取决于你的操作系统对线程标识的定义。

`thread apply [THREADNO] [ALL]  ARGS'
     此命令让你对一个以上的线程发出相同的命令"ARGS",[THREADNO]的含义同上。
如果你要向你进程中的所有的线程发出命令使用[ALL]选项。
   无论gdb何时中断了你的程序(因为一个断点或是一个信号),它自动选择信号或
断点发生的线程为当前线程。gdb将用一个格式为'[Switching to SYSTAG]'的消息
来向你报告。
   *参见:运行和停止多线程程序。
   *参见:设置观察点

调试多进程的程序
==========================================
   gdb对调试使用'fork'系统调用产生新进程的程序没有很多支持。当一个程序开始
一个新进程时,gdb将继续对父进程进行调试,子进程将不受影响的运行。如果你在子
进程可能会执行到的地方设了断点,那么子进程将收到'SIGTRAP'信号,如果子进程没
有对这个信号进行处理的话那么缺省的处理就是使子进程终止。
   然而,如果你要一定要调试子进程的话,这儿有一个不是很麻烦的折衷的办法。在
子进程被运行起来的开头几句语句前加上一个'sleep'命令。这在调试过程中并不会引
起程序中很大的麻烦(不过你要自己注意例外的情况幺:-))。然后再使用'ps'命令列出
新开的子进程号,最后使用'attach'命令。这样就没有问题了。
  关于这一段,本人觉得实际使用上并不全是这样。我在调试程中就试过,好象不一定
能起作用,要看gdb的版本和你所使用的操作系统了。
===============================================================================
停止和继续
***********************
   调试器的基本功能就是让你能够在程序运行时在终止之前在某些条件下停止下来,然
后再继续运行,这样的话你就可以检查当你的程序出错时你的程序究竟做了些什么。
   在gdb内部,你的程序会由于各种原因而暂时停止,比如一个信号,一个断点,或是
由于你用了'step'命令。在程序停止的时候你就可以检查和改变变量的值,设置或去掉
断点,然后继续你程序的运行。一般当程序停下来时gdb都会显示一些有关程序状态的信
息。比如象程序停止的原因,堆栈等等。如果你要了解更详细的信息,你可以使用'info
program'命令。另外,在任何时候你输入这条命令,gdb都会显示当前程序运行的状态信
息。

`info program'
     显示有关你程序状态的信息:你的程序是在运行还是停止,是什么进程,为什么停止。

断点,观察点和异常
========================================
   断点的作用是当你程序运行到断点时,无论它在做什么都会被停止下来。对于每个断点
你都可以设置一些更高级的信息以决定断点在什么时候起作用。你可以使用'break’命令来
在你的程序中设置断点,在前面的例子中我们已经提到过一些这个命令的使用方法了。你可
以在行上,函数上,甚至在确切的地址上设置断点。在含有异常处理的语言(比如象c++)中,
你还可以在异常发生的地方设置断点。
   在SunOS 4.x,SVR4和Alpha OSF/1的设置中,你还可以在共享库中设置断点。
   观察点是一种特殊的断点。它们在你程序中某个表达式的值发生变化时起作用。你必须使
用另外一些命令来设置观察点。除了这个特性以外,你可以象对普通断点一样对观察点进行
操作--使用和普通断点操作一样的命令来对观察点使能,使不能,删除。
   你可以安排当你程序被中断时显示的程序变量。
   当你在程序中设置断点或观察点时gdb为每个断点或观察点赋一个数值.在许多对断点操作
的命令中都要使用这个数值。

* Menu:

* Set Breaks::                  Setting breakpoints
* Set Watchpoints::             Setting watchpoints

* Exception Handling::          Breakpoints and exceptions

* Delete Breaks::               Deleting breakpoints
* Disabling::                   Disabling breakpoints
* Conditions::                  Break conditions
* Break Commands::              Breakpoint command lists

* Breakpoint Menus::            Breakpoint menus


File: gdb.info,  Node: Set Breaks,  Next: Set Watchpoints,  Up: Breakpoints
设置断点
=============
   使用'break'或简写成'b'来设置断点。gdb使用环境变量$bpnum来记录你最新设置的
断点。
   你有不少方法来设置断点。


`break FUNCTION'
     此命令用来在某个函数上设置断点。当你使用允许函数重载的语言比如C++时,有可
能同时在几个重载的函数上设置了断点。

`break +OFFSET'
`break -OFFSET'
     在当前程序运行到的前几行或后几行设置断点。OFFSET为行号。

`break LINENUM'
     在行号为LINENUM的行上设置断点。程序在运行到此行之前停止。

`break FILENAME:LINENUM'
     在文件名为FILENAME的原文件的第LINENUM行设置断点。

`break FILENAME:FUNCTION'
     在文件名为FILENAME的原文件的名为FUNCTION的函数上设置断点。当你的多个文件中
可能含有相同的函数名时必须给出文件名。

`break *ADDRESS'
     在地址ADDRESS上设置断点,这个命令允许你在没有调试信息的程序中设置断点。

`break'
     当'break'命令不包含任何参数时,'break'命令在当前执行到的程序运行栈中的下一
条指令上设置一个断点。除了栈底以外,这个命令使程序在一旦从当前函数返回时停止。
相似的命令是'finish',但'finish'并不设置断点。这一点在循环语句中很有用。
     gdb在恢复执行时,至少执行一条指令。

`break ... if COND'
     这个命令设置一个条件断点,条件由COND指定;在gdb每次执行到此断点时COND都被计算
当COND的值为非零时,程序在断点处停止。这意味着COND的值为真时程序停止。...可以为下
面所说的一些参量。

`tbreak ARGS'
     设置断点为只有效一次。ARGS的使用同'break'中的参量的使用。

`hbreak ARGS'
     设置一个由硬件支持的断点。ARGS同'break'命令,设置方法也和'break'相同。
但这种断点需要由硬件支持,所以不是所有的系统上这个命令都有效。这个命令的主要目的是
用于对EPROM/ROM程序的调试。因为这条命令可以在不改变代码的情况下设置断点。这可以同
SPARCLite DSU一起使用。当程序访问某些变量和代码时,DSU将设置“陷井”。
注意:你只能一次使用一个断点,在新设置断点时,先删除原断点。

`thbreak ARGS'
     设置只有一次作用的硬件支持断点。ARGS用法同'hbreak'命令。这个命令和'tbreak'命令
相似,它所设置的断点只起一次作用,然后就被自动的删除。这个命令所设置的断点需要有硬件
支持。

`rbreak REGEX'
     在所有满足表达式REGEX的函数上设置断点。这个命令在所有相匹配的函数上设置无条件断
点,当这个命令完成时显示所有被设置的断点信息。这个命令设置的断点和'break'命令设置的没
有什么不同。这样你可以象操作一般的断点一样对这个命令设置的断点进行删除,使能,使不能
等操作。当调试C++程序时这个命令在重载函数上设置断点时非常有用。

`info breakpoints [N]'
`info break [N]'
`info watchpoints [N]'
     显示所有的断点和观察点的设置表,有下列一些列

    *Breakpoint Numbers*----断点号
    *Type*----断点类型(断点或是观察点)
    *Disposition*---显示断点的状态。

    *Enabled or Disabled*---使能或不使能。'y'表示使能,'n'表示不使能。

    *Address*----地址,断点在你程序中的地址(内存地址)
    *What*---地址,断点在你程序中的行号。
     如果断点是条件断点,此命令还显示断点所需要的条件。
     带参数N的'info break'命令只显示由N指定的断点的信息。
     此命令还显示断点的运行信息(被执行过几次),这个功能在使用'ignore'
命令时很有用。你可以'ignore'一个断点许多次。使用这个命令可以查看断点
被执行了多少次。这样可以更快的找到错误。
    gdb允许你在一个地方设置多个断点。但设置相同的断点无疑是弱智的。不过
你可以使用条件断点,这样就非常有用。
   gdb有时会自动在你的程序中加入断点。这主要是gdb自己的需要。比如为了正
确的处理C语言中的'longjmp'。这些内部断点都是负值,以'-1'开始。'info 
breakpoints'不会显示它们。
   不过你可以使用命令’maint info breakpoints'来查看这些断点。

`maint info breakpoints'
     使用格式和'info breakpoints'相同,显示所有的断点,无论是你设置的还是
gdb自动设置的。
     以下列的含义:

    `breakpoint'
          断点,普通断点。
    `watchpoint'
          普通观察点。

    `longjmp'
          内部断点,用于处理'longjmp'调用。

    `longjmp resume'
          内部断点,设置在'longjmp'调用的目标上。

    `until'
          'until'命令所使用的内部断点。

    `finish'
          'finish'命令所使用的内部断点。



============================================================================
设置观察点
==============
   你可以使用观察点来停止一个程序,当某个表达式的值改变时,观察点会将程序
停止。而不需要先指定在某个地方设置一个断点。
   由于观察点的这个特性,使观察点的使用时开销比较大,但在捕捉错误时非常有
用。特别是你不知道你的程序什么地方出了问题时。

`watch EXPR'
     这个命令使用EXPR作为表达式设置一个观察点。GDB将把表达式加入到程序中
并监视程序的运行,当表达式的值被改变时GDB就使程序停止。这个也可以被用在
SPARClite DSU提供的新的自陷工具中。当程序存取某个地址或某条指令时(这个地
址在调试寄存器中指定),DSU将产生自陷。对于数据地址DSU支持'watch'命令,然而
硬件断点寄存器只能存储两个断点地址,而且断点的类型必须相同。就是两个
'rwatch'型断点,或是两个'awatch'型断点。

`rwatch EXPR'
     设置一个观察点,当EXPR被程序读时,程序被暂停。

`awatch EXPR'
     设置一个观察点,当EXPR被读出然后被写入时程序被暂停。这个命令和'awatch'
命令合用。

`info watchpoints'
     显示所设置的观察点的列表,和'info break'命令相似。
     *注意:*在多线程的程序中,观察点的作用很有限,GDB只能观察在一个线程中
的表达式的值如果你确信表达式只被当前线程所存取,那么使用观察点才有效。GDB
不能注意一个非当前线程对表达式值的改变。

断点和异常
==============
   在一些语言中比如象GNU C++,实现了异常处理。你可以使用GDB来检查异常发生的
原因。而且GDB还可以列出在某个点上异常处理的所有过程。

`catch EXCEPTIONS'
     你可以使用这个命令来在一个被激活的异常处理句柄中设置断点。EXCEPTIONS是
一个你要抓住的异常。
     你一样可以使用'info catch'命令来列出活跃的异常处理句柄。
     现在GDB中对于异常处理由以下情况不能处理。
   * 如果你使用一个交互的函数,当函数运行结束时,GDB将象普通情况一样把控制返
回给你。如果在调用中发生了异常,这个函数将继续运行直到遇到一个断点,一个信号
或是退出运行。
   * 你不能手工产生一个异常( 即异常只能由程序运行中产生 )
   * 你不能手工设置一个异常处理句柄。
   有时'catch'命令不一定是调试异常处理的最好的方法。如果你需要知道异常产生的
确切位置,最好在异常处理句柄被调用以前设置一个断点,这样你可以检查栈的内容。
如果你在一个异常处理句柄上设置断点,那么你就不容易知道异常发生的位置和原因。
   要仅仅只在异常处理句柄被唤醒之前设置断点,你必须了解一些语言的实现细节。
比如在GNU C++中异常被一个叫'__raise_exception'的库函数所调用。这个函数的原
型是:

         /* ADDR is where the exception identifier is stored.
            ID is the exception identifier.  */
         void __raise_exception (void **ADDR, void *ID);
要使GDB在栈展开之前抓住所有的句柄,你可以在函数'__raise_exception'上设置断点。
   对于一个条件断点,由于它取决于ID的值,你可以在你程序中设置断点,当某个特
别的异常被唤醒。当有一系列异常被唤醒时,你可以使用多重条件断点来停止你的程序。

删除断点
===================
   很自然当一个断点或是一个观察点完成了它的使命后,你需要把它从程序中删去。
不然你的程序还会在相同的地方停主,给你造成干扰。使用'clear'命令来从程序中删去
一个断点。
   使用'clear'命令你可以删除指定位置的断点。使用'delete'命令你可以使用断点号
来指定要删去的断点或观察点。
   在删除断点时不需要先运行过它,GDB会忽略你刚才删去的断点。所以你可以继续运行
你的程序而不必管断点。

`clear'
     在当前选择的栈帧上清除下一个所要执行到的断点(指令级)。当你当前选择帧是栈中
最内层时使用这个命令可以很方便的删去刚才程序停止处的断点。

`clear FUNCTION'
`clear FILENAME:FUNCTION'
     删除名为FUNCITON的函数上的断点。

`clear LINENUM'
`clear FILENAME:LINENUM'
     删除以LINENUM为行号上的断点。

`delete [breakpoints] [BNUMS...]'
     删除参数所指定的断点,如果没有指定参数则删去程序中所有的断点。这个命令可以
缩写成为'd'

使断点暂时不起作用。
========================
   如果你只是想让断点一时失去作用以方便调试的话,你可以先使断点不起作用。
当你以后又想使用时可以用'enable'命令激活它们。
   你使用'enable'命令来激活断点或是观察点,使用'disable'命令来使断点或观察点
不起作用。使用'info break'或'info watch'来查看那些断点是活跃的。
   断点或观察点有四种状态:
   * 使能。当程序运行到断点处时,程序停止。使用'break'命令设置的断点一开始缺省
是使能的。
   *不使能。断点对你程序的运行没有什么影响。
   *使能一次后变为不使能。断点对你的程序运行只有一次影响,然后就自动变成不使能
状态。使用'tbreak'设置的断点一开始缺省是这个状态。
   * 使能一次自动删除。断点在起了一次作用后自动被删除。
   你可以使用以下的命令来使能或使不能一个断点或观察点。

`disable [breakpoints] [BNUMS...]'
     使由参数指定的断点或观察点变为不使能,如果没有参数的话缺省使所有断点和观察
点变为不使能。当一个断点或观察点被不使能后在被不使能前的状态被记录下来,在断点或
观察点再次被激活时,原来的状态得到继续。比如一个条件断点或一个设置了
'ignore-counts'的断点在被使不能后记录活跃时断点被执行的次数,在不使能状态下,断
点的执行次数(ignore-counts)不增加,直到断点再次被激活时,再继续计算条件
(ignore-counts)。你可以使用'disable'命令的缩写'dis'

`enable [breakpoints] [BNUMS...]'
     使能由参数指定的断点或全部断点。

`enable [breakpoints] once BNUMS...'
     功能同上条命令,只是这条命令使断点只使能一次。

`enable [breakpoints] delete BNUMS...'
     功能同上条命令,只是这条命令使被使能的断点起作用一次然后自动被删除。     
     除了使用'tbreak'命令所设置的断点以外,断点被设置时都是使能的。

断点条件
===========
   最简单的断点就是当你的程序每次执行到的时候就简单将程序挂起。你也可以为断点
设置“条件”。条件只是你所使用的编程语言的一个布尔表达式,带有条件表达式的断点
在每次执行时判断计算表达式的值,当表达式值为真时才挂起程序。
   这是使用“断言”的一中形式,在这种形式中你只有在断言为真时才挂起程序。如果
在C语言中你要使断言为假时挂起程序则使用:“!表达式”。
   条件表达式对观察点也同样有效,但你并不需要它,因为观察点本身就计算一个表达式。
但它也许会简单一些。比如只在一个变量名上设置观察点然后设置一个条件来测试新的赋
值。
  断点条件可能有副作用(side effects)会影响程序的运行。这一点有时也是很有用的
比如来激活一个显示程序完成情况的的函数,或使用你自己的打印函数来格式化特殊的
数据结构。当在同一位置没有另一个断点设置时,结果是可预见的。(在gdb中如果在同一
个地方使用了一个断点和一个条件断点则普通断点可能先被激活。)在条件断点的应用上
有很多技巧。
   断点条件可以在设置断点的同时被设置。使用'if'命令作为'break'命令的参数。断点
条件也可以在任何时候使用'condition'命令来设置。'watch'命令不能以'if'作为参数
所以使用'condition'命令是在观察点上设置条件的唯一方法。

`condition BNUM EXPRESSION'
     把'EXPRESSIN'作为断点条件。断点用'BNUM'来指定。在你为BNUM号断点设置了条件
后,只有在条件为真时程序才被暂停。当你使用'condition'命令GDB马上同步的检查
'EXPRESSION'的值判断表达式中的符号在断点处是否有效,但GDB并不真正计算表达式
的值。

`condition BNUM'
     删除在'BNUM'号断点处的条件。使之成为一个普通断点。
   一个条件断点的特殊例子是时一个程序在执行了某句语句若干次后停止。由于这
个功能非常常用,你可以使用一个命令来直接设置它那就是'ignore count'。每个
断点都有'ignore count',缺省是零。如果'ignore count'是正的那么你的程序在
运行过断点处'count'次后被暂停。

`ignore BNUM COUNT'
     设置第BNUM号断点的'ignore count'为'COUNT'。
     如果要让断点在下次执行到时就暂停程序,那么把'COUNT'设为0.
     当你使用'continue'命令来继续你程序的执行时,你可以直接把'ignore count'
作为'continue'的参数使用。你只要直接在'continue'命令后直接跟要"ignore"的
次数就行。
     如果一个断点同时有一个ignore count和一个条件时,条件不被检查。只有当
'ignore count'为零时GDB才开始检查条件的真假。
     另外你可以用'condition'命令来获得与用‘ignore count'同样效果的断点。用法
是用类似于'$foo--<=0'的参量作为'condition'命令的参数(使用一个不停减量的变量
作为条件表达式的成员)。


断点命令列表
==================
   你可以为任一个断点或观察点指定一系列命令,当你程序执行到断点时,GDB自动执行
这些命令。例如:你可以打印一些表达式的值,或使能其他的断点。

`commands [BNUM]'
`... COMMAND-LIST ...'
`end'
     为断点号为BNUM的断点设置一个命令列表。这些命令在'...COMMAND-LIST...'中列
出使用'end'命令来表示列表的结束。
    要删除断点上设置的命令序列,你只需在'command'命令后直接跟'end'命令就可以
了。
    当不指定BNUM时,GDB缺省为最近遇到的断点或是观察点设置命令列表。
    使用回车来表示重复使用命令的特性在'...command list...'中不能使用。
    你可以使用命令列表中的命令来再次使你的程序进入运行状态。简单的在命令列表
中使用'continue'命令,或'step'命令。
    在使程序恢复执行的命令后的命令都被忽略。这是因为一旦你的程序重新运行就可
能遇到新的命令列表,那么就应该执行新的命令。防止了二义。
    如果你在命令列表中使用了'silent'命令,那么你程序在断点处停止的信息将不被
显示。这对于用一个断点然后显示一些信息,接着再继续执行很有用。但'silent'命令
只有在命令列表的开头有效。
    命令'echo','output'和'printf'允许你精确的控制显示信息,这些命令在"silent"
断点中很有用。
   例如:这个例子演示了使用断点命令列表来打印'x'的值.

     break foo if x>0
     commands
     silent
     printf "x is %d\n",x
     cont
     end
   断点命令列表的一个应用是在遇到一个buf之后改正数据然后继续调试的过程。
使用命令来修改含有错误值的变量,然后使用'continue'命令继续程序的运行。
  使用'silent'命令屏蔽输出:

     break 403
     commands
     silent
     set x = y + 4
     cont
     end


File: gdb.info,  Node: Breakpoint Menus,  Prev: Break Commands,  Up: Breakpoints

断点菜单
==============
   一些编程语言(比如象C++)允许一个函数名被多次使用(重载),以方便应用的使用。
当一个函数名被重载时,'break FUNCITON'命令向GDB提供的信息不够GDB了解你要设置
断点的确切位置。如果你了解到这个问题,你可以使用'break FUNCITONS(TYPES)'命令
来指定断点的确切位置。否则GDB会提供一个函数的选择的菜单供你选择。使用提示符
'>'来等待你的输入。开始的两个选择一般是'[0] cancel'和'[1] all'输入1则在所有
同名函数上加入断点。输入0则退出选择。
   下例为企图在重载的函数符号'String::after'上设置断点。
     (gdb) b String::after
     [0] cancel
     [1] all
     [2] file:String.cc; line number:867
     [3] file:String.cc; line number:860
     [4] file:String.cc; line number:875
     [5] file:String.cc; line number:853
     [6] file:String.cc; line number:846
     [7] file:String.cc; line number:735
     > 2 4 6
     Breakpoint 1 at 0xb26c: file String.cc, line 867.
     Breakpoint 2 at 0xb344: file String.cc, line 875.
     Breakpoint 3 at 0xafcc: file String.cc, line 846.
     Multiple breakpoints were set.
     Use the "delete" command to delete unwanted
      breakpoints.
     (gdb)

--
※ 来源: 中国科大BBS站 [bbs.ustc.edu.cn]
--
※ 转载:.紫 丁 香 bbs.hit.edu.cn.[FROM: poster.hit.edu.c]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:211.196毫秒