193 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
			
		
		
	
	
			193 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
| 
 | |
|                         Xserver Debugging
 | |
|                         =================
 | |
| 
 | |
| This file is  intended to collect helpful hints  on Xserver debugging.
 | |
| I merely outline my experiences  here. Somebody else might have better
 | |
| methods on  doing it. This person  is therefore invited  to share this
 | |
| experience with the rest of the world by adding it here.
 | |
| 
 | |
| Paul Flinders has made some patches to gdb to add support for loadable
 | |
| modules.  This version  of gdb  is currently  available as  binary for
 | |
| Linux/x86 on Paul's web site:
 | |
| 
 | |
|          www.dawa.demon.co.uk/xfree-gdb
 | |
| 
 | |
| This web-site also contains the patches to gdb 4.18 so you may port it
 | |
| to other platforms.
 | |
| 
 | |
| It  loads  the module  symbols  and  supports  all gdb  features  like
 | |
| breakpointing, disassembling  and single  stepping. It also  shows the
 | |
| exact location of a signal 11. Paul  has fixed the code so that all of
 | |
| this is  working even  if using modules  compiled without -g.  You can
 | |
| find his latest version on his web site.
 | |
| 
 | |
| If no module aware gdb is available the following hints might help:
 | |
| 
 | |
| 1. Use remote  login. This  can be done  thru a network  connection or
 | |
|    simply by  connecting a serial  console. This enables you  to watch
 | |
|    the  Xservers output while  running set  breakpoints with  gdb etc.
 | |
|    Don't even try  to run the Xserver from  a system console. Whenever
 | |
|    something  happens gdb  waits for  input. However  the  Xserver has
 | |
|    locked the system console  including the keyboard, therefore you'll
 | |
|    never  be able  to send  any  input to  gdb. Even  if your  process
 | |
|    doesn't crash or you haven't set any breakpoints a vt switch can be
 | |
|    hazardous: When doing vt switching a signal is sent; unless you did
 | |
|          
 | |
|    gdb> handle SIGUSR1 nostop
 | |
| 
 | |
|    gdb waits  for you to continue  the program which  cannot happen as
 | |
|    you don't have access to gdb's console.
 | |
| 
 | |
| 2. You can  compile any source  file with debugging symbols  to obtain
 | |
|    more information  about where an  error occurred. Simply go  to the
 | |
|    directory which holds the corresponding object file and do:
 | |
|             
 | |
|    # rm <file>.o
 | |
|    # xc/config/util/makeg.sh <file>.o
 | |
| 
 | |
|    After  relinking the server  or module  gdb is  able to  obtain the
 | |
|    necessary debugging information and will show the exact line in the
 | |
|    source  where the error ccurred. See also:
 | |
|    xc/config/util/makeg.man.
 | |
| 
 | |
| 3. In some cases it might be  useful to have the assembler output of a
 | |
|    compiled source file. This can be obtained by doing:
 | |
|     
 | |
|    # make <file>.s
 | |
|    
 | |
|    or 
 | |
|  
 | |
|    # xc/config/util/makeg.sh <file>.s
 | |
| 
 | |
|    Make will use exactly the same rules it uses for building *.o files.
 | |
| 
 | |
| 4. In some cases it might be useful to set breakpoints in modules.  If
 | |
|    no module  aware gdb is available you  should add a call  to one of
 | |
|    the three dummy breakpoint functions
 | |
| 
 | |
|    xf86Break1(), xf86Break2() and xf86Break3()
 | |
| 
 | |
|    to the source  file and recompile the module. You  now just have to
 | |
|    set  a  breakpoint  onto  the appropriate  dummy  functions.  These
 | |
|    functions are located in the  core part of the server and therefore
 | |
|    will be available any time.
 | |
| 
 | |
| 5. Without module support gdb is  not able to print the function where
 | |
|    an error occurred in a module.
 | |
| 
 | |
|      If you get a line like:
 | |
| 
 | |
|    (gdb) bt
 | |
|    #0  0x823b4f5 in ?? ()
 | |
|    ....
 | |
| 
 | |
|    You may obtain the function the address belongs to by calling 
 | |
|    LoaderPrintSymbol():
 | |
| 
 | |
|    (gdb) call LoaderPrintSymbol(0x823b4f5)
 | |
| 
 | |
|    The symbol  returned might not always  be the name  of the function
 | |
|    which contains the address. In  case of static functions the symbol
 | |
|    is not known to  the loader. However LoaderPrintSymbol() will print
 | |
|    the nearest known  function and the offset from  its start. You may
 | |
|    easily find the exact location of the address if you do:
 | |
| 
 | |
|    # objdump --disassemble <file>.o
 | |
| 
 | |
|    <file>.o is the name of the object file containing the symbol printed.
 | |
| 
 | |
| 6. Locating static  symbols in modules is  simpler if the  module is a
 | |
|    single object  file instead  of a library.  Such a object  file can
 | |
|    easily  be build  from  a  library: #  mkdir  tmp #  cd  tmp; ar  x
 | |
|    module-path/<libname>.a # ld -r *.o -o module-path/<name>.o
 | |
|    
 | |
|    When calling  LoaderPrintSymbol() the closes public  symbol will be
 | |
|    printed together with  the offset from the symbol's  address.  If a
 | |
|    static symbol comes before the  first public symbol in a module The
 | |
|    following trick may help:
 | |
| 
 | |
|    create a file 1-<name>.c in tmp/
 | |
|    containing:
 | |
|    void Dummy-<name>() {}
 | |
|     
 | |
|    Compile it:
 | |
| 
 | |
|    # gcc -c 1-<name>.c
 | |
| 
 | |
|    and do the link step above.
 | |
| 
 | |
|    This way  Dummy-<name>() will be  the first public function  in the
 | |
|    module.   All  addresses in  static  function  can  now be  printed
 | |
|    relatively to this address if no other public function comes before
 | |
|    this static one.
 | |
| 
 | |
| 7. In some situations it is  quite helpful to add debugging symbols to
 | |
|    the binary.  This can  be done per  object file. Simply  remove the
 | |
|    object file and do
 | |
| 
 | |
|    # makeg
 | |
| 
 | |
|    When looking  for a bug  in a module  these debugging infos  can be
 | |
|    very helpful:  Calling LoaderPrintSymbol() as  described above will
 | |
|    return a  function and an offset  giving the exact  location of the
 | |
|    address  with   respect  to   this  function  entry   point.   When
 | |
|    disassembling an  object file with debugging symbols:  # objdump -d
 | |
|    -l <file>.o one will  receive a disassembled output containing line
 | |
|    number  information. Thus  one can  locate the  exact line  of code
 | |
|    where the error occurred.
 | |
| 
 | |
| 8. To quickly trace the value of a variable declared in a module three
 | |
|    dummy variables have been added to the core part:
 | |
| 
 | |
|    CARD32 xf86DummyVar1;
 | |
|    CARD32 xf86DummyVar2;
 | |
|    CARD32 xf86DummyVar3;
 | |
| 
 | |
|    The variable can  be assigned to one of them. One  can then use gdb
 | |
|    to return the value of this variable:
 | |
| 
 | |
|    gdb> p /x xf86DummyVar1
 | |
| 
 | |
| 9. Sometimes it might be useful to check how the preprocessor replaced
 | |
|    symbols. One can  obtain a preprocessed version of  the source file
 | |
|    by doing:
 | |
| 
 | |
|    make <filename>.i
 | |
| 
 | |
|    This will generate a preprocessed source in <filename>.i.
 | |
| 
 | |
| 10. xfree() can catch  if one tries to free a  memory range twice. You
 | |
|     will get the message:
 | |
| 
 | |
|        Xalloc error: range already freed in Xrealloc() :-(
 | |
| 
 | |
|   To  find  the  location  from  which  xfree()  was  called  one  can
 | |
|   breakpoint on XfreeTrap(). The backtrace should show the origin of the
 | |
|   call this call. 
 | |
| 
 | |
| 11. To access mapped physical  memory the following functions might be
 | |
|     useful.  
 | |
| 
 | |
|     These may be used to  access physical memory that was mapped using
 | |
|     the flags VIDMEM_FRAMEBUFFER or VIDMEM_MMIO32:
 | |
| 
 | |
|       CARD8  xf86PeekFb8(CARD8  *p);
 | |
|       CARD16 xf86PeekFb16(CARD16 *p);
 | |
|       CARD32 xf86PeekFb32(CARD32 *p);
 | |
|       void xf86PokeFb8(CARD8  *p, CARD8  v);
 | |
|       void xf86PokeFb16(CARD16 *p, CARD16 v);
 | |
|       void xf86PokeFb32(CARD16 *p, CARD32 v);
 | |
| 
 | |
|     Physical memory which was  mapped by setting VIDMEM_MMIO should be
 | |
|     accessed using the following.  Here  the base address to which the
 | |
|     memory is mapped and the offset are required separately.
 | |
| 
 | |
|       CARD8  xf86PeekMmio8(pointer Base, unsigned long Offset);
 | |
|       CARD16 xf86PeekMmio16(pointer Base, unsigned long Offset);
 | |
|       CARD32 xf86PeekMmio32(pointer Base, unsigned long Offset);
 | |
|       void xf86PokeMmio8(pointer Base, unsigned long Offset, CARD8  v);
 | |
|       void xf86PokeMmio16(pointer Base, unsigned long Offset, CARD16 v);
 | |
|       void xf86PokeMmio32(pointer Base, unsigned long Offset, CARD32 v);
 | |
| 
 |