summaryrefslogtreecommitdiff
path: root/compiler/dbgstabs.pas
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/dbgstabs.pas')
-rw-r--r--compiler/dbgstabs.pas1589
1 files changed, 1589 insertions, 0 deletions
diff --git a/compiler/dbgstabs.pas b/compiler/dbgstabs.pas
new file mode 100644
index 0000000000..bfdd181c68
--- /dev/null
+++ b/compiler/dbgstabs.pas
@@ -0,0 +1,1589 @@
+{
+ 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.