Mercurial > projects > ddbg_continued
view src/codeview/codeview.d @ 5:496dfd8f7342 default tip
added:
-repeat option for "in", "ov"
-run until a line option
-run until a function option
-break on a function start
-n is an alias for ov
author | marton@basel.hu |
---|---|
date | Sun, 17 Apr 2011 11:05:31 +0200 |
parents | a5fb1bc967e6 |
children |
line wrap: on
line source
/* Ddbg - Win32 Debugger for the D programming language * Copyright (c) 2007 Jascha Wetzel * All rights reserved. See LICENSE.TXT for details. */ module codeview.codeview; import std.ctype; import std.string; import std.math; import util; import container; import codeview.coff; import codeview.decl; public import codeview.debuginfo; //================================================================================================= // classes for accessing CodeView data abstract class Symbol { SymbolIndex symbol_index; this(SymbolIndex si) { symbol_index = si; } } class ReturnSymbol : Symbol { CVReturnSymbol* cvdata; ubyte[] registers; this(CVReturnSymbol* cv) { super(SymbolIndex.S_RETURN); cvdata = cv; } } class StringWrap { string str; this(string _str) { str = _str; } int opCmp(Object o) { NamedSymbol ns = cast(NamedSymbol)o; if ( ns !is null ) return -ns.opCmp(this); StringWrap sw = cast(StringWrap)o; if ( sw is null ) return -1; if ( str == sw.str ) return 0; if ( str < sw.str ) return -1; return 1; } } abstract class NamedSymbol : Symbol { string mangled_name, name_type, name_notype; this(SymbolIndex si) { super(si); } int opCmp(Object o) { string str; NamedSymbol ns = cast(NamedSymbol)o; if ( ns is null ) { StringWrap sw = cast(StringWrap)o; if ( sw is null ) return -1; str = sw.str; } else str = ns.name_notype; if ( name_notype == str ) return 0; if ( name_notype < str ) return -1; return 1; } } class StackSymbol : NamedSymbol { CVStackSymbol* cvdata; int size; this(CVStackSymbol* cv) { super(SymbolIndex.S_BPREL32); cvdata=cv; } uint offset() { return cvdata.offset; } uint cvtype() { return cvdata.type; } } class DataSymbol : NamedSymbol { CVDataSymbol* cvdata; uint size; this(SymbolIndex si, CVDataSymbol* cv) { super(si); cvdata=cv; } uint offset() { return cvdata.offset; } uint cvtype() { return cvdata.type; } } abstract class ScopeSymbol : NamedSymbol { ScopeSymbol parent_scope; SymbolSet symbols; uint lfo; this(SymbolIndex si, uint _lfo) { super(si); lfo = _lfo; symbols = new SymbolSet; } } class ProcedureSymbol : ScopeSymbol { CVProcedureSymbol* cvdata; SymbolSet arguments; ReturnSymbol return_sym; this(SymbolIndex si, uint lfo, CVProcedureSymbol* cvd) { super(si,lfo); cvdata = cvd; arguments = new SymbolSet; } } class SymbolSet { ProcedureSymbol[] proc_symbols; StackSymbol[] stack_symbols; DataSymbol[] data_symbols; NamedSymbol[] named_symbols; Symbol[] symbols; void opCatAssign(SymbolSet s) { symbols ~= s.symbols; named_symbols ~= s.named_symbols; data_symbols ~= s.data_symbols; stack_symbols ~= s.stack_symbols; proc_symbols ~= s.proc_symbols; } void add(Symbol s) { NamedSymbol ns = cast(NamedSymbol)s; if ( ns is null ) { symbols ~= s; return; } named_symbols ~= ns; ClassInfo ci = s.classinfo; if ( ci == ProcedureSymbol.classinfo ) proc_symbols ~= cast(ProcedureSymbol)s; else if ( ci == StackSymbol.classinfo ) stack_symbols ~= cast(StackSymbol)s; else if ( ci == DataSymbol.classinfo ) data_symbols ~= cast(DataSymbol)s; } /********************************************************************************************** Find procedure symbol covering the given address. **********************************************************************************************/ ProcedureSymbol findProcedureSymbol(uint address) { foreach ( ps; proc_symbols ) if ( address >= ps.cvdata.offset && address < ps.cvdata.offset+ps.cvdata.proc_length ) return ps; return null; } /********************************************************************************************** Find data symbol covering the given address. **********************************************************************************************/ DataSymbol findDataSymbol(uint address, uint segment) { foreach ( ds; data_symbols ) { if ( segment > 0 && ds.cvdata.segment != segment ) continue; if ( address == ds.cvdata.offset ) return ds; } return null; } /********************************************************************************************** Find data symbol by name. **********************************************************************************************/ DataSymbol findDataSymbol(string name) { foreach ( ds; data_symbols ) { if ( ds.name_notype == name ) return ds; } return null; } /********************************************************************************************** Find matching data symbols by a substring in its name. **********************************************************************************************/ DataSymbol[] findDataSymbolBySubstring(string name) { DataSymbol[] found; foreach ( ds; data_symbols ) { if ( find(ds.name_notype,name)>=0 ) found~=ds; } return found; } /********************************************************************************************** Find nearest data symbol to the given address. **********************************************************************************************/ DataSymbol findNearestDataSymbol(uint address, inout uint min_dist, uint segment) { DataSymbol min_ds; foreach ( ds; data_symbols ) { if ( address < ds.cvdata.offset || ds.cvdata.segment != segment ) continue; uint dist = abs(cast(int)address-cast(int)ds.cvdata.offset); if ( dist < min_dist ) { min_dist = dist; min_ds = ds; } } return min_ds; } } class Module { ModuleHeader* header; SegInfo[] seginfos; string name; ushort pe_section; SymbolSet symbols; SourceModule source_module; CodeView codeview; this(CodeView cv) { symbols = new SymbolSet; codeview = cv; } } class Location { string path; ScopeSymbol scope_sym; DataSymbol data_sym; Module mod; CodeBlock codeblock; CodeView codeview; uint address; this(uint addr, CodeView cv) { codeview = cv; address = addr; } this(uint addr) { address = addr; } this(string p) { path = p; } uint line() { if ( codeblock is null ) return 0; return codeblock.line; } string file() { if ( codeblock is null || codeblock.segment is null ) return null; return codeblock.segment.file.name; } size_t getCodeBase() { return mod.codeview.image.getCodeBase; } bool bind(ImageSet images, string[] source_search_paths) { if ( path is null ) return false; if ( find(path, '"') >= 0 ) path = replace(path, "\"", ""); string[] file_line = split(path, ":"); if ( file_line is null || file_line.length < 2 || !isNumeric(file_line[$-1]) ) { DbgIO.println("Invalid location format. Use <part of filename>:<linenumber>"); return false; } string file = join(file_line[0..$-1], ":"), line = file_line[$-1]; if ( find(file, '/') >= 0 ) file = replace(file, "/", "\\"); debug DbgIO.println("searching in %s", file); SourceFile[] sfs = images.findSrcFiles(file); if ( sfs.length == 0 ) sfs = images.findSrcFiles(file, source_search_paths); if ( sfs.length == 0 ) { DbgIO.println("Source file \"%s\" not found", file); return false; } uint linenum = cast(uint)atoi(line); Location loc; foreach ( sf; sfs ) { debug DbgIO.println("searching sf %s", sf.name); auto loc2 = images.findSrcLine(sf, linenum); if ( loc is null ) loc = loc2; else if ( loc2 !is null && loc2.line < loc.line ) loc = loc2; } if ( loc is null ) DbgIO.println("Line %d in \"%s\" not found", linenum, sfs[0].name); scope_sym = loc.scope_sym; data_sym = loc.data_sym; mod = loc.mod; codeblock = loc.codeblock; address = loc.address; path = null; return true; } } class UserDefinedType { ushort type_index; string name; } /************************************************************************************************** Represents the CodeView information of an executable image. Provides methods to browse the information. Objects of this class get created by CodeViewParser.parse. **************************************************************************************************/ class CodeView : DebugInfo { Module[string] modulesByName; Module[] modulesByIndex; SymbolSet global_pub, global_sym, static_sym; UserDefinedType[] udtypes; Leaf[][] type_strings; Leaf[string] UDTsByName; string[] libraries, segnames; COFFImage image; AVLTree!(NamedSymbol) globalNamedSymbols; size_t getCodeBase() { return image.getCodeBase; } /********************************************************************************************** Find the module and segment covering the given address. **********************************************************************************************/ Module findModule(uint vaddress, out uint segment) { uint address = vaddress-image.getCodeBase; foreach ( m; modulesByIndex ) { foreach ( s; m.seginfos ) { if ( address < s.offset ) continue; if ( address-s.offset < s.cbSeg ) { segment = s.Seg; return m; } } } return null; } /********************************************************************************************** Find next source line from the given location. **********************************************************************************************/ Location findNextSrcLine(Location loc) { if ( loc is null || loc.codeblock is null || loc.codeblock.segment is null ) return null; Location nextloc = findLocation(loc.codeblock.end+image.getCodeBase); return nextloc; } /********************************************************************************************** Find previous source line from location that isn't covered by a source codeblock. **********************************************************************************************/ Location findPrevSrcLine(Location loc) { if ( loc is null ) return null; if ( loc.codeblock !is null ) return loc; AVLNode!(CodeBlock) node; if ( !codeblocks.find(loc.address-1+image.getCodeBase, node) ) { if ( node.value.start > loc.address ) { if ( !node.findPrev(node) ) return null; } } Location prevloc = new Location(node.value.start, this); prevloc.codeblock = node.value; findSymbolForLocation(prevloc); assert(prevloc.line != 0); return prevloc; } /********************************************************************************************** Find first source line in the given file that has a line number >= line and a start address >= min_start. **********************************************************************************************/ Location findSrcLine(SourceFile sf, uint min_line, size_t min_start=0) { if ( sf is null ) return null; pragma(msg, TODO(__FILE__,__LINE__,"use binary search here")); foreach ( l; sf.lines ) { if ( l < min_line ) continue; foreach ( cb; sf.blocks_by_line[l] ) { if ( cb.start < min_start || cb.end <= cb.start ) continue; Location loc = new Location(cb.start+image.getCodeBase, this); loc.codeblock = cb; findSymbolForLocation(loc); return loc; } } return null; } /********************************************************************************************** Find all debug information available for the given address. **********************************************************************************************/ Location findLocation(uint vaddress) { Location loc = new Location(vaddress, this); CodeBlock cb = findCodeBlockAbs(vaddress); loc.codeblock = cb; findSymbolForLocation(loc); return loc; } /********************************************************************************************** Fill out symbol information (as opposed to source line information) in the given location. **********************************************************************************************/ void findSymbolForLocation(Location loc) { ProcedureSymbol psym = findProcedureSymbol(loc.address); if ( psym !is null ) loc.scope_sym = psym; else { DataSymbol dsym = findDataSymbol(loc.address, 2); if ( dsym !is null ) loc.data_sym = dsym; } uint seg; Module mod = findModule(loc.address, seg); if ( mod !is null ) { loc.mod = mod; if ( loc.data_sym is null ) { uint min_dist = uint.max; loc.data_sym = global_sym.findNearestDataSymbol(loc.address-image.getCodeBase, min_dist, image.code_section_index+1); if ( loc.data_sym is null ) loc.data_sym = global_pub.findNearestDataSymbol(loc.address-image.getCodeBase, min_dist, image.code_section_index+1); } } } /********************************************************************************************** Find procedure symbol covering the given address. **********************************************************************************************/ ProcedureSymbol findProcedureSymbol(uint vaddress) { uint address = vaddress-image.getCodeBase; ProcedureSymbol ps; foreach ( m; modulesByIndex ) { ps = m.symbols.findProcedureSymbol(address); if ( ps !is null ) return ps; } ps = global_sym.findProcedureSymbol(address); if ( ps is null ) ps = static_sym.findProcedureSymbol(address); if ( ps is null ) ps = global_pub.findProcedureSymbol(address); return ps; } /********************************************************************************************** Find data symbol covering the given address. **********************************************************************************************/ DataSymbol findDataSymbol(uint vaddress, uint segment=0) { uint address = vaddress-image.getCodeBase; DataSymbol ps; foreach ( m; modulesByIndex ) { ps = m.symbols.findDataSymbol(address, segment); if ( ps !is null ) break; } ps = global_sym.findDataSymbol(address, segment); if ( ps is null ) ps = static_sym.findDataSymbol(address, segment); if ( ps is null ) ps = global_pub.findDataSymbol(address, segment); return ps; } /********************************************************************************************** Creates a D mangled name from a CodeView symbol. Uses available mangled type info if available, mangles CodeView type info else. Returns: Symbol name with mangled type info. **********************************************************************************************/ string mangle(NamedSymbol s) { // use mangled typeinfo if available if ( s.mangled_name !is null && s.mangled_name.length > 2 && s.mangled_name[0..2] == "_D" && isdigit(s.mangled_name[2]) ) return s.mangled_name; return "_D"~mangleName(s.name_type)~mangleType(s); } /********************************************************************************************** Creates the type part of a D mangled name for a CodeView symbol. **********************************************************************************************/ string mangleType(Symbol s) { DataSymbol ds = cast(DataSymbol)s; ushort cvtype; if ( ds !is null ) cvtype = ds.cvdata.type; else { StackSymbol ss = cast(StackSymbol)s; if ( ss !is null ) cvtype = ss.cvdata.type; else { pragma(msg, TODO(__FILE__,__LINE__,"implement procedure symbol mangling")); } } return mangleCVtype(cvtype); } /********************************************************************************************** Creates the type part of a D mangled name for a CodeView type index. **********************************************************************************************/ string mangleCVtype(ushort cvtype) { if ( cvtype >= 0x1000 ) { uint typeindex = cvtype-0x1000; if ( typeindex >= type_strings.length ) { debug DbgIO.println("undefined complex type 0x%x largest known type 0x%x", cvtype, type_strings.length-1); return null; } Leaf[] typestring = type_strings[typeindex]; while ( typestring.length > 0 ) { switch ( typestring[0].leaf_index ) { case LF_MODIFIER_16t: LeafModifer lm = cast(LeafModifer)typestring[0]; assert ( lm !is null ); return mangleCVtype(lm.index); case LF_POINTER_16t: LeafPointer lp = cast(LeafPointer)typestring[0]; assert ( lp !is null ); return "P"~mangleCVtype(lp.type); // do not insert new cases here case LF_CLASS_16t: LeafClassStruc lcs = cast(LeafClassStruc)typestring[0]; assert ( lcs !is null ); return "C"~mangleName(lcs.name); case LF_ARRAY_16t: LeafArray la = cast(LeafArray)typestring[0]; assert ( la !is null ); debug(cvparser) DbgIO.println("Static array elemtype 0x%x idxtype 0x%x length %d", la.elemtype, la.idxtype, la.length.getUint); uint count = la.length.getUint, elmsize = sizeofCV(la.elemtype); if ( elmsize > 0 ) { count /= elmsize; assert(la.length.getUint % sizeofCV(la.elemtype) == 0); } else debug DbgIO.println("WARNING: elm size == 0"); return "G"~.toString(count)~mangleCVtype(la.elemtype); case LF_OEM_16t: LeafDynArray lda = cast(LeafDynArray)typestring[0]; if ( lda !is null ) return "A"~mangleCVtype(lda.elem_type); LeafAssocArray laa = cast(LeafAssocArray)typestring[0]; if ( laa !is null ) return "H"~mangleCVtype(laa.key_type)~mangleCVtype(laa.elem_type); LeafDelegate ld = cast(LeafDelegate)typestring[0]; if ( ld !is null ) return "D"~mangleCVtype(ld.func_type); assert(0); case LF_STRUCTURE_16t: LeafClassStruc lcs = cast(LeafClassStruc)typestring[0]; assert ( lcs !is null ); return "S"~mangleName(lcs.name); case LF_PROCEDURE_16t: case LF_METHODLIST_16t: debug(cvparser) DbgIO.println("unmangled procedure or methodlist in complex type"); return ""; case LF_UNION_16t: LeafUnion lu = cast(LeafUnion)typestring[0]; return "S"~mangleName(lu.name); default: DbgIO.println("mangleCVtype: unsupported type leaf 0x%x", typestring[0].leaf_index); typestring = typestring[1..$]; } } return null; } switch ( cvtype ) { case T_NOTYPE: return null; case T_VOID: return "v"; case T_PVOID: case T_PFVOID: case T_PHVOID: case T_32PVOID: case T_32PFVOID: return "Pv"; case T_CHAR: return "g"; case T_UCHAR: return "h"; case T_RCHAR: return "a"; case T_WCHAR: return "u"; case T_DCHAR: return "w"; case T_32PDCHAR: case T_32PFDCHAR: return "Pw"; case T_PFRCHAR: case T_PHRCHAR: case T_32PRCHAR: case T_32PFRCHAR: case T_PRCHAR: return "Pa"; case T_PFWCHAR: case T_PHWCHAR: case T_32PWCHAR: case T_32PFWCHAR: case T_PWCHAR: return "Pu"; case T_PFCHAR: case T_PHCHAR: case T_32PCHAR: case T_32PFCHAR: case T_PCHAR: return "Pg"; case T_PFUCHAR: case T_PHUCHAR: case T_32PUCHAR: case T_32PFUCHAR: case T_PUCHAR: return "Ph"; case T_SHORT: case T_INT2: return "s"; case T_USHORT: case T_UINT2: return "t"; case T_PINT2: case T_PSHORT: case T_32PSHORT: return "Ps"; case T_PUSHORT: case T_PUINT2: case T_32PUSHORT: return "Pt"; case T_INT4: case T_LONG: return "i"; case T_UINT4: case T_ULONG: return "k"; case T_32PINT4: case T_PINT4: return "Pi"; case T_32PUINT4: case T_PUINT4: return "Pk"; case T_QUAD: return "l"; case T_UQUAD: return "m"; case T_32PQUAD: case T_PQUAD: return "Pl"; case T_32PUQUAD: case T_PUQUAD: return "Pm"; case T_REAL32: return "f"; case T_32PREAL32: case T_PREAL32: return "Pf"; case T_REAL64: return "d"; case T_32PREAL64: case T_PREAL64: return "Pd"; case T_REAL80: return "e"; case T_PREAL80: case T_PFREAL80: case T_PHREAL80: case T_32PREAL80: case T_32PFREAL80: return "Pe"; case T_BOOL08: return "b"; case T_32PBOOL08: case T_32PFBOOL08: return "Pb"; case T_CPLX80: return "c"; case T_CPLX64: return "r"; case T_CPLX32: return "q"; case T_32PCPLX80: case T_32PFCPLX80: return "Pc"; case T_32PCPLX64: case T_32PFCPLX64: return "Pr"; case T_32PCPLX32: case T_32PFCPLX32: return "Pq"; default: debug DbgIO.println("mangleCVtype: unknown codeview type 0x%x", cvtype); } return null; } /************************************************************************************************** Returns: size of demangled type **************************************************************************************************/ uint sizeofMangled(string m) { assert(m.length > 0); switch ( m[0] ) { case 'A': return ulong.sizeof; case 'G': string n = m[1..$]; size_t count = parseNumber(n); return count*sizeofMangled(n); case 'P': return size_t.sizeof; case 'H': return size_t.sizeof; case 'v': return void.sizeof; case 'b': return bit.sizeof; case 'x': return bool.sizeof; case 'g': return byte.sizeof; case 'h': return ubyte.sizeof; case 's': return short.sizeof; case 't': return ushort.sizeof; case 'i': return int.sizeof; case 'k': return uint.sizeof; case 'l': return long.sizeof; case 'm': return ulong.sizeof; case 'f': return float.sizeof; case 'd': return double.sizeof; case 'e': return real.sizeof; case 'o': return ifloat.sizeof; case 'p': return idouble.sizeof; case 'j': return ireal.sizeof; case 'q': return cfloat.sizeof; case 'r': return cdouble.sizeof; case 'c': return creal.sizeof; case 'a': return char.sizeof; case 'u': return wchar.sizeof; case 'w': return dchar.sizeof; case 'C': case 'S': string mangled_name = m[1..$], name = demangleNameSkip(mangled_name); if ( name in UDTsByName ) { LeafClassStruc lcs = cast(LeafClassStruc)UDTsByName[name]; if ( lcs !is null ) return lcs.length.getUint; LeafUnion lu = cast(LeafUnion)UDTsByName[name]; if ( lu !is null ) return lu.length.getUint; } assert(0, "unknown struct in sizeofMangled: "~name); default: assert(0, "unknown type in sizeofMangled: "~m); } return 0; } /********************************************************************************************** Calculates the size of the type specified by a CodeView type index. **********************************************************************************************/ uint sizeofCV(uint cvtype) { if ( cvtype >= 0x1000 ) { uint typeindex = cvtype-0x1000; if ( typeindex >= type_strings.length ) { debug DbgIO.println("sizeofCV: undefined complex type 0x%x", cvtype); return 0; } Leaf[] typestring = type_strings[typeindex]; while ( typestring.length > 0 ) { switch ( typestring[0].leaf_index ) { case LF_MODIFIER_16t: LeafModifer lm = cast(LeafModifer)typestring[0]; assert ( lm !is null ); return sizeofCV(lm.index); case LF_ARRAY_16t: LeafArray la = cast(LeafArray)typestring[0]; assert ( la !is null ); return la.length.getUint; case LF_POINTER_16t: case LF_CLASS_16t: return 4; case LF_STRUCTURE_16t: LeafClassStruc lcs = cast(LeafClassStruc)typestring[0]; assert ( lcs !is null ); return lcs.length.getUint; case LF_PROCEDURE_16t: case LF_METHODLIST_16t: debug DbgIO.println("unmangled procedure or methodlist in complex type"); return 0; case LF_UNION_16t: LeafUnion lu = cast(LeafUnion)typestring[0]; return lu.length.getUint; case LF_OEM_16t: LeafDynArray lda = cast(LeafDynArray)typestring[0]; if ( lda !is null ) return size_t.sizeof*2; LeafAssocArray laa = cast(LeafAssocArray)typestring[0]; if ( laa !is null ) return size_t.sizeof; LeafDelegate ld = cast(LeafDelegate)typestring[0]; if ( ld !is null ) return size_t.sizeof*2; assert(0); default: DbgIO.println("sizeofCV: unsupported complex type leaf 0x%x", typestring[0].leaf_index); typestring = typestring[1..$]; } } return 0; } switch ( cvtype ) { case T_NOTYPE: return 0; case T_VOID: case T_CHAR: case T_UCHAR: case T_RCHAR: case T_BOOL08: return 1; case T_SHORT: case T_INT2: case T_USHORT: case T_UINT2: case T_WCHAR: return 2; case T_PVOID: case T_PFVOID: case T_PHVOID: case T_32PVOID: case T_32PFVOID: case T_DCHAR: case T_32PDCHAR: case T_32PFDCHAR: case T_PFCHAR: case T_PHCHAR: case T_32PCHAR: case T_32PFCHAR: case T_PCHAR: case T_PFUCHAR: case T_PHUCHAR: case T_32PUCHAR: case T_32PFUCHAR: case T_PUCHAR: case T_PRCHAR: case T_PFRCHAR: case T_PHRCHAR: case T_32PRCHAR: case T_32PFRCHAR: case T_PWCHAR: case T_PFWCHAR: case T_PHWCHAR: case T_32PWCHAR: case T_32PFWCHAR: case T_PINT2: case T_PSHORT: case T_32PSHORT: case T_PUSHORT: case T_PUINT2: case T_32PUSHORT: case T_32PBOOL08: case T_32PFBOOL08: case T_INT4: case T_UINT4: case T_32PINT4: case T_PINT4: case T_32PUINT4: case T_PUINT4: case T_32PQUAD: case T_PQUAD: case T_32PUQUAD: case T_PUQUAD: case T_ULONG: case T_REAL32: case T_32PREAL32: case T_PREAL32: case T_32PREAL64: case T_PREAL64: case T_PREAL80: case T_PFREAL80: case T_PHREAL80: case T_32PREAL80: case T_32PFREAL80: case T_CPLX32: case T_32PCPLX32: case T_32PFCPLX32: case T_32PCPLX64: case T_32PFCPLX64: case T_32PCPLX80: case T_32PFCPLX80: return 4; case T_QUAD: case T_UQUAD: case T_REAL64: case T_CPLX64: return 8; case T_CPLX80: case T_REAL80: return 10; default: debug DbgIO.println("sizeofCV: unknown codeview type 0x%x", cvtype); } return 0; } }