mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-10-31 09:11:53 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1590 lines
		
	
	
		
			60 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			1590 lines
		
	
	
		
			60 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {
 | |
|     Copyright (c) 2003-2004 by Peter Vreman and Florian Klaempfl
 | |
| 
 | |
|     This units contains support for STABS 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 dbgstabs;
 | |
| 
 | |
| {$i fpcdefs.inc}
 | |
| 
 | |
| interface
 | |
| 
 | |
|     uses
 | |
|       cclasses,
 | |
|       dbgbase,
 | |
|       symtype,symdef,symsym,symtable,symbase,
 | |
|       aasmtai;
 | |
| 
 | |
|     type
 | |
|       TDebugInfoStabs=class(TDebugInfo)
 | |
|       private
 | |
|         writing_def_stabs  : boolean;
 | |
|         global_stab_number : word;
 | |
|         defnumberlist      : tlist;
 | |
|         { tsym writing }
 | |
|         function  sym_var_value(const s:string;arg:pointer):string;
 | |
|         function  sym_stabstr_evaluate(sym:tsym;const s:string;const vars:array of string):Pchar;
 | |
|         procedure write_symtable_syms(list:taasmoutput;st:tsymtable);
 | |
|         { tdef writing }
 | |
|         function  def_stab_number(def:tdef):string;
 | |
|         function  def_stab_classnumber(def:tobjectdef):string;
 | |
|         function  def_var_value(const s:string;arg:pointer):string;
 | |
|         function  def_stabstr_evaluate(def:tdef;const s:string;const vars:array of string):Pchar;
 | |
|         procedure field_add_stabstr(p:Tnamedindexitem;arg:pointer);
 | |
|         procedure method_add_stabstr(p:Tnamedindexitem;arg:pointer);
 | |
|         function  def_stabstr(def:tdef):pchar;
 | |
|         procedure write_def_stabstr(list:taasmoutput;def:tdef);
 | |
|         procedure field_write_defs(p:Tnamedindexitem;arg:pointer);
 | |
|         procedure method_write_defs(p :tnamedindexitem;arg:pointer);
 | |
|         procedure write_symtable_defs(list:taasmoutput;st:tsymtable);
 | |
|         procedure write_procdef(list:taasmoutput;pd:tprocdef);
 | |
|         procedure insertsym(list:taasmoutput;sym:tsym);
 | |
|         procedure insertdef(list:taasmoutput;def:tdef);
 | |
|       public
 | |
|         procedure inserttypeinfo;override;
 | |
|         procedure insertmoduleinfo;override;
 | |
|         procedure insertlineinfo(list:taasmoutput);override;
 | |
|         procedure referencesections(list:taasmoutput);override;
 | |
|       end;
 | |
| 
 | |
| 
 | |
| implementation
 | |
| 
 | |
|     uses
 | |
|       strings,cutils,
 | |
|       systems,globals,globtype,verbose,
 | |
|       symconst,defutil,
 | |
|       cpuinfo,cpubase,cgbase,paramgr,
 | |
|       aasmbase,procinfo,
 | |
|       finput,fmodule,ppu;
 | |
| 
 | |
|     const
 | |
|       memsizeinc = 512;
 | |
| 
 | |
|       N_GSYM = $20;
 | |
|       N_STSYM = 38;     { initialized const }
 | |
|       N_LCSYM = 40;     { non initialized variable}
 | |
|       N_Function = $24; { function or const }
 | |
|       N_TextLine = $44;
 | |
|       N_DataLine = $46;
 | |
|       N_BssLine = $48;
 | |
|       N_RSYM = $40;     { register variable }
 | |
|       N_LSYM = $80;
 | |
|       N_tsym = 160;
 | |
|       N_SourceFile = $64;
 | |
|       N_IncludeFile = $84;
 | |
|       N_BINCL = $82;
 | |
|       N_EINCL = $A2;
 | |
|       N_EXCL  = $C2;
 | |
| 
 | |
|       tagtypes = [
 | |
|         recorddef,
 | |
|         enumdef,
 | |
|         stringdef,
 | |
|         filedef,
 | |
|         objectdef
 | |
|       ];
 | |
| 
 | |
|     type
 | |
|        get_var_value_proc=function(const s:string;arg:pointer):string of object;
 | |
| 
 | |
|        Trecord_stabgen_state=record
 | |
|           stabstring:Pchar;
 | |
|           stabsize,staballoc,recoffset:integer;
 | |
|        end;
 | |
|        Precord_stabgen_state=^Trecord_stabgen_state;
 | |
| 
 | |
| 
 | |
|     function string_evaluate(s:string;get_var_value:get_var_value_proc;
 | |
|                              get_var_value_arg:pointer;
 | |
|                              const vars:array of string):Pchar;
 | |
| 
 | |
|     (*
 | |
|      S contains a prototype of a result. Stabstr_evaluate will expand
 | |
|      variables and parameters.
 | |
| 
 | |
|      Output is s in ASCIIZ format, with the following expanded:
 | |
| 
 | |
|      ${varname}   - The variable name is expanded.
 | |
|      $n           - The parameter n is expanded.
 | |
|      $$           - Is expanded to $
 | |
|     *)
 | |
| 
 | |
|     const maxvalue=9;
 | |
|           maxdata=1023;
 | |
| 
 | |
|     var i,j:byte;
 | |
|         varname:string[63];
 | |
|         varno,varcounter:byte;
 | |
|         varvalues:array[0..9] of Pstring;
 | |
|         {1 kb of parameters is the limit. 256 extra bytes are allocated to
 | |
|          ensure buffer integrity.}
 | |
|         varvaluedata:array[0..maxdata+256] of char;
 | |
|         varptr:Pchar;
 | |
|         varidx : byte;
 | |
|         len:cardinal;
 | |
|         r:Pchar;
 | |
| 
 | |
|     begin
 | |
|       {Two pass approach, first, calculate the length and receive variables.}
 | |
|       i:=1;
 | |
|       len:=0;
 | |
|       varcounter:=0;
 | |
|       varptr:=@varvaluedata;
 | |
|       while i<=length(s) do
 | |
|         begin
 | |
|           if (s[i]='$') and (i<length(s)) then
 | |
|             begin
 | |
|              if s[i+1]='$' then
 | |
|                begin
 | |
|                  inc(len);
 | |
|                  inc(i);
 | |
|                end
 | |
|              else if (s[i+1]='{') and (length(s)>2) and (i<length(s)-2) then
 | |
|                begin
 | |
|                  varname:='';
 | |
|                  inc(i,2);
 | |
|                  repeat
 | |
|                    inc(varname[0]);
 | |
|                    varname[length(varname)]:=s[i];
 | |
|                    s[i]:=char(varcounter);
 | |
|                    inc(i);
 | |
|                  until s[i]='}';
 | |
|                  varvalues[varcounter]:=Pstring(varptr);
 | |
|                  if varptr>@varvaluedata+maxdata then
 | |
|                    internalerrorproc(200411152);
 | |
|                  Pstring(varptr)^:=get_var_value(varname,get_var_value_arg);
 | |
|                  inc(len,length(Pstring(varptr)^));
 | |
|                  inc(varptr,length(Pstring(varptr)^)+1);
 | |
|                  inc(varcounter);
 | |
|                end
 | |
|              else if s[i+1] in ['1'..'9'] then
 | |
|                begin
 | |
|                  varidx:=byte(s[i+1])-byte('1');
 | |
|                  if varidx>high(vars) then
 | |
|                    internalerror(200509263);
 | |
|                  inc(len,length(vars[varidx]));
 | |
|                  inc(i);
 | |
|                end;
 | |
|             end
 | |
|           else
 | |
|             inc(len);
 | |
|           inc(i);
 | |
|         end;
 | |
| 
 | |
|       {Second pass, writeout result.}
 | |
|       getmem(r,len+1);
 | |
|       string_evaluate:=r;
 | |
|       i:=1;
 | |
|       while i<=length(s) do
 | |
|         begin
 | |
|           if (s[i]='$') and (i<length(s)) then
 | |
|             begin
 | |
|              if s[i+1]='$' then
 | |
|                begin
 | |
|                  r^:='$';
 | |
|                  inc(r);
 | |
|                  inc(i);
 | |
|                end
 | |
|              else if (s[i+1]='{') and (length(s)>2) and (i<length(s)-2) then
 | |
|                begin
 | |
|                  varname:='';
 | |
|                  inc(i,2);
 | |
|                  varno:=byte(s[i]);
 | |
|                  repeat
 | |
|                    inc(i);
 | |
|                  until s[i]='}';
 | |
|                  for j:=1 to length(varvalues[varno]^) do
 | |
|                    begin
 | |
|                      r^:=varvalues[varno]^[j];
 | |
|                      inc(r);
 | |
|                    end;
 | |
|                end
 | |
|              else if s[i+1] in ['0'..'9'] then
 | |
|                begin
 | |
|                  for j:=1 to length(vars[byte(s[i+1])-byte('1')]) do
 | |
|                    begin
 | |
|                      r^:=vars[byte(s[i+1])-byte('1')][j];
 | |
|                      inc(r);
 | |
|                    end;
 | |
|                  inc(i);
 | |
|                end
 | |
|             end
 | |
|           else
 | |
|             begin
 | |
|               r^:=s[i];
 | |
|               inc(r);
 | |
|             end;
 | |
|           inc(i);
 | |
|         end;
 | |
|       r^:=#0;
 | |
|     end;
 | |
| 
 | |
| 
 | |
| {****************************************************************************
 | |
|                                TDef support
 | |
| ****************************************************************************}
 | |
| 
 | |
|     function TDebugInfoStabs.def_stab_number(def:tdef):string;
 | |
|       begin
 | |
|         { procdefs only need a number, mark them as already written
 | |
|           so they won't be written implicitly }
 | |
|         if (def.deftype=procdef) then
 | |
|           def.stab_state:=stab_state_written;
 | |
|         { Stab must already be written, or we must be busy writing it }
 | |
|         if writing_def_stabs and
 | |
|            not(def.stab_state in [stab_state_writing,stab_state_written]) then
 | |
|           internalerror(200403091);
 | |
|         { Keep track of used stabs, this info is only usefull for stabs
 | |
|           referenced by the symbols. Definitions will always include all
 | |
|           required stabs }
 | |
|         if def.stab_state=stab_state_unused then
 | |
|           def.stab_state:=stab_state_used;
 | |
|         { Need a new number? }
 | |
|         if def.stab_number=0 then
 | |
|           begin
 | |
|             inc(global_stab_number);
 | |
|             { classes require 2 numbers }
 | |
|             if is_class(def) then
 | |
|               inc(global_stab_number);
 | |
|             def.stab_number:=global_stab_number;
 | |
|             if global_stab_number>=defnumberlist.count then
 | |
|               defnumberlist.count:=global_stab_number+250;
 | |
|             defnumberlist[global_stab_number]:=def;
 | |
|           end;
 | |
|         result:=tostr(def.stab_number);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function TDebugInfoStabs.def_stab_classnumber(def:tobjectdef):string;
 | |
|       begin
 | |
|         if def.stab_number=0 then
 | |
|           def_stab_number(def);
 | |
|         result:=tostr(def.stab_number-1);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function TDebugInfoStabs.def_var_value(const s:string;arg:pointer):string;
 | |
|       var
 | |
|         def : tdef;
 | |
|       begin
 | |
|         def:=tdef(arg);
 | |
|         result:='';
 | |
|         if s='numberstring' then
 | |
|           result:=def_stab_number(def)
 | |
|         else if s='sym_name' then
 | |
|           begin
 | |
|             if assigned(def.typesym) then
 | |
|                result:=Ttypesym(def.typesym).name;
 | |
|           end
 | |
|         else if s='N_LSYM' then
 | |
|           result:=tostr(N_LSYM)
 | |
|         else if s='savesize' then
 | |
|           result:=tostr(def.size);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function TDebugInfoStabs.def_stabstr_evaluate(def:tdef;const s:string;const vars:array of string):Pchar;
 | |
|       begin
 | |
|         result:=string_evaluate(s,@def_var_value,def,vars);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure TDebugInfoStabs.field_add_stabstr(p:Tnamedindexitem;arg:pointer);
 | |
|       var
 | |
|         newrec  : Pchar;
 | |
|         spec    : string[3];
 | |
|         varsize : aint;
 | |
|         state   : Precord_stabgen_state;
 | |
|       begin
 | |
|         state:=arg;
 | |
|         { static variables from objects are like global objects }
 | |
|         if (Tsym(p).typ=fieldvarsym) and
 | |
|            not(sp_static in Tsym(p).symoptions) then
 | |
|           begin
 | |
|             if ([sp_protected,sp_strictprotected]*tsym(p).symoptions)<>[] then
 | |
|               spec:='/1'
 | |
|             else if ([sp_private,sp_strictprivate]*tsym(p).symoptions)<>[] then
 | |
|               spec:='/0'
 | |
|             else
 | |
|               spec:='';
 | |
|             varsize:=tfieldvarsym(p).vartype.def.size;
 | |
|             { open arrays made overflows !! }
 | |
|             if varsize>$fffffff then
 | |
|               varsize:=$fffffff;
 | |
|             newrec:=def_stabstr_evaluate(nil,'$1:$2,$3,$4;',[p.name,
 | |
|                                      spec+def_stab_number(tfieldvarsym(p).vartype.def),
 | |
|                                      tostr(tfieldvarsym(p).fieldoffset*8),tostr(varsize*8)]);
 | |
|             if state^.stabsize+strlen(newrec)>=state^.staballoc-256 then
 | |
|               begin
 | |
|                 inc(state^.staballoc,strlen(newrec)+64);
 | |
|                 reallocmem(state^.stabstring,state^.staballoc);
 | |
|               end;
 | |
|             strcopy(state^.stabstring+state^.stabsize,newrec);
 | |
|             inc(state^.stabsize,strlen(newrec));
 | |
|             strdispose(newrec);
 | |
|             {This should be used for case !!}
 | |
|             inc(state^.recoffset,Tfieldvarsym(p).vartype.def.size);
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure TDebugInfoStabs.method_add_stabstr(p:Tnamedindexitem;arg:pointer);
 | |
|       var virtualind,argnames : string;
 | |
|           newrec : pchar;
 | |
|           pd     : tprocdef;
 | |
|           lindex : longint;
 | |
|           arglength : byte;
 | |
|           sp : char;
 | |
|           state:^Trecord_stabgen_state;
 | |
|           olds:integer;
 | |
|           i : integer;
 | |
|           parasym : tparavarsym;
 | |
|       begin
 | |
|         state:=arg;
 | |
|         if tsym(p).typ = procsym then
 | |
|          begin
 | |
|            pd := tprocsym(p).first_procdef;
 | |
|            if (po_virtualmethod in pd.procoptions) then
 | |
|              begin
 | |
|                lindex := pd.extnumber;
 | |
|                {doesnt seem to be necessary
 | |
|                lindex := lindex or $80000000;}
 | |
|                virtualind := '*'+tostr(lindex)+';'+def_stab_classnumber(pd._class)+';'
 | |
|              end
 | |
|             else
 | |
|              virtualind := '.';
 | |
| 
 | |
|             { used by gdbpas to recognize constructor and destructors }
 | |
|             if (pd.proctypeoption=potype_constructor) then
 | |
|               argnames:='__ct__'
 | |
|             else if (pd.proctypeoption=potype_destructor) then
 | |
|               argnames:='__dt__'
 | |
|             else
 | |
|               argnames := '';
 | |
| 
 | |
|            { arguments are not listed here }
 | |
|            {we don't need another definition}
 | |
|             for i:=0 to pd.paras.count-1 do
 | |
|               begin
 | |
|                 parasym:=tparavarsym(pd.paras[i]);
 | |
|                 if Parasym.vartype.def.deftype = formaldef then
 | |
|                   begin
 | |
|                     case Parasym.varspez of
 | |
|                       vs_var :
 | |
|                         argnames := argnames+'3var';
 | |
|                       vs_const :
 | |
|                         argnames:=argnames+'5const';
 | |
|                       vs_out :
 | |
|                         argnames:=argnames+'3out';
 | |
|                     end;
 | |
|                   end
 | |
|                 else
 | |
|                   begin
 | |
|                     { if the arg definition is like (v: ^byte;..
 | |
|                     there is no sym attached to data !!! }
 | |
|                     if assigned(Parasym.vartype.def.typesym) then
 | |
|                       begin
 | |
|                         arglength := length(Parasym.vartype.def.typesym.name);
 | |
|                         argnames := argnames + tostr(arglength)+Parasym.vartype.def.typesym.name;
 | |
|                       end
 | |
|                     else
 | |
|                       argnames:=argnames+'11unnamedtype';
 | |
|                   end;
 | |
|               end;
 | |
|            { here 2A must be changed for private and protected }
 | |
|            { 0 is private 1 protected and 2 public }
 | |
|            if ([sp_private,sp_strictprivate]*tsym(p).symoptions)<>[] then
 | |
|              sp:='0'
 | |
|            else if ([sp_protected,sp_strictprotected]*tsym(p).symoptions)<>[] then
 | |
|              sp:='1'
 | |
|            else
 | |
|              sp:='2';
 | |
|            newrec:=def_stabstr_evaluate(nil,'$1::$2=##$3;:$4;$5A$6;',[p.name,def_stab_number(pd),
 | |
|                                     def_stab_number(pd.rettype.def),argnames,sp,
 | |
|                                     virtualind]);
 | |
|            { get spare place for a string at the end }
 | |
|            olds:=state^.stabsize;
 | |
|            inc(state^.stabsize,strlen(newrec));
 | |
|            if state^.stabsize>=state^.staballoc-256 then
 | |
|              begin
 | |
|                 inc(state^.staballoc,strlen(newrec)+64);
 | |
|                 reallocmem(state^.stabstring,state^.staballoc);
 | |
|              end;
 | |
|            strcopy(state^.stabstring+olds,newrec);
 | |
|            strdispose(newrec);
 | |
|            {This should be used for case !!
 | |
|            RecOffset := RecOffset + pd.size;}
 | |
|          end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function TDebugInfoStabs.def_stabstr(def:tdef):pchar;
 | |
| 
 | |
|         function stringdef_stabstr(def:tstringdef):pchar;
 | |
|           var
 | |
|             slen : aint;
 | |
|             bytest,charst,longst : string;
 | |
|           begin
 | |
|             case def.string_typ of
 | |
|               st_shortstring:
 | |
|                 begin
 | |
|                   { fix length of openshortstring }
 | |
|                   slen:=def.len;
 | |
|                   if slen=0 then
 | |
|                     slen:=255;
 | |
|                   charst:=def_stab_number(cchartype.def);
 | |
|                   bytest:=def_stab_number(u8inttype.def);
 | |
|                   result:=def_stabstr_evaluate(def,'s$1length:$2,0,8;st:ar$2;1;$3;$4,8,$5;;',
 | |
|                               [tostr(slen+1),bytest,tostr(slen),charst,tostr(slen*8)]);
 | |
|                 end;
 | |
|               st_longstring:
 | |
|                 begin
 | |
|                   charst:=def_stab_number(cchartype.def);
 | |
|                   bytest:=def_stab_number(u8inttype.def);
 | |
|                   longst:=def_stab_number(u32inttype.def);
 | |
|                   result:=def_stabstr_evaluate(def,'s$1length:$2,0,32;dummy:$6,32,8;st:ar$2;1;$3;$4,40,$5;;',
 | |
|                               [tostr(def.len+5),longst,tostr(def.len),charst,tostr(def.len*8),bytest]);
 | |
|                end;
 | |
|              st_ansistring:
 | |
|                begin
 | |
|                  { looks like a pchar }
 | |
|                  charst:=def_stab_number(cchartype.def);
 | |
|                  result:=strpnew('*'+charst);
 | |
|                end;
 | |
|              st_widestring:
 | |
|                begin
 | |
|                  { looks like a pwidechar }
 | |
|                  charst:=def_stab_number(cwidechartype.def);
 | |
|                  result:=strpnew('*'+charst);
 | |
|                end;
 | |
|             end;
 | |
|           end;
 | |
| 
 | |
|         function enumdef_stabstr(def:tenumdef):pchar;
 | |
|           var
 | |
|             st : Pchar;
 | |
|             p : Tenumsym;
 | |
|             s : string;
 | |
|             memsize,
 | |
|             stl : aint;
 | |
|           begin
 | |
|             memsize:=memsizeinc;
 | |
|             getmem(st,memsize);
 | |
|             { we can specify the size with @s<size>; prefix PM }
 | |
|             if def.size <> std_param_align then
 | |
|               strpcopy(st,'@s'+tostr(def.size*8)+';e')
 | |
|             else
 | |
|               strpcopy(st,'e');
 | |
|             p := tenumsym(def.firstenum);
 | |
|             stl:=strlen(st);
 | |
|             while assigned(p) do
 | |
|               begin
 | |
|                 s :=p.name+':'+tostr(p.value)+',';
 | |
|                 { place for the ending ';' also }
 | |
|                 if (stl+length(s)+1>=memsize) then
 | |
|                   begin
 | |
|                     inc(memsize,memsizeinc);
 | |
|                     reallocmem(st,memsize);
 | |
|                   end;
 | |
|                 strpcopy(st+stl,s);
 | |
|                 inc(stl,length(s));
 | |
|                 p:=p.nextenum;
 | |
|               end;
 | |
|             st[stl]:=';';
 | |
|             st[stl+1]:=#0;
 | |
|             reallocmem(st,stl+2);
 | |
|             result:=st;
 | |
|           end;
 | |
| 
 | |
|         function orddef_stabstr(def:torddef):pchar;
 | |
|           begin
 | |
|             if cs_gdb_valgrind in aktglobalswitches then
 | |
|               begin
 | |
|                 case def.typ of
 | |
|                   uvoid :
 | |
|                     result:=strpnew(def_stab_number(def));
 | |
|                   bool8bit,
 | |
|                   bool16bit,
 | |
|                   bool32bit :
 | |
|                     result:=def_stabstr_evaluate(def,'r${numberstring};0;255;',[]);
 | |
|                   u32bit,
 | |
|                   s64bit,
 | |
|                   u64bit :
 | |
|                     result:=def_stabstr_evaluate(def,'r${numberstring};0;-1;',[]);
 | |
|                   else
 | |
|                     result:=def_stabstr_evaluate(def,'r${numberstring};$1;$2;',[tostr(longint(def.low)),tostr(longint(def.high))]);
 | |
|                 end;
 | |
|               end
 | |
|             else
 | |
|               begin
 | |
|                 case def.typ of
 | |
|                   uvoid :
 | |
|                     result:=strpnew(def_stab_number(def));
 | |
|                   uchar :
 | |
|                     result:=strpnew('-20;');
 | |
|                   uwidechar :
 | |
|                     result:=strpnew('-30;');
 | |
|                   bool8bit :
 | |
|                     result:=strpnew('-21;');
 | |
|                   bool16bit :
 | |
|                     result:=strpnew('-22;');
 | |
|                   bool32bit :
 | |
|                     result:=strpnew('-23;');
 | |
|                   u64bit :
 | |
|                     result:=strpnew('-32;');
 | |
|                   s64bit :
 | |
|                     result:=strpnew('-31;');
 | |
|                   {u32bit : result:=def_stab_number(s32inttype.def)+';0;-1;'); }
 | |
|                   else
 | |
|                     result:=def_stabstr_evaluate(def,'r${numberstring};$1;$2;',[tostr(longint(def.low)),tostr(longint(def.high))]);
 | |
|                 end;
 | |
|              end;
 | |
|           end;
 | |
| 
 | |
|         function floatdef_stabstr(def:tfloatdef):Pchar;
 | |
|           begin
 | |
|             case def.typ of
 | |
|               s32real,
 | |
|               s64real,
 | |
|               s80real:
 | |
|                 result:=def_stabstr_evaluate(def,'r$1;${savesize};0;',[def_stab_number(s32inttype.def)]);
 | |
|               s64currency,
 | |
|               s64comp:
 | |
|                 result:=def_stabstr_evaluate(def,'r$1;-${savesize};0;',[def_stab_number(s32inttype.def)]);
 | |
|               else
 | |
|                 internalerror(200509261);
 | |
|             end;
 | |
|           end;
 | |
| 
 | |
|         function filedef_stabstr(def:tfiledef):pchar;
 | |
|           begin
 | |
| {$ifdef cpu64bit}
 | |
|             result:=def_stabstr_evaluate(def,'s${savesize}HANDLE:$1,0,32;MODE:$1,32,32;RECSIZE:$2,64,64;'+
 | |
|                                      '_PRIVATE:ar$1;1;64;$3,128,256;USERDATA:ar$1;1;16;$3,384,128;'+
 | |
|                                      'NAME:ar$1;0;255;$4,512,2048;;',[def_stab_number(s32inttype.def),
 | |
|                                      def_stab_number(s64inttype.def),
 | |
|                                      def_stab_number(u8inttype.def),
 | |
|                                      def_stab_number(cchartype.def)]);
 | |
| {$else cpu64bit}
 | |
|             result:=def_stabstr_evaluate(def,'s${savesize}HANDLE:$1,0,32;MODE:$1,32,32;RECSIZE:$1,64,32;'+
 | |
|                                      '_PRIVATE:ar$1;1;32;$3,96,256;USERDATA:ar$1;1;16;$2,352,128;'+
 | |
|                                      'NAME:ar$1;0;255;$3,480,2048;;',[def_stab_number(s32inttype.def),
 | |
|                                      def_stab_number(u8inttype.def),
 | |
|                                      def_stab_number(cchartype.def)]);
 | |
| {$endif cpu64bit}
 | |
|           end;
 | |
| 
 | |
|         function procdef_stabstr(def:tprocdef):pchar;
 | |
|           Var
 | |
|             RType : Char;
 | |
|             Obj,Info : String;
 | |
|             stabsstr : string;
 | |
|             p : pchar;
 | |
|           begin
 | |
|             obj := def.procsym.name;
 | |
|             info := '';
 | |
|             if (po_global in def.procoptions) then
 | |
|               RType := 'F'
 | |
|             else
 | |
|               RType := 'f';
 | |
|             if assigned(def.owner) then
 | |
|              begin
 | |
|                if (def.owner.symtabletype = objectsymtable) then
 | |
|                  obj := def.owner.name^+'__'+def.procsym.name;
 | |
|                if not(cs_gdb_valgrind in aktglobalswitches) and
 | |
|                   (def.owner.symtabletype=localsymtable) and
 | |
|                   assigned(def.owner.defowner) and
 | |
|                   assigned(tprocdef(def.owner.defowner).procsym) then
 | |
|                  info := ','+def.procsym.name+','+tprocdef(def.owner.defowner).procsym.name;
 | |
|              end;
 | |
|             stabsstr:=def.mangledname;
 | |
|             getmem(p,length(stabsstr)+255);
 | |
|             strpcopy(p,'"'+obj+':'+RType
 | |
|                   +def_stab_number(def.rettype.def)+info+'",'+tostr(n_function)
 | |
|                   +',0,'+
 | |
|                   tostr(def.fileinfo.line)
 | |
|                   +',');
 | |
|             strpcopy(strend(p),stabsstr);
 | |
|             result:=strnew(p);
 | |
|             freemem(p,length(stabsstr)+255);
 | |
|           end;
 | |
| 
 | |
|         function recorddef_stabstr(def:trecorddef):pchar;
 | |
|           var
 | |
|             state : Trecord_stabgen_state;
 | |
|           begin
 | |
|             getmem(state.stabstring,memsizeinc);
 | |
|             state.staballoc:=memsizeinc;
 | |
|             strpcopy(state.stabstring,'s'+tostr(def.size));
 | |
|             state.recoffset:=0;
 | |
|             state.stabsize:=strlen(state.stabstring);
 | |
|             def.symtable.foreach(@field_add_stabstr,@state);
 | |
|             state.stabstring[state.stabsize]:=';';
 | |
|             state.stabstring[state.stabsize+1]:=#0;
 | |
|             reallocmem(state.stabstring,state.stabsize+2);
 | |
|             result:=state.stabstring;
 | |
|           end;
 | |
| 
 | |
|         function objectdef_stabstr(def:tobjectdef):pchar;
 | |
|           var
 | |
|             anc    : tobjectdef;
 | |
|             state  :Trecord_stabgen_state;
 | |
|             ts     : string;
 | |
|           begin
 | |
|             { Write the invisible pointer for the class? }
 | |
|             if (def.objecttype=odt_class) and
 | |
|                (not def.writing_class_record_stab) then
 | |
|               begin
 | |
|                 result:=strpnew('*'+def_stab_classnumber(def));
 | |
|                 exit;
 | |
|               end;
 | |
| 
 | |
|             state.staballoc:=memsizeinc;
 | |
|             getmem(state.stabstring,state.staballoc);
 | |
|             strpcopy(state.stabstring,'s'+tostr(tobjectsymtable(def.symtable).datasize));
 | |
|             if assigned(def.childof) then
 | |
|               begin
 | |
|                 {only one ancestor not virtual, public, at base offset 0 }
 | |
|                 {       !1           ,    0       2         0    ,       }
 | |
|                 strpcopy(strend(state.stabstring),'!1,020,'+def_stab_classnumber(def.childof)+';');
 | |
|               end;
 | |
|             {virtual table to implement yet}
 | |
|             state.recoffset:=0;
 | |
|             state.stabsize:=strlen(state.stabstring);
 | |
|             def.symtable.foreach(@field_add_stabstr,@state);
 | |
|             if (oo_has_vmt in def.objectoptions) then
 | |
|               if not assigned(def.childof) or not(oo_has_vmt in def.childof.objectoptions) then
 | |
|                  begin
 | |
|                     ts:='$vf'+def_stab_classnumber(def)+':'+def_stab_number(vmtarraytype.def)+','+tostr(def.vmt_offset*8)+';';
 | |
|                     strpcopy(state.stabstring+state.stabsize,ts);
 | |
|                     inc(state.stabsize,length(ts));
 | |
|                  end;
 | |
|             def.symtable.foreach(@method_add_stabstr,@state);
 | |
|             if (oo_has_vmt in def.objectoptions) then
 | |
|               begin
 | |
|                  anc := def;
 | |
|                  while assigned(anc.childof) and (oo_has_vmt in anc.childof.objectoptions) do
 | |
|                    anc := anc.childof;
 | |
|                  { just in case anc = self }
 | |
|                  ts:=';~%'+def_stab_classnumber(anc)+';';
 | |
|               end
 | |
|             else
 | |
|               ts:=';';
 | |
|             strpcopy(state.stabstring+state.stabsize,ts);
 | |
|             inc(state.stabsize,length(ts));
 | |
|             reallocmem(state.stabstring,state.stabsize+1);
 | |
|             result:=state.stabstring;
 | |
|           end;
 | |
| 
 | |
|       begin
 | |
|         result:=nil;
 | |
|         case def.deftype of
 | |
|           stringdef :
 | |
|             result:=stringdef_stabstr(tstringdef(def));
 | |
|           enumdef :
 | |
|             result:=enumdef_stabstr(tenumdef(def));
 | |
|           orddef :
 | |
|             result:=orddef_stabstr(torddef(def));
 | |
|           floatdef :
 | |
|             result:=floatdef_stabstr(tfloatdef(def));
 | |
|           filedef :
 | |
|             result:=filedef_stabstr(tfiledef(def));
 | |
|           recorddef :
 | |
|             result:=recorddef_stabstr(trecorddef(def));
 | |
|           variantdef :
 | |
|             result:=def_stabstr_evaluate(def,'formal${numberstring};',[]);
 | |
|           pointerdef :
 | |
|             result:=strpnew('*'+def_stab_number(tpointerdef(def).pointertype.def));
 | |
|           classrefdef :
 | |
|             result:=strpnew(def_stab_number(pvmttype.def));
 | |
|           setdef :
 | |
|             result:=def_stabstr_evaluate(def,'@s$1;S$2',[tostr(def.size*8),def_stab_number(tsetdef(def).elementtype.def)]);
 | |
|           formaldef :
 | |
|             result:=def_stabstr_evaluate(def,'formal${numberstring};',[]);
 | |
|           arraydef :
 | |
|             result:=def_stabstr_evaluate(def,'ar$1;$2;$3;$4',[def_stab_number(tarraydef(def).rangetype.def),
 | |
|                tostr(tarraydef(def).lowrange),tostr(tarraydef(def).highrange),def_stab_number(tarraydef(def).elementtype.def)]);
 | |
|           procdef :
 | |
|             result:=procdef_stabstr(tprocdef(def));
 | |
|           procvardef :
 | |
|             result:=strpnew('*f'+def_stab_number(tprocvardef(def).rettype.def));
 | |
|           objectdef :
 | |
|             begin
 | |
|               if tobjectdef(def).writing_class_record_stab then
 | |
|                 result:=objectdef_stabstr(tobjectdef(def))
 | |
|               else
 | |
|                 result:=strpnew('*'+def_stab_classnumber(tobjectdef(def)));
 | |
|             end;
 | |
|         end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure TDebugInfoStabs.write_def_stabstr(list:taasmoutput;def:tdef);
 | |
|       var
 | |
|         stabchar : string[2];
 | |
|         ss,st,su : pchar;
 | |
|       begin
 | |
|         { procdefs require a different stabs style without type prefix }
 | |
|         if def.deftype=procdef then
 | |
|           begin
 | |
|             st:=def_stabstr(def);
 | |
|             { add to list }
 | |
|             list.concat(Tai_stab.create(stab_stabs,st));
 | |
|           end
 | |
|         else
 | |
|           begin
 | |
|             { type prefix }
 | |
|             if def.deftype in tagtypes then
 | |
|               stabchar := 'Tt'
 | |
|             else
 | |
|               stabchar := 't';
 | |
|             { Here we maybe generate a type, so we have to use numberstring }
 | |
|             if is_class(def) and
 | |
|                tobjectdef(def).writing_class_record_stab then
 | |
|               st:=def_stabstr_evaluate(def,'"${sym_name}:$1$2=',[stabchar,def_stab_classnumber(tobjectdef(def))])
 | |
|             else
 | |
|               st:=def_stabstr_evaluate(def,'"${sym_name}:$1$2=',[stabchar,def_stab_number(def)]);
 | |
|             ss:=def_stabstr(def);
 | |
|             reallocmem(st,strlen(ss)+512);
 | |
|             { line info is set to 0 for all defs, because the def can be in an other
 | |
|               unit and then the linenumber is invalid in the current sourcefile }
 | |
|             su:=def_stabstr_evaluate(def,'",${N_LSYM},0,0,0',[]);
 | |
|             strcopy(strecopy(strend(st),ss),su);
 | |
|             reallocmem(st,strlen(st)+1);
 | |
|             strdispose(ss);
 | |
|             strdispose(su);
 | |
|             { add to list }
 | |
|             list.concat(Tai_stab.create(stab_stabs,st));
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure TDebugInfoStabs.field_write_defs(p:Tnamedindexitem;arg:pointer);
 | |
|       begin
 | |
|         if (Tsym(p).typ=fieldvarsym) and
 | |
|            not(sp_static in Tsym(p).symoptions) then
 | |
|           insertdef(taasmoutput(arg),tfieldvarsym(p).vartype.def);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure TDebugInfoStabs.method_write_defs(p :tnamedindexitem;arg:pointer);
 | |
|       var
 | |
|         pd : tprocdef;
 | |
|       begin
 | |
|         if tsym(p).typ = procsym then
 | |
|           begin
 | |
|             pd:=tprocsym(p).first_procdef;
 | |
|             insertdef(taasmoutput(arg),pd.rettype.def);
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure TDebugInfoStabs.insertdef(list:taasmoutput;def:tdef);
 | |
|       var
 | |
|         anc : tobjectdef;
 | |
|         oldtypesym : tsym;
 | |
| //        nb  : string[12];
 | |
|       begin
 | |
|         if (def.stab_state in [stab_state_writing,stab_state_written]) then
 | |
|           exit;
 | |
|         { to avoid infinite loops }
 | |
|         def.stab_state := stab_state_writing;
 | |
|         { write dependencies first }
 | |
|         case def.deftype of
 | |
|           stringdef :
 | |
|             begin
 | |
|               if tstringdef(def).string_typ=st_widestring then
 | |
|                 insertdef(list,cwidechartype.def)
 | |
|               else
 | |
|                 begin
 | |
|                   insertdef(list,cchartype.def);
 | |
|                   insertdef(list,u8inttype.def);
 | |
|                 end;
 | |
|             end;
 | |
|           floatdef :
 | |
|             insertdef(list,s32inttype.def);
 | |
|           filedef :
 | |
|             begin
 | |
|               insertdef(list,s32inttype.def);
 | |
| {$ifdef cpu64bit}
 | |
|               insertdef(list,s64inttype.def);
 | |
| {$endif cpu64bit}
 | |
|               insertdef(list,u8inttype.def);
 | |
|               insertdef(list,cchartype.def);
 | |
|             end;
 | |
|           classrefdef :
 | |
|             insertdef(list,pvmttype.def);
 | |
|           pointerdef :
 | |
|             insertdef(list,tpointerdef(def).pointertype.def);
 | |
|           setdef :
 | |
|             insertdef(list,tsetdef(def).elementtype.def);
 | |
|           procvardef,
 | |
|           procdef :
 | |
|             insertdef(list,tprocdef(def).rettype.def);
 | |
|           arraydef :
 | |
|             begin
 | |
|               insertdef(list,tarraydef(def).rangetype.def);
 | |
|               insertdef(list,tarraydef(def).elementtype.def);
 | |
|             end;
 | |
|           recorddef :
 | |
|             trecorddef(def).symtable.foreach(@field_write_defs,list);
 | |
|           objectdef :
 | |
|             begin
 | |
|               insertdef(list,vmtarraytype.def);
 | |
|               { first the parents }
 | |
|               anc:=tobjectdef(def);
 | |
|               while assigned(anc.childof) do
 | |
|                 begin
 | |
|                   anc:=anc.childof;
 | |
|                   insertdef(list,anc);
 | |
|                 end;
 | |
|               tobjectdef(def).symtable.foreach(@field_write_defs,list);
 | |
|               tobjectdef(def).symtable.foreach(@method_write_defs,list);
 | |
|             end;
 | |
|         end;
 | |
| (*
 | |
|         { Handle pointerdefs to records and objects to avoid recursion }
 | |
|         if (def.deftype=pointerdef) and
 | |
|            (tpointerdef(def).pointertype.def.deftype in [recorddef,objectdef]) then
 | |
|           begin
 | |
|             def.stab_state:=stab_state_used;
 | |
|             write_def_stabstr(list,def);
 | |
|             {to avoid infinite recursion in record with next-like fields }
 | |
|             if tdef(tpointerdef(def).pointertype.def).stab_state=stab_state_writing then
 | |
|               begin
 | |
|                 if assigned(tpointerdef(def).pointertype.def.typesym) then
 | |
|                   begin
 | |
|                     if is_class(tpointerdef(def).pointertype.def) then
 | |
|                       nb:=def_stab_classnumber(tobjectdef(tpointerdef(def).pointertype.def))
 | |
|                     else
 | |
|                       nb:=def_stab_number(tpointerdef(def).pointertype.def);
 | |
|                     list.concat(Tai_stab.create(stab_stabs,def_stabstr_evaluate(
 | |
|                             def,'"${sym_name}:t${numberstring}=*$1=xs$2:",${N_LSYM},0,0,0',
 | |
|                             [nb,tpointerdef(def).pointertype.def.typesym.name])));
 | |
|                   end;
 | |
|                 def.stab_state:=stab_state_written;
 | |
|               end
 | |
|           end
 | |
|         else
 | |
| *)
 | |
|         case def.deftype of
 | |
|           objectdef :
 | |
|             begin
 | |
|               { classes require special code to write the record and the invisible pointer }
 | |
|               if is_class(def) then
 | |
|                 begin
 | |
|                   { Write the record class itself }
 | |
|                   tobjectdef(def).writing_class_record_stab:=true;
 | |
|                   write_def_stabstr(list,def);
 | |
|                   tobjectdef(def).writing_class_record_stab:=false;
 | |
|                   { Write the invisible pointer class }
 | |
|                   oldtypesym:=def.typesym;
 | |
|                   def.typesym:=nil;
 | |
|                   write_def_stabstr(list,def);
 | |
|                   def.typesym:=oldtypesym;
 | |
|                 end
 | |
|               else
 | |
|                 write_def_stabstr(list,def);
 | |
|               { VMT symbol }
 | |
|               if (oo_has_vmt in tobjectdef(def).objectoptions) and
 | |
|                  assigned(def.owner) and
 | |
|                  assigned(def.owner.name) then
 | |
|                 list.concat(Tai_stab.create(stab_stabs,strpnew('"vmt_'+def.owner.name^+tobjectdef(def).name+':S'+
 | |
|                        def_stab_number(vmttype.def)+'",'+tostr(N_STSYM)+',0,0,'+tobjectdef(def).vmt_mangledname)));
 | |
|             end;
 | |
|           procdef :
 | |
|             begin
 | |
|               { procdefs are handled separatly }
 | |
|             end;
 | |
|           else
 | |
|             write_def_stabstr(list,def);
 | |
|         end;
 | |
| 
 | |
|         def.stab_state := stab_state_written;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure TDebugInfoStabs.write_symtable_defs(list:taasmoutput;st:tsymtable);
 | |
| 
 | |
|        procedure dowritestabs(list:taasmoutput;st:tsymtable);
 | |
|          var
 | |
|            p : tdef;
 | |
|          begin
 | |
|            p:=tdef(st.defindex.first);
 | |
|            while assigned(p) do
 | |
|              begin
 | |
|                if (p.stab_state=stab_state_used) then
 | |
|                  insertdef(list,p);
 | |
|                p:=tdef(p.indexnext);
 | |
|              end;
 | |
|          end;
 | |
| 
 | |
|       var
 | |
|         old_writing_def_stabs : boolean;
 | |
|       begin
 | |
|         case st.symtabletype of
 | |
|           staticsymtable :
 | |
|             list.concat(tai_comment.Create(strpnew('Defs - Begin Staticsymtable')));
 | |
|           globalsymtable :
 | |
|             list.concat(tai_comment.Create(strpnew('Defs - Begin unit '+st.name^+' has index '+tostr(st.moduleid))));
 | |
|         end;
 | |
|         old_writing_def_stabs:=writing_def_stabs;
 | |
|         writing_def_stabs:=true;
 | |
|         dowritestabs(list,st);
 | |
|         writing_def_stabs:=old_writing_def_stabs;
 | |
|         case st.symtabletype of
 | |
|           staticsymtable :
 | |
|             list.concat(tai_comment.Create(strpnew('Defs - End Staticsymtable')));
 | |
|           globalsymtable :
 | |
|             list.concat(tai_comment.Create(strpnew('Defs - End unit '+st.name^+' has index '+tostr(st.moduleid))));
 | |
|         end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure TDebugInfoStabs.write_procdef(list:taasmoutput;pd:tprocdef);
 | |
|       var
 | |
|         templist : taasmoutput;
 | |
|         stabsendlabel : tasmlabel;
 | |
|         mangled_length : longint;
 | |
|         p : pchar;
 | |
|         hs : string;
 | |
|       begin
 | |
|         if assigned(pd.procstarttai) then
 | |
|           begin
 | |
|             templist:=taasmoutput.create;
 | |
|             { para types }
 | |
|             write_def_stabstr(templist,pd);
 | |
|             if assigned(pd.parast) then
 | |
|               write_symtable_syms(templist,pd.parast);
 | |
|             { local type defs and vars should not be written
 | |
|               inside the main proc stab }
 | |
|             if assigned(pd.localst) and
 | |
|                (pd.localst.symtabletype=localsymtable) then
 | |
|               write_symtable_syms(templist,pd.localst);
 | |
|             asmlist[al_procedures].insertlistbefore(pd.procstarttai,templist);
 | |
|             { end of procedure }
 | |
|             objectlibrary.getlabel(stabsendlabel,alt_dbgtype);
 | |
|             templist.concat(tai_label.create(stabsendlabel));
 | |
|             if assigned(pd.funcretsym) and
 | |
|                (tabstractnormalvarsym(pd.funcretsym).refs>0) then
 | |
|               begin
 | |
|                 if tabstractnormalvarsym(pd.funcretsym).localloc.loc=LOC_REFERENCE then
 | |
|                   begin
 | |
|     {$warning Need to add gdb support for ret in param register calling}
 | |
|                     if paramanager.ret_in_param(pd.rettype.def,pd.proccalloption) then
 | |
|                       hs:='X*'
 | |
|                     else
 | |
|                       hs:='X';
 | |
|                     templist.concat(Tai_stab.create(stab_stabs,strpnew(
 | |
|                        '"'+pd.procsym.name+':'+hs+def_stab_number(pd.rettype.def)+'",'+
 | |
|                        tostr(N_tsym)+',0,0,'+tostr(tabstractnormalvarsym(pd.funcretsym).localloc.reference.offset))));
 | |
|                     if (m_result in aktmodeswitches) then
 | |
|                       templist.concat(Tai_stab.create(stab_stabs,strpnew(
 | |
|                          '"RESULT:'+hs+def_stab_number(pd.rettype.def)+'",'+
 | |
|                          tostr(N_tsym)+',0,0,'+tostr(tabstractnormalvarsym(pd.funcretsym).localloc.reference.offset))));
 | |
|                   end;
 | |
|               end;
 | |
|             mangled_length:=length(pd.mangledname);
 | |
|             getmem(p,2*mangled_length+50);
 | |
|             strpcopy(p,'192,0,0,');
 | |
|             {$IFDEF POWERPC64}strpcopy(strend(p), '.');{$ENDIF POWERPC64}
 | |
|             strpcopy(strend(p),pd.mangledname);
 | |
|             if (target_info.use_function_relative_addresses) then
 | |
|               begin
 | |
|                 strpcopy(strend(p),'-');
 | |
|                 {$IFDEF POWERPC64}strpcopy(strend(p), '.');{$ENDIF POWERPC64}
 | |
|                 strpcopy(strend(p),pd.mangledname);
 | |
|               end;
 | |
|             templist.concat(Tai_stab.Create(stab_stabn,strnew(p)));
 | |
|             strpcopy(p,'224,0,0,'+stabsendlabel.name);
 | |
|             if (target_info.use_function_relative_addresses) then
 | |
|               begin
 | |
|                 strpcopy(strend(p),'-');
 | |
|                 {$IFDEF POWERPC64}strpcopy(strend(p), '.');{$ENDIF POWERPC64}
 | |
|                 strpcopy(strend(p),pd.mangledname);
 | |
|               end;
 | |
|             templist.concat(Tai_stab.Create(stab_stabn,strnew(p)));
 | |
|             freemem(p,2*mangled_length+50);
 | |
|             asmlist[al_procedures].insertlistbefore(pd.procendtai,templist);
 | |
|             templist.free;
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
| {****************************************************************************
 | |
|                                TSym support
 | |
| ****************************************************************************}
 | |
| 
 | |
|     function TDebugInfoStabs.sym_var_value(const s:string;arg:pointer):string;
 | |
|       var
 | |
|         sym : tsym;
 | |
|       begin
 | |
|         sym:=tsym(arg);
 | |
|         result:='';
 | |
|         if s='name' then
 | |
|           result:=sym.name
 | |
|         else if s='mangledname' then
 | |
|           result:=sym.mangledname
 | |
|         else if s='ownername' then
 | |
|           result:=sym.owner.name^
 | |
|         else if s='line' then
 | |
|           result:=tostr(sym.fileinfo.line)
 | |
|         else if s='N_LSYM' then
 | |
|           result:=tostr(N_LSYM)
 | |
|         else if s='N_LCSYM' then
 | |
|           result:=tostr(N_LCSYM)
 | |
|         else if s='N_RSYM' then
 | |
|           result:=tostr(N_RSYM)
 | |
|         else if s='N_TSYM' then
 | |
|           result:=tostr(N_TSYM)
 | |
|         else if s='N_STSYM' then
 | |
|           result:=tostr(N_STSYM)
 | |
|         else if s='N_FUNCTION' then
 | |
|           result:=tostr(N_FUNCTION)
 | |
|         else
 | |
|           internalerror(200401152);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function TDebugInfoStabs.sym_stabstr_evaluate(sym:tsym;const s:string;const vars:array of string):Pchar;
 | |
|       begin
 | |
|         result:=string_evaluate(s,@sym_var_value,sym,vars);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure TDebugInfoStabs.insertsym(list:taasmoutput;sym:tsym);
 | |
| 
 | |
|         function fieldvarsym_stabstr(sym:tfieldvarsym):Pchar;
 | |
|           begin
 | |
|             result:=nil;
 | |
|             if (sym.owner.symtabletype=objectsymtable) and
 | |
|                (sp_static in sym.symoptions) then
 | |
|               result:=sym_stabstr_evaluate(sym,'"${ownername}__${name}:S$1",${N_LCSYM},0,${line},${mangledname}',
 | |
|                   [def_stab_number(sym.vartype.def)]);
 | |
|           end;
 | |
| 
 | |
|         function globalvarsym_stabstr(sym:tglobalvarsym):Pchar;
 | |
|           var
 | |
|             st : string;
 | |
|             threadvaroffset : string;
 | |
|             regidx : Tregisterindex;
 | |
|           begin
 | |
|             result:=nil;
 | |
|             { external symbols can't be resolved at link time, so we
 | |
|               can't generate stabs for them }
 | |
|             if vo_is_external in sym.varoptions then
 | |
|               exit;
 | |
|             st:=def_stab_number(sym.vartype.def);
 | |
|             case sym.localloc.loc of
 | |
|               LOC_REGISTER,
 | |
|               LOC_CREGISTER,
 | |
|               LOC_MMREGISTER,
 | |
|               LOC_CMMREGISTER,
 | |
|               LOC_FPUREGISTER,
 | |
|               LOC_CFPUREGISTER :
 | |
|                 begin
 | |
|                   regidx:=findreg_by_number(sym.localloc.register);
 | |
|                   { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "eip", "ps", "cs", "ss", "ds", "es", "fs", "gs", }
 | |
|                   { this is the register order for GDB}
 | |
|                   if regidx<>0 then
 | |
|                     result:=sym_stabstr_evaluate(sym,'"${name}:r$1",${N_RSYM},0,${line},$2',[st,tostr(regstabs_table[regidx])]);
 | |
|                 end;
 | |
|               else
 | |
|                 begin
 | |
|                   if (vo_is_thread_var in sym.varoptions) then
 | |
|                     threadvaroffset:='+'+tostr(sizeof(aint))
 | |
|                   else
 | |
|                     threadvaroffset:='';
 | |
|                   { Here we used S instead of
 | |
|                     because with G GDB doesn't look at the address field
 | |
|                     but searches the same name or with a leading underscore
 | |
|                     but these names don't exist in pascal !}
 | |
|                   st:='S'+st;
 | |
|                   result:=sym_stabstr_evaluate(sym,'"${name}:$1",${N_LCSYM},0,${line},${mangledname}$2',[st,threadvaroffset]);
 | |
|                 end;
 | |
|             end;
 | |
|           end;
 | |
| 
 | |
|         function localvarsym_stabstr(sym:tlocalvarsym):Pchar;
 | |
|           var
 | |
|             st : string;
 | |
|             regidx : Tregisterindex;
 | |
|           begin
 | |
|             result:=nil;
 | |
|             { There is no space allocated for not referenced locals }
 | |
|             if (sym.owner.symtabletype=localsymtable) and (sym.refs=0) then
 | |
|               exit;
 | |
| 
 | |
|             st:=def_stab_number(sym.vartype.def);
 | |
|             case sym.localloc.loc of
 | |
|               LOC_REGISTER,
 | |
|               LOC_CREGISTER,
 | |
|               LOC_MMREGISTER,
 | |
|               LOC_CMMREGISTER,
 | |
|               LOC_FPUREGISTER,
 | |
|               LOC_CFPUREGISTER :
 | |
|                 begin
 | |
|                   regidx:=findreg_by_number(sym.localloc.register);
 | |
|                   { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "eip", "ps", "cs", "ss", "ds", "es", "fs", "gs", }
 | |
|                   { this is the register order for GDB}
 | |
|                   if regidx<>0 then
 | |
|                     result:=sym_stabstr_evaluate(sym,'"${name}:r$1",${N_RSYM},0,${line},$2',[st,tostr(regstabs_table[regidx])]);
 | |
|                 end;
 | |
|               LOC_REFERENCE :
 | |
|                 { offset to ebp => will not work if the framepointer is esp
 | |
|                   so some optimizing will make things harder to debug }
 | |
|                 result:=sym_stabstr_evaluate(sym,'"${name}:$1",${N_TSYM},0,${line},$2',[st,tostr(sym.localloc.reference.offset)])
 | |
|               else
 | |
|                 internalerror(2003091814);
 | |
|             end;
 | |
|           end;
 | |
| 
 | |
|         function paravarsym_stabstr(sym:tparavarsym):Pchar;
 | |
|           var
 | |
|             st : string;
 | |
|             regidx : Tregisterindex;
 | |
|             c : char;
 | |
|           begin
 | |
|             result:=nil;
 | |
|             { set loc to LOC_REFERENCE to get somewhat usable debugging info for -Or }
 | |
|             { while stabs aren't adapted for regvars yet                             }
 | |
|             if (vo_is_self in sym.varoptions) then
 | |
|               begin
 | |
|                 case sym.localloc.loc of
 | |
|                   LOC_REGISTER,
 | |
|                   LOC_CREGISTER:
 | |
|                     regidx:=findreg_by_number(sym.localloc.register);
 | |
|                   LOC_REFERENCE: ;
 | |
|                   else
 | |
|                     internalerror(2003091815);
 | |
|                 end;
 | |
|                 if (po_classmethod in tabstractprocdef(sym.owner.defowner).procoptions) or
 | |
|                    (po_staticmethod in tabstractprocdef(sym.owner.defowner).procoptions) then
 | |
|                   begin
 | |
|                     if (sym.localloc.loc=LOC_REFERENCE) then
 | |
|                       result:=sym_stabstr_evaluate(sym,'"pvmt:p$1",${N_TSYM},0,0,$2',
 | |
|                         [def_stab_number(pvmttype.def),tostr(sym.localloc.reference.offset)]);
 | |
|       (*            else
 | |
|                       result:=sym_stabstr_evaluate(sym,'"pvmt:r$1",${N_RSYM},0,0,$2',
 | |
|                         [def_stab_number(pvmttype.def),tostr(regstabs_table[regidx])]) *)
 | |
|                     end
 | |
|                 else
 | |
|                   begin
 | |
|                     if not(is_class(tprocdef(sym.owner.defowner)._class)) then
 | |
|                       c:='v'
 | |
|                     else
 | |
|                       c:='p';
 | |
|                     if (sym.localloc.loc=LOC_REFERENCE) then
 | |
|                       result:=sym_stabstr_evaluate(sym,'"$$t:$1",${N_TSYM},0,0,$2',
 | |
|                             [c+def_stab_number(tprocdef(sym.owner.defowner)._class),tostr(sym.localloc.reference.offset)]);
 | |
|       (*            else
 | |
|                       result:=sym_stabstr_evaluate(sym,'"$$t:r$1",${N_RSYM},0,0,$2',
 | |
|                             [c+def_stab_number(tprocdef(sym.owner.defowner)._class),tostr(regstabs_table[regidx])]); *)
 | |
|                   end;
 | |
|               end
 | |
|             else
 | |
|               begin
 | |
|                 st:=def_stab_number(sym.vartype.def);
 | |
| 
 | |
|                 if paramanager.push_addr_param(sym.varspez,sym.vartype.def,tprocdef(sym.owner.defowner).proccalloption) and
 | |
|                    not(vo_has_local_copy in sym.varoptions) and
 | |
|                    not is_open_string(sym.vartype.def) then
 | |
|                   st := 'v'+st { should be 'i' but 'i' doesn't work }
 | |
|                 else
 | |
|                   st := 'p'+st;
 | |
|                 case sym.localloc.loc of
 | |
|                   LOC_REGISTER,
 | |
|                   LOC_CREGISTER,
 | |
|                   LOC_MMREGISTER,
 | |
|                   LOC_CMMREGISTER,
 | |
|                   LOC_FPUREGISTER,
 | |
|                   LOC_CFPUREGISTER :
 | |
|                     begin
 | |
|                       regidx:=findreg_by_number(sym.localloc.register);
 | |
|                       { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "eip", "ps", "cs", "ss", "ds", "es", "fs", "gs", }
 | |
|                       { this is the register order for GDB}
 | |
|                       if regidx<>0 then
 | |
|                         result:=sym_stabstr_evaluate(sym,'"${name}:r$1",${N_RSYM},0,${line},$2',[st,tostr(longint(regstabs_table[regidx]))]);
 | |
|                     end;
 | |
|                   LOC_REFERENCE :
 | |
|                     { offset to ebp => will not work if the framepointer is esp
 | |
|                       so some optimizing will make things harder to debug }
 | |
|                     result:=sym_stabstr_evaluate(sym,'"${name}:$1",${N_TSYM},0,${line},$2',[st,tostr(sym.localloc.reference.offset)])
 | |
|                   else
 | |
|                     internalerror(2003091814);
 | |
|                 end;
 | |
|               end;
 | |
|           end;
 | |
| 
 | |
|         function constsym_stabstr(sym:tconstsym):Pchar;
 | |
|           var
 | |
|             st : string;
 | |
|           begin
 | |
|             case sym.consttyp of
 | |
|               conststring:
 | |
|                 begin
 | |
|                   if sym.value.len<200 then
 | |
|                     st:='s'''+backspace_quote(octal_quote(strpas(pchar(sym.value.valueptr)),[#0..#9,#11,#12,#14..#31,'''']),['"','\',#10,#13])+''''
 | |
|                   else
 | |
|                     st:='<constant string too long>';
 | |
|                 end;
 | |
|               constord:
 | |
|                 st:='i'+tostr(sym.value.valueord);
 | |
|               constpointer:
 | |
|                 st:='i'+tostr(sym.value.valueordptr);
 | |
|               constreal:
 | |
|                 begin
 | |
|                   system.str(pbestreal(sym.value.valueptr)^,st);
 | |
|                   st := 'r'+st;
 | |
|                 end;
 | |
|               else
 | |
|                 begin
 | |
|                   { if we don't know just put zero !! }
 | |
|                   st:='i0';
 | |
|                 end;
 | |
|             end;
 | |
|             { valgrind does not support constants }
 | |
|             if cs_gdb_valgrind in aktglobalswitches then
 | |
|               result:=nil
 | |
|             else
 | |
|               result:=sym_stabstr_evaluate(sym,'"${name}:c=$1;",${N_FUNCTION},0,${line},0',[st]);
 | |
|           end;
 | |
| 
 | |
|         function typesym_stabstr(sym:ttypesym) : pchar;
 | |
|           var
 | |
|             stabchar : string[2];
 | |
|           begin
 | |
|             result:=nil;
 | |
|             if not assigned(sym.restype.def) then
 | |
|               internalerror(200509262);
 | |
|             if sym.restype.def.deftype in tagtypes then
 | |
|               stabchar:='Tt'
 | |
|             else
 | |
|               stabchar:='t';
 | |
|             result:=sym_stabstr_evaluate(sym,'"${name}:$1$2",${N_LSYM},0,${line},0',[stabchar,def_stab_number(sym.restype.def)]);
 | |
|           end;
 | |
| 
 | |
|         function procsym_stabstr(sym:tprocsym) : pchar;
 | |
|           var
 | |
|             i : longint;
 | |
|           begin
 | |
|             result:=nil;
 | |
|             for i:=1 to sym.procdef_count do
 | |
|               write_procdef(list,sym.procdef[i]);
 | |
|           end;
 | |
| 
 | |
|       var
 | |
|         stabstr : Pchar;
 | |
|       begin
 | |
|         stabstr:=nil;
 | |
|         case sym.typ of
 | |
|           labelsym :
 | |
|             stabstr:=sym_stabstr_evaluate(sym,'"${name}",${N_LSYM},0,${line},0',[]);
 | |
|           fieldvarsym :
 | |
|             stabstr:=fieldvarsym_stabstr(tfieldvarsym(sym));
 | |
|           globalvarsym :
 | |
|             stabstr:=globalvarsym_stabstr(tglobalvarsym(sym));
 | |
|           localvarsym :
 | |
|             stabstr:=localvarsym_stabstr(tlocalvarsym(sym));
 | |
|           paravarsym :
 | |
|             stabstr:=paravarsym_stabstr(tparavarsym(sym));
 | |
|           typedconstsym :
 | |
|             stabstr:=sym_stabstr_evaluate(sym,'"${name}:S$1",${N_STSYM},0,${line},${mangledname}',
 | |
|                 [def_stab_number(ttypedconstsym(sym).typedconsttype.def)]);
 | |
|           constsym :
 | |
|             stabstr:=constsym_stabstr(tconstsym(sym));
 | |
|           typesym :
 | |
|             stabstr:=typesym_stabstr(ttypesym(sym));
 | |
|           procsym :
 | |
|             stabstr:=procsym_stabstr(tprocsym(sym));
 | |
|         end;
 | |
|         if stabstr<>nil then
 | |
|           list.concat(Tai_stab.create(stab_stabs,stabstr));
 | |
|         { For object types write also the symtable entries }
 | |
|         if (sym.typ=typesym) and (ttypesym(sym).restype.def.deftype=objectdef) then
 | |
|           write_symtable_syms(list,tobjectdef(ttypesym(sym).restype.def).symtable);
 | |
|         sym.isstabwritten:=true;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure TDebugInfoStabs.write_symtable_syms(list:taasmoutput;st:tsymtable);
 | |
|       var
 | |
|         p : tsym;
 | |
|       begin
 | |
|         case st.symtabletype of
 | |
|           staticsymtable :
 | |
|             list.concat(tai_comment.Create(strpnew('Syms - Begin Staticsymtable')));
 | |
|           globalsymtable :
 | |
|             list.concat(tai_comment.Create(strpnew('Syms - Begin unit '+st.name^+' has index '+tostr(st.moduleid))));
 | |
|         end;
 | |
|         p:=tsym(st.symindex.first);
 | |
|         while assigned(p) do
 | |
|           begin
 | |
|             if (not p.isstabwritten) then
 | |
|               insertsym(list,p);
 | |
|             p:=tsym(p.indexnext);
 | |
|           end;
 | |
|         case st.symtabletype of
 | |
|           staticsymtable :
 | |
|             list.concat(tai_comment.Create(strpnew('Syms - End Staticsymtable')));
 | |
|           globalsymtable :
 | |
|             list.concat(tai_comment.Create(strpnew('Syms - End unit '+st.name^+' has index '+tostr(st.moduleid))));
 | |
|         end;
 | |
|       end;
 | |
| 
 | |
| {****************************************************************************
 | |
|                              Proc/Module support
 | |
| ****************************************************************************}
 | |
| 
 | |
|     procedure tdebuginfostabs.inserttypeinfo;
 | |
| 
 | |
|        procedure reset_unit_type_info;
 | |
|        var
 | |
|          hp : tmodule;
 | |
|        begin
 | |
|          hp:=tmodule(loaded_units.first);
 | |
|          while assigned(hp) do
 | |
|            begin
 | |
|              hp.is_stab_written:=false;
 | |
|              hp:=tmodule(hp.next);
 | |
|            end;
 | |
|        end;
 | |
| 
 | |
|        procedure write_used_unit_type_info(list:taasmoutput;hp:tmodule);
 | |
|        var
 | |
|          pu : tused_unit;
 | |
|        begin
 | |
|          pu:=tused_unit(hp.used_units.first);
 | |
|          while assigned(pu) do
 | |
|            begin
 | |
|              if not pu.u.is_stab_written then
 | |
|                begin
 | |
|                  { prevent infinte loop for circular dependencies }
 | |
|                  pu.u.is_stab_written:=true;
 | |
|                  { write type info from used units, use a depth first
 | |
|                    strategy to reduce the recursion in writing all
 | |
|                    dependent stabs }
 | |
|                  write_used_unit_type_info(list,pu.u);
 | |
|                  if assigned(pu.u.globalsymtable) then
 | |
|                    write_symtable_defs(list,pu.u.globalsymtable);
 | |
|                end;
 | |
|              pu:=tused_unit(pu.next);
 | |
|            end;
 | |
|        end;
 | |
| 
 | |
|       var
 | |
|         stabsvarlist,
 | |
|         stabstypelist : taasmoutput;
 | |
|         storefilepos  : tfileposinfo;
 | |
|         st : tsymtable;
 | |
|         i  : longint;
 | |
|       begin
 | |
|         storefilepos:=aktfilepos;
 | |
|         aktfilepos:=current_module.mainfilepos;
 | |
| 
 | |
|         global_stab_number:=0;
 | |
|         defnumberlist:=tlist.create;
 | |
|         stabsvarlist:=taasmoutput.create;
 | |
|         stabstypelist:=taasmoutput.create;
 | |
| 
 | |
|         { include symbol that will be referenced from the main to be sure to
 | |
|           include this debuginfo .o file }
 | |
|         if current_module.is_unit then
 | |
|           begin
 | |
|             current_module.flags:=current_module.flags or uf_has_debuginfo;
 | |
|             st:=current_module.globalsymtable;
 | |
|           end
 | |
|         else
 | |
|           st:=current_module.localsymtable;
 | |
|         new_section(asmlist[al_stabs],sec_data,st.name^,0);
 | |
|         asmlist[al_stabs].concat(tai_symbol.Createname_global(make_mangledname('DEBUGINFO',st,''),AT_DATA,0));
 | |
| 
 | |
|         { first write all global/local symbols. This will flag all required tdefs  }
 | |
|         if assigned(current_module.globalsymtable) then
 | |
|           write_symtable_syms(stabsvarlist,current_module.globalsymtable);
 | |
|         if assigned(current_module.localsymtable) then
 | |
|           write_symtable_syms(stabsvarlist,current_module.localsymtable);
 | |
| 
 | |
|         { reset unit type info flag }
 | |
|         reset_unit_type_info;
 | |
| 
 | |
|         { write used types from the used units }
 | |
|         write_used_unit_type_info(stabstypelist,current_module);
 | |
|         { last write the types from this unit }
 | |
|         if assigned(current_module.globalsymtable) then
 | |
|           write_symtable_defs(stabstypelist,current_module.globalsymtable);
 | |
|         if assigned(current_module.localsymtable) then
 | |
|           write_symtable_defs(stabstypelist,current_module.localsymtable);
 | |
| 
 | |
|         asmlist[al_stabs].concatlist(stabstypelist);
 | |
|         asmlist[al_stabs].concatlist(stabsvarlist);
 | |
| 
 | |
|         { reset stab numbers }
 | |
|         for i:=0 to defnumberlist.count-1 do
 | |
|           begin
 | |
|             if assigned(defnumberlist[i]) then
 | |
|               begin
 | |
|                 tdef(defnumberlist[i]).stab_number:=0;
 | |
|                 tdef(defnumberlist[i]).stab_state:=stab_state_unused;
 | |
|               end;
 | |
|           end;
 | |
| 
 | |
|         defnumberlist.free;
 | |
|         defnumberlist:=nil;
 | |
| 
 | |
|         stabsvarlist.free;
 | |
|         stabstypelist.free;
 | |
|         aktfilepos:=storefilepos;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tdebuginfostabs.insertlineinfo(list:taasmoutput);
 | |
|       var
 | |
|         currfileinfo,
 | |
|         lastfileinfo : tfileposinfo;
 | |
|         currfuncname : pstring;
 | |
|         currsectype  : tasmsectiontype;
 | |
|         hlabel       : tasmlabel;
 | |
|         hp : tai;
 | |
|         infile : tinputfile;
 | |
|       begin
 | |
|         FillChar(lastfileinfo,sizeof(lastfileinfo),0);
 | |
|         currfuncname:=nil;
 | |
|         currsectype:=sec_code;
 | |
|         hp:=Tai(list.first);
 | |
|         while assigned(hp) do
 | |
|           begin
 | |
|             case hp.typ of
 | |
|               ait_section :
 | |
|                 currsectype:=tai_section(hp).sectype;
 | |
|               ait_function_name :
 | |
|                 currfuncname:=tai_function_name(hp).funcname;
 | |
|               ait_force_line :
 | |
|                 lastfileinfo.line:=-1;
 | |
|             end;
 | |
| 
 | |
|             if (currsectype=sec_code) and
 | |
|                (hp.typ=ait_instruction) then
 | |
|               begin
 | |
|                 currfileinfo:=tailineinfo(hp).fileinfo;
 | |
|                 { file changed ? (must be before line info) }
 | |
|                 if (currfileinfo.fileindex<>0) and
 | |
|                    (lastfileinfo.fileindex<>currfileinfo.fileindex) then
 | |
|                   begin
 | |
|                     infile:=current_module.sourcefiles.get_file(currfileinfo.fileindex);
 | |
|                     if assigned(infile) then
 | |
|                       begin
 | |
|                         objectlibrary.getlabel(hlabel,alt_dbgfile);
 | |
|                         { emit stabs }
 | |
|                         if (infile.path^<>'') then
 | |
|                           list.insertbefore(Tai_stab.Create_str(stab_stabs,'"'+BsToSlash(FixPath(infile.path^,false))+'",'+tostr(n_includefile)+
 | |
|                                             ',0,0,'+hlabel.name),hp);
 | |
|                         list.insertbefore(Tai_stab.Create_str(stab_stabs,'"'+FixFileName(infile.name^)+'",'+tostr(n_includefile)+
 | |
|                                           ',0,0,'+hlabel.name),hp);
 | |
|                         list.insertbefore(tai_label.create(hlabel),hp);
 | |
|                         { force new line info }
 | |
|                         lastfileinfo.line:=-1;
 | |
|                       end;
 | |
|                   end;
 | |
| 
 | |
|                 { line changed ? }
 | |
|                 if (lastfileinfo.line<>currfileinfo.line) and (currfileinfo.line<>0) then
 | |
|                   begin
 | |
|                      if assigned(currfuncname) and
 | |
|                         (target_info.use_function_relative_addresses) then
 | |
|                       begin
 | |
|                         objectlibrary.getlabel(hlabel,alt_dbgline);
 | |
|                         list.insertbefore(Tai_stab.Create_str(stab_stabn,tostr(n_textline)+',0,'+tostr(currfileinfo.line)+','+
 | |
|                                           hlabel.name+' - '+{$IFDEF POWERPC64}'.'+{$ENDIF POWERPC64}currfuncname^),hp);
 | |
|                         list.insertbefore(tai_label.create(hlabel),hp);
 | |
|                       end
 | |
|                      else
 | |
|                       list.insertbefore(Tai_stab.Create_str(stab_stabd,tostr(n_textline)+',0,'+tostr(currfileinfo.line)),hp);
 | |
|                   end;
 | |
|                 lastfileinfo:=currfileinfo;
 | |
|               end;
 | |
| 
 | |
|             hp:=tai(hp.next);
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tdebuginfostabs.insertmoduleinfo;
 | |
|       var
 | |
|         hlabel : tasmlabel;
 | |
|         infile : tinputfile;
 | |
|         templist : taasmoutput;
 | |
|       begin
 | |
|         { emit main source n_sourcefile for start of module }
 | |
|         objectlibrary.getlabel(hlabel,alt_dbgfile);
 | |
|         infile:=current_module.sourcefiles.get_file(1);
 | |
|         templist:=taasmoutput.create;
 | |
|         new_section(templist,sec_code,'',0);
 | |
|         if (infile.path^<>'') then
 | |
|           templist.concat(Tai_stab.Create_str(stab_stabs,'"'+BsToSlash(FixPath(infile.path^,false))+'",'+tostr(n_sourcefile)+
 | |
|                       ',0,0,'+hlabel.name));
 | |
|         templist.concat(Tai_stab.Create_str(stab_stabs,'"'+FixFileName(infile.name^)+'",'+tostr(n_sourcefile)+
 | |
|                     ',0,0,'+hlabel.name));
 | |
|         templist.concat(tai_label.create(hlabel));
 | |
|         asmlist[al_stabsstart].insertlist(templist);
 | |
|         templist.free;
 | |
|         { emit empty n_sourcefile for end of module }
 | |
|         objectlibrary.getlabel(hlabel,alt_dbgfile);
 | |
|         templist:=taasmoutput.create;
 | |
|         new_section(templist,sec_code,'',0);
 | |
|         templist.concat(Tai_stab.Create_str(stab_stabs,'"",'+tostr(n_sourcefile)+',0,0,'+hlabel.name));
 | |
|         templist.concat(tai_label.create(hlabel));
 | |
|         asmlist[al_stabsend].insertlist(templist);
 | |
|         templist.free;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tdebuginfostabs.referencesections(list:taasmoutput);
 | |
|       var
 | |
|         hp   : tused_unit;
 | |
|       begin
 | |
|         { Reference all DEBUGINFO sections from the main .text section }
 | |
|         if (target_info.system <> system_powerpc_macos) then
 | |
|           begin
 | |
|             { include reference to all debuginfo sections of used units }
 | |
|             hp:=tused_unit(usedunits.first);
 | |
|             while assigned(hp) do
 | |
|               begin
 | |
|                 If (hp.u.flags and uf_has_debuginfo)=uf_has_debuginfo then
 | |
|                   list.concat(Tai_const.Createname(make_mangledname('DEBUGINFO',hp.u.globalsymtable,''),AT_DATA,0));
 | |
|                 hp:=tused_unit(hp.next);
 | |
|               end;
 | |
|             { include reference to debuginfo for this program }
 | |
|             list.concat(Tai_const.Createname(make_mangledname('DEBUGINFO',current_module.localsymtable,''),AT_DATA,0));
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     const
 | |
|       dbg_stabs_info : tdbginfo =
 | |
|          (
 | |
|            id     : dbg_stabs;
 | |
|            idtxt  : 'STABS';
 | |
|          );
 | |
| 
 | |
| initialization
 | |
|   RegisterDebugInfo(dbg_stabs_info,TDebugInfoStabs);
 | |
| end.
 | 
