mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 06:39:25 +01:00 
			
		
		
		
	that deal with paths/filenames with TPathStr (= ansistring) to prevent
    cutting off long paths (no change in speed when compiling the compiler,
    1% extra memory usage)
git-svn-id: trunk@21120 -
		
	
			
		
			
				
	
	
		
			473 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			473 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    Copyright (c) 2012 by Jonas Maebe
 | 
						|
 | 
						|
    This units contains support for STABX debug info generation
 | 
						|
 | 
						|
    This program is free software; you can redistribute it and/or modify
 | 
						|
    it under the terms of the GNU General Public License as published by
 | 
						|
    the Free Software Foundation; either version 2 of the License, or
 | 
						|
    (at your option) any later version.
 | 
						|
 | 
						|
    This program is distributed in the hope that it will be useful,
 | 
						|
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
    GNU General Public License for more details.
 | 
						|
 | 
						|
    You should have received a copy of the GNU General Public License
 | 
						|
    along with this program; if not, write to the Free Software
 | 
						|
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
						|
 | 
						|
 ****************************************************************************
 | 
						|
}
 | 
						|
unit dbgstabx;
 | 
						|
 | 
						|
{$i fpcdefs.inc}
 | 
						|
 | 
						|
interface
 | 
						|
 | 
						|
  uses
 | 
						|
    cclasses,globtype,
 | 
						|
    dbgbase,dbgstabs,cgbase,
 | 
						|
    symtype,symdef,symsym,symtable,symbase,
 | 
						|
    aasmtai,aasmdata;
 | 
						|
 | 
						|
  type
 | 
						|
    TDebugInfoStabx = class(TDebugInfoStabs)
 | 
						|
     protected
 | 
						|
      function staticvarsym_mangled_name(sym: tstaticvarsym): string; override;
 | 
						|
      procedure maybe_add_vmt_sym(list: TAsmList; def: tobjectdef); override;
 | 
						|
      procedure write_def_stabstr(list:TAsmList;def:tdef;const ss:ansistring);override;
 | 
						|
      function  base_stabs_str(const typ, other, desc, value: ansistring): ansistring;overload;override;
 | 
						|
      function  gen_procdef_startsym_stabs(def: tprocdef): TAsmList; override;
 | 
						|
      function  gen_procdef_endsym_stabs(def: tprocdef): TAsmList; override;
 | 
						|
      procedure appendsym_label(list: TAsmList; sym: tlabelsym); override;
 | 
						|
      procedure appendsym_staticvar(list: TAsmList; sym: tstaticvarsym); override;
 | 
						|
     public
 | 
						|
      procedure insertlineinfo(list:TAsmList);override;
 | 
						|
      procedure insertmoduleinfo; override;
 | 
						|
      procedure referencesections(list: TAsmList); override;
 | 
						|
 | 
						|
      constructor create;override;
 | 
						|
    end;
 | 
						|
 | 
						|
implementation
 | 
						|
 | 
						|
  uses
 | 
						|
    globals,cutils,cfileutl,verbose,
 | 
						|
    systems,finput,fmodule,
 | 
						|
    aasmbase,
 | 
						|
    symconst;
 | 
						|
 | 
						|
  const
 | 
						|
    STABX_N_GSYM = $80;
 | 
						|
    STABX_N_LSYM = $81;
 | 
						|
    STABX_N_PSYM = $82;
 | 
						|
    STABX_N_RSYM = $83;
 | 
						|
    STABX_N_RPSYM = $84;
 | 
						|
    STABX_N_STSYM = $85;
 | 
						|
    STABX_N_LCSYM = 255;
 | 
						|
    STABX_N_Function = $8e;
 | 
						|
    STABX_N_TextLine = 255;
 | 
						|
    STABX_N_DataLine = 255;
 | 
						|
    STABX_N_BssLine = 255;
 | 
						|
    STABX_N_DECL = $8c;
 | 
						|
    STABX_N_tsym = $86;
 | 
						|
    STABX_N_SourceFile = 255;
 | 
						|
    STABX_N_OSO = 255;
 | 
						|
    STABX_N_IncludeFile = 255;
 | 
						|
    STABX_N_BINCL = 255;
 | 
						|
    STABX_N_EINCL = 255;
 | 
						|
    STABX_N_LBRAC = 255;
 | 
						|
    STABX_N_EXCL = 255;
 | 
						|
    STABX_N_RBRAC = 255;
 | 
						|
 | 
						|
 | 
						|
{ TDebugInfoStabx }
 | 
						|
 | 
						|
  function TDebugInfoStabx.base_stabs_str(const typ, other, desc, value: ansistring): ansistring;
 | 
						|
    begin
 | 
						|
      { no other/desc }
 | 
						|
      result:=value+','+typ+',0';
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
  function TDebugInfoStabx.staticvarsym_mangled_name(sym: tstaticvarsym): string;
 | 
						|
    begin
 | 
						|
      { create reference to the local symbol at the same address as the global
 | 
						|
        symbol (with same name as unmangled symbol, so GDB can find it) }
 | 
						|
      Result:=ReplaceForbiddenAsmSymbolChars(sym.name);
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
  procedure TDebugInfoStabx.maybe_add_vmt_sym(list: TAsmList; def: tobjectdef);
 | 
						|
    begin
 | 
						|
(*
 | 
						|
      if assigned(def.owner) and
 | 
						|
         def.owner.iscurrentunit then
 | 
						|
        begin
 | 
						|
          if (oo_has_vmt in def.objectoptions) and
 | 
						|
             assigned(def.owner.name) then
 | 
						|
            list.concat(Tai_stab.create_ansistr(stabsdir,ansistring('"vmt_')+GetSymTableName(def.owner)+tobjectdef(def).objname^+':S'+
 | 
						|
                   def_stab_number(vmttype)+'",'+
 | 
						|
                   base_stabs_str(globalvarsym_inited_stab,'0','0',ReplaceForbiddenAsmSymbolChars(tobjectdef(def).vmt_mangledname)+'.')));
 | 
						|
        end;
 | 
						|
*)
 | 
						|
      { do nothing, because creating debug information for a global symbol
 | 
						|
        defined in another unit is not possible for stabx given the FPC
 | 
						|
        constraints (namely that the name of the global symbol does not match
 | 
						|
        the name of the variable). If it's in the same unit, we have to add an
 | 
						|
        extra symbol for the vmt with the same variable name as what we have
 | 
						|
        here (ansistring('"vmt_')+GetSymTableName(def.owner)+tobjectdef(def).objname^).
 | 
						|
        We'd have to do that when that symbol is created, in generic code,
 | 
						|
        which is not very clean, and moreover these symbols are not really
 | 
						|
        used for anything currently, afaik }
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
  procedure TDebugInfoStabx.write_def_stabstr(list:TAsmList;def:tdef;const ss:ansistring);
 | 
						|
    var
 | 
						|
      stabchar,
 | 
						|
      symname,
 | 
						|
      declstabnr,
 | 
						|
      st    : ansistring;
 | 
						|
    begin
 | 
						|
      { type prefix }
 | 
						|
      if def.typ in tagtypes then
 | 
						|
        stabchar := tagtypeprefix
 | 
						|
      else
 | 
						|
        stabchar := 't';
 | 
						|
      { in case of writing the class record structure, we always have to
 | 
						|
        use the class name (so it refers both to the struct and the
 | 
						|
        pointer to the struct), otherwise gdb crashes (see tests/webtbs/tw9766.pp) }
 | 
						|
 | 
						|
      if is_class(def) and
 | 
						|
         tobjectdef(def).writing_class_record_dbginfo then
 | 
						|
        begin
 | 
						|
          declstabnr:=def_stab_classnumber(tobjectdef(def));
 | 
						|
          symname:='${sym_name}'
 | 
						|
        end
 | 
						|
      else
 | 
						|
        begin
 | 
						|
          { Type names for types defined in the current unit are already written in
 | 
						|
            the typesym }
 | 
						|
          if (def.owner.symtabletype=globalsymtable) and
 | 
						|
             not(def.owner.iscurrentunit) then
 | 
						|
            symname:='${sym_name}'
 | 
						|
          else
 | 
						|
            symname:='';
 | 
						|
          declstabnr:=def_stab_number(def)
 | 
						|
        end;
 | 
						|
      if (symname='') or
 | 
						|
         not(def.typ in tagtypes) then
 | 
						|
        begin
 | 
						|
          st:=def_stabstr_evaluate(def,':$1$2=',[stabchar,declstabnr]);
 | 
						|
          st:='"'+def_stabstr_evaluate(def,symname,[])+st+ss;
 | 
						|
          { line info is set to 0 for all defs, because the def can be in another
 | 
						|
            unit and then the linenumber is invalid in the current sourcefile }
 | 
						|
          st:=st+'",'+base_stabs_str(def_stab,'0','0','0');
 | 
						|
          { add to list }
 | 
						|
          list.concat(Tai_stab.create_ansistr(stabsdir,st));
 | 
						|
        end
 | 
						|
      else
 | 
						|
        begin
 | 
						|
          { first tag, then type decl }
 | 
						|
          inc(global_stab_number);
 | 
						|
          st:=def_stabstr_evaluate(def,':$1$2=',[stabchar,tostr(global_stab_number)]);
 | 
						|
          st:='"'+st+ss;
 | 
						|
          st:=st+'",'+base_stabs_str(def_stab,'0','0','0');
 | 
						|
          list.concat(Tai_stab.create_ansistr(stabsdir,st));
 | 
						|
          st:='"'+def_stabstr_evaluate(def,symname+':t$1=$2',[declstabnr,tostr(global_stab_number)]);
 | 
						|
          st:=st+'",'+base_stabs_str(def_stab,'0','0','0');
 | 
						|
          list.concat(Tai_stab.create_ansistr(stabsdir,st));
 | 
						|
        end;
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
  function TDebugInfoStabx.gen_procdef_startsym_stabs(def: tprocdef): TAsmList;
 | 
						|
    var
 | 
						|
      mangledname: ansistring;
 | 
						|
      hp, hpp, inclstart: tai;
 | 
						|
    begin
 | 
						|
      result:=inherited;
 | 
						|
      { can happen for procdefs defined in other units, this code is only for
 | 
						|
        the place where it is defined }
 | 
						|
      if not assigned(def.procstarttai) then
 | 
						|
        exit;
 | 
						|
      mangledname:=ReplaceForbiddenAsmSymbolChars(def.mangledname);
 | 
						|
      if target_info.system in systems_dotted_function_names then
 | 
						|
        mangledname:='.'+mangledname;
 | 
						|
      result.concat(tai_stab.create(stabx_function,
 | 
						|
        strpnew(mangledname+','+mangledname+',16,044,LT.'+mangledname+'-'+mangledname)));
 | 
						|
      { hoist the already generated ".bf" up right after the function
 | 
						|
        definition so that all parameter and local variable definitions come
 | 
						|
        after it -- we have to generate it during lineinfo generation and not
 | 
						|
        here to make sure it takes into account include files opened right after
 | 
						|
        the function definition but before the code starts
 | 
						|
        -- also move include file start if any}
 | 
						|
      hp:=def.procstarttai;
 | 
						|
      inclstart:=nil;
 | 
						|
      while (hp.typ<>ait_symbol_end) and
 | 
						|
            ((hp.typ<>ait_stab) or
 | 
						|
             (tai_stab(hp).stabtype<>stabx_bf)) do
 | 
						|
        begin
 | 
						|
          if (hp.typ=ait_stab) and
 | 
						|
             (tai_stab(hp).stabtype=stabx_bi) then
 | 
						|
            inclstart:=hp;
 | 
						|
          hp:=tai(hp.next);
 | 
						|
        end;
 | 
						|
      { happens for implicit unit init routines and the like, they don't get
 | 
						|
        line info }
 | 
						|
      if hp.typ=ait_symbol_end then
 | 
						|
        exit;
 | 
						|
      if assigned(inclstart) then
 | 
						|
        begin
 | 
						|
          current_asmdata.asmlists[al_procedures].Remove(inclstart);
 | 
						|
          result.concat(inclstart);
 | 
						|
        end;
 | 
						|
      current_asmdata.asmlists[al_procedures].Remove(hp);
 | 
						|
      result.concat(hp);
 | 
						|
      { also hoist up the function start symbol(s) }
 | 
						|
      hp:=def.procstarttai;
 | 
						|
      while assigned(hp) and
 | 
						|
            (hp.typ<>ait_symbol_end) do
 | 
						|
        begin
 | 
						|
          if (hp.typ=ait_symbol) and
 | 
						|
             (tai_symbol(hp).sym.typ=AT_FUNCTION) then
 | 
						|
            begin
 | 
						|
              hpp:=tai(hp.next);
 | 
						|
              if hp=def.procstarttai then
 | 
						|
                def.procstarttai:=hpp;
 | 
						|
              current_asmdata.asmlists[al_procedures].Remove(hp);
 | 
						|
              result.insert(hp);
 | 
						|
              hp:=hpp;
 | 
						|
            end
 | 
						|
          else
 | 
						|
            hp:=tai(hp.next);
 | 
						|
        end;
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
  function TDebugInfoStabx.gen_procdef_endsym_stabs(def: tprocdef): TAsmList;
 | 
						|
    var
 | 
						|
      procendsymbol: tasmsymbol;
 | 
						|
    begin
 | 
						|
      result:=inherited gen_procdef_endsym_stabs(def);
 | 
						|
      if not assigned(def.procstarttai) then
 | 
						|
        exit;
 | 
						|
      procendsymbol:=current_asmdata.DefineAsmSymbol('LT..'+ReplaceForbiddenAsmSymbolChars(def.mangledname),AB_LOCAL,AT_ADDR);
 | 
						|
      current_asmdata.asmlists[al_procedures].insertbefore(tai_symbol.create(procendsymbol,0),def.procendtai);
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
  procedure TDebugInfoStabx.appendsym_label(list: TAsmList; sym: tlabelsym);
 | 
						|
    begin
 | 
						|
      // ignore, not sure what kind of debug information we could generate for
 | 
						|
      // this
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
  procedure TDebugInfoStabx.appendsym_staticvar(list: TAsmList; sym: tstaticvarsym);
 | 
						|
    var
 | 
						|
      ismem,
 | 
						|
      isglobal: boolean;
 | 
						|
    begin
 | 
						|
      if vo_is_external in sym.varoptions then
 | 
						|
        exit;
 | 
						|
      ismem:=not(sym.localloc.loc in [LOC_REGISTER,LOC_CREGISTER,LOC_MMREGISTER,LOC_CMMREGISTER,LOC_FPUREGISTER,LOC_CFPUREGISTER]);
 | 
						|
      if ismem then
 | 
						|
        isglobal:=current_asmdata.RefAsmSymbol(sym.mangledname).bind=AB_GLOBAL;
 | 
						|
 | 
						|
      { put extra ss/es markers in place }
 | 
						|
      if ismem then
 | 
						|
        if isglobal then
 | 
						|
          list.concat(tai_stab.Create_ansistr(stabx_bs,'.data[RW]'))
 | 
						|
        else
 | 
						|
          list.concat(tai_stab.Create_ansistr(stabx_bs,'_data.bss_[RW]'));
 | 
						|
      inherited;
 | 
						|
      if ismem then
 | 
						|
        list.concat(tai_stab.Create_ansistr(stabx_es,''));
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
  procedure TDebugInfoStabx.insertlineinfo(list: TAsmList);
 | 
						|
    var
 | 
						|
      currfileinfo,
 | 
						|
      lastfileinfo,
 | 
						|
      curincludefileinfo,
 | 
						|
      curfunstartfileinfo: tfileposinfo;
 | 
						|
      currsectype  : TAsmSectiontype;
 | 
						|
      hp, inclinsertpos, last : tai;
 | 
						|
      infile : tinputfile;
 | 
						|
      i,
 | 
						|
      linenr,
 | 
						|
      nolineinfolevel: longint;
 | 
						|
      nextlineisfunstart: boolean;
 | 
						|
    begin
 | 
						|
      FillChar(currfileinfo,sizeof(currfileinfo),0);
 | 
						|
      FillChar(lastfileinfo,sizeof(lastfileinfo),0);
 | 
						|
      FillChar(curincludefileinfo,sizeof(curincludefileinfo),0);
 | 
						|
      FillChar(curfunstartfileinfo,sizeof(curfunstartfileinfo),0);
 | 
						|
      currsectype:=sec_code;
 | 
						|
      hp:=Tai(list.first);
 | 
						|
      nextlineisfunstart:=false;
 | 
						|
      nolineinfolevel:=0;
 | 
						|
      last:=nil;
 | 
						|
      while assigned(hp) do
 | 
						|
        begin
 | 
						|
          case hp.typ of
 | 
						|
            ait_section :
 | 
						|
              currsectype:=tai_section(hp).sectype;
 | 
						|
            ait_force_line :
 | 
						|
              lastfileinfo.line:=-1;
 | 
						|
            ait_symbol:
 | 
						|
              if tai_symbol(hp).sym.typ = AT_FUNCTION then
 | 
						|
                nextlineisfunstart:=true;
 | 
						|
            ait_symbol_end:
 | 
						|
              if tai_symbol_end(hp).sym.typ = AT_FUNCTION then
 | 
						|
                begin
 | 
						|
                  { end of function }
 | 
						|
                  list.insertbefore(Tai_stab.Create_str(stabx_ef,tostr(currfileinfo.line)),hp);
 | 
						|
                end;
 | 
						|
            ait_marker :
 | 
						|
              begin
 | 
						|
                case tai_marker(hp).kind of
 | 
						|
                  mark_NoLineInfoStart:
 | 
						|
                    inc(nolineinfolevel);
 | 
						|
                  mark_NoLineInfoEnd:
 | 
						|
                    dec(nolineinfolevel);
 | 
						|
                end;
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
 | 
						|
          if (currsectype=sec_code) and
 | 
						|
             (hp.typ=ait_instruction) then
 | 
						|
            begin
 | 
						|
              currfileinfo:=tailineinfo(hp).fileinfo;
 | 
						|
 | 
						|
              inclinsertpos:=hp;
 | 
						|
              while assigned(inclinsertpos.previous) and
 | 
						|
                    (tai(inclinsertpos.previous).typ in (SkipInstr+[ait_marker])) do
 | 
						|
                inclinsertpos:=tai(inclinsertpos.previous);
 | 
						|
 | 
						|
              { file changed ? (must be before line info) }
 | 
						|
              if (currfileinfo.fileindex<>0) and
 | 
						|
                 ((lastfileinfo.fileindex<>currfileinfo.fileindex) or
 | 
						|
                  (lastfileinfo.moduleindex<>currfileinfo.moduleindex)) then
 | 
						|
                begin
 | 
						|
                  if curincludefileinfo.fileindex<>0 then
 | 
						|
                    begin
 | 
						|
                      infile:=get_module(curincludefileinfo.moduleindex).sourcefiles.get_file(curincludefileinfo.fileindex);
 | 
						|
                      list.insertbefore(Tai_stab.Create_str(stabx_ei,'"'+FixFileName(infile.name)+'"'),inclinsertpos);
 | 
						|
                      curincludefileinfo.fileindex:=0;
 | 
						|
                    end;
 | 
						|
                  if currfileinfo.fileindex<>1 then
 | 
						|
                    begin
 | 
						|
                      infile:=get_module(currfileinfo.moduleindex).sourcefiles.get_file(currfileinfo.fileindex);
 | 
						|
                      if assigned(infile) then
 | 
						|
                        begin
 | 
						|
                          list.insertbefore(Tai_stab.Create_str(stabx_bi,'"'+FixFileName(infile.name)+'"'),inclinsertpos);
 | 
						|
                          curincludefileinfo:=currfileinfo;
 | 
						|
                          { force new line info }
 | 
						|
                          lastfileinfo.line:=-1;
 | 
						|
                        end;
 | 
						|
                    end
 | 
						|
                  else
 | 
						|
                    lastfileinfo.line:=-1;
 | 
						|
                  if nextlineisfunstart then
 | 
						|
                    begin
 | 
						|
                      curfunstartfileinfo:=currfileinfo;
 | 
						|
                      { insert here rather than via procdef, because the procdef
 | 
						|
                        may have been created in another file in case the body
 | 
						|
                        is completely declared in an include file }
 | 
						|
                      list.insertbefore(Tai_stab.Create_str(stabx_bf,tostr(currfileinfo.line)),hp);
 | 
						|
                      { -1 to avoid outputting a relative line 0 in the
 | 
						|
                        function, because that means something different }
 | 
						|
                      dec(curfunstartfileinfo.line);
 | 
						|
                      nextlineisfunstart:=false;
 | 
						|
                    end;
 | 
						|
 | 
						|
                end;
 | 
						|
 | 
						|
              if nolineinfolevel=0 then
 | 
						|
                begin
 | 
						|
                  { line changed ? }
 | 
						|
                  if (currfileinfo.line>lastfileinfo.line) and
 | 
						|
                     (currfileinfo.line<>0) then
 | 
						|
                    begin
 | 
						|
                      linenr:=currfileinfo.line;
 | 
						|
                      { line numbers in AIX are relative to the function start line
 | 
						|
                        (except if they are in a different file then where the
 | 
						|
                         function started!) }
 | 
						|
                      if (currfileinfo.fileindex=curfunstartfileinfo.fileindex) and
 | 
						|
                         (currfileinfo.moduleindex=curfunstartfileinfo.moduleindex) then
 | 
						|
                        dec(linenr,curfunstartfileinfo.line);
 | 
						|
                      { can be < 0 in case of bugs in the compiler }
 | 
						|
                      if (linenr > 0)
 | 
						|
{$ifndef cpu64bitaddr}
 | 
						|
                         { line numbers are unsigned short in 32 bit xcoff }
 | 
						|
                         and (linenr<=high(word))
 | 
						|
{$endif}
 | 
						|
                        then
 | 
						|
                         list.insertbefore(Tai_stab.Create_str(stabx_line,tostr(linenr)),hp);
 | 
						|
                    end;
 | 
						|
                  lastfileinfo:=currfileinfo;
 | 
						|
                end;
 | 
						|
            end;
 | 
						|
 | 
						|
          last:=hp;
 | 
						|
          hp:=tai(hp.next);
 | 
						|
        end;
 | 
						|
      { close include file if still open }
 | 
						|
      if curincludefileinfo.fileindex<>0 then
 | 
						|
        begin
 | 
						|
          infile:=get_module(curincludefileinfo.moduleindex).sourcefiles.get_file(curincludefileinfo.fileindex);
 | 
						|
          list.insertbefore(Tai_stab.Create_str(stabx_ei,'"'+FixFileName(infile.name)+'"'),last);
 | 
						|
          curincludefileinfo.fileindex:=0;
 | 
						|
        end;
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
  procedure TDebugInfoStabx.insertmoduleinfo;
 | 
						|
    begin
 | 
						|
      // do nothing
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
  procedure TDebugInfoStabx.referencesections(list: TAsmList);
 | 
						|
    begin
 | 
						|
      // do nothing
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
  constructor TDebugInfoStabx.create;
 | 
						|
    begin
 | 
						|
      inherited create;
 | 
						|
      dbgtype:=dbg_stabx;
 | 
						|
      stabsdir:=stab_stabx;
 | 
						|
 | 
						|
      def_stab:=STABX_N_DECL;
 | 
						|
      regvar_stab:=STABX_N_RPSYM;
 | 
						|
      procdef_stab:=STABX_N_Function;
 | 
						|
      constsym_stab:=STABX_N_GSYM;
 | 
						|
      typesym_stab:=STABX_N_DECL;
 | 
						|
      globalvarsym_uninited_stab:=STABX_N_STSYM;
 | 
						|
      globalvarsym_inited_stab:=STABX_N_STSYM;
 | 
						|
      staticvarsym_uninited_stab:=STABX_N_STSYM;
 | 
						|
      staticvarsym_inited_stab:=STABX_N_STSYM;
 | 
						|
      localvarsymref_stab:=STABX_N_LSYM;
 | 
						|
      paravarsymref_stab:=STABX_N_PSYM;
 | 
						|
 | 
						|
      tagtypeprefix:='T';
 | 
						|
    end;
 | 
						|
 | 
						|
  const
 | 
						|
    dbg_stabx_info : tdbginfo =
 | 
						|
       (
 | 
						|
         id     : dbg_stabx;
 | 
						|
         idtxt  : 'STABX';
 | 
						|
       );
 | 
						|
 | 
						|
initialization
 | 
						|
  RegisterDebugInfo(dbg_stabx_info,TDebugInfoStabx);
 | 
						|
end.
 |