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