Skip to content

Commit

Permalink
Merge pull request #8906 from rainers/issue19318
Browse files Browse the repository at this point in the history
fix Issue 19318 - Variables captured from outer functions not visible in debugger
  • Loading branch information
thewilsonator authored Nov 4, 2018
2 parents ffbffb6 + e922ee7 commit dfc29bc
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 5 deletions.
2 changes: 2 additions & 0 deletions src/dmd/backend/cgcv.d
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ debtyp_t* debtyp_alloc(uint length);
int cv_stringbytes(const(char)* name);
uint cv4_numericbytes(uint value);
void cv4_storenumeric(ubyte* p, uint value);
uint cv4_signednumericbytes(int value);
void cv4_storesignednumeric(ubyte* p, int value);
idx_t cv_debtyp(debtyp_t* d);
int cv_namestring(ubyte* p, const(char)* name, int length = -1);
uint cv4_typidx(type* t);
Expand Down
42 changes: 42 additions & 0 deletions src/dmd/backend/dcgcv.d
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,48 @@ void cv4_storenumeric(ubyte *p, uint value)
}
}

/***********************************
* Return number of bytes required to store a signed numeric leaf.
* Params:
* value = value to store
* Returns:
* number of bytes required for storing value
*/
uint cv4_signednumericbytes(int value)
{
uint u;
if (value >= 0 && value < 0x8000)
u = 2;
else if (value == cast(short)value)
u = 4;
else
u = 6;
return u;
}

/********************************
* Store signed numeric leaf.
* Must use exact same number of bytes as cv4_signednumericbytes().
* Params:
* p = address where to store value
* value = value to store
*/
void cv4_storesignednumeric(ubyte *p, int value)
{
if (value >= 0 && value < 0x8000)
TOWORD(p, value);
else if (value == cast(short)value)
{
TOWORD(p, LF_SHORT);
TOWORD(p + 2, value);
}
else
{
TOWORD(p,LF_LONG);
TOLONG(p + 2, value);
}
}

/*********************************
* Generate a type index for a parameter list.
*/
Expand Down
3 changes: 3 additions & 0 deletions src/dmd/glue.d
Original file line number Diff line number Diff line change
Expand Up @@ -1234,6 +1234,9 @@ void FuncDeclaration_toObjFile(FuncDeclaration fd, bool multiobj)
}

writefunc(s);

buildCapture(fd);

// Restore symbol table
cstate.CSpsymtab = symtabsave;

Expand Down
10 changes: 5 additions & 5 deletions src/dmd/tocvdebug.d
Original file line number Diff line number Diff line change
Expand Up @@ -735,8 +735,8 @@ private uint writeField(ubyte* p, const char* id, uint attr, uint typidx, uint o
TOWORD(p,LF_MEMBER_V3);
TOWORD(p + 2,attr);
TOLONG(p + 4,typidx);
cv4_storenumeric(p + 8, offset);
uint len = 8 + cv4_numericbytes(offset);
cv4_storesignednumeric(p + 8, offset);
uint len = 8 + cv4_signednumericbytes(offset);
len += cv_namestring(p + len, id);
return cv_align(p + len, len);
}
Expand All @@ -745,8 +745,8 @@ private uint writeField(ubyte* p, const char* id, uint attr, uint typidx, uint o
TOWORD(p,LF_MEMBER);
TOWORD(p + 2,typidx);
TOWORD(p + 4,attr);
cv4_storenumeric(p + 6, offset);
uint len = 6 + cv4_numericbytes(offset);
cv4_storesignednumeric(p + 6, offset);
uint len = 6 + cv4_signednumericbytes(offset);
return len + cv_namestring(p + len, id);
}
}
Expand Down Expand Up @@ -793,7 +793,7 @@ void toDebugClosure(Symbol* closstru)
{
Symbol *sf = list_symbol(sl);
uint thislen = (config.fulltypes == CV8 ? 8 : 6);
thislen += cv4_numericbytes(cast(uint)sf.Smemoff);
thislen += cv4_signednumericbytes(cast(uint)sf.Smemoff);
thislen += cv_stringbytes(sf.Sident.ptr);
thislen = cv_align(null, thislen);

Expand Down
46 changes: 46 additions & 0 deletions src/dmd/toir.d
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,52 @@ void buildClosure(FuncDeclaration fd, IRState *irs)
}
}

/*************************************
* build a debug info struct for variables captured by nested functions,
* but not in a closure.
* must be called after generating the function to fill stack offsets
* Params:
* fd = function
*/
void buildCapture(FuncDeclaration fd)
{
if (!global.params.symdebug)
return;
if (!global.params.mscoff) // toDebugClosure only implemented for CodeView,
return; // but optlink crashes for negative field offsets

if (fd.closureVars.dim && !fd.needsClosure)
{
/* Generate type name for struct with captured variables */
const char *name1 = "CAPTURE.";
const char *name2 = fd.toPrettyChars();
size_t namesize = strlen(name1)+strlen(name2)+1;
char *capturename = cast(char *) calloc(namesize, char.sizeof);
strcat(strcat(capturename, name1), name2);

/* Build type for struct */
type *capturestru = type_struct_class(capturename, Target.ptrsize, 0, null, null, false, false, true, false);
free(capturename);

foreach (v; fd.closureVars)
{
Symbol *vsym = toSymbol(v);

/* Add variable as capture type member */
symbol_struct_addField(capturestru.Ttag, &vsym.Sident[0], vsym.Stype, cast(uint)vsym.Soffset);
//printf("capture field %s: offset: %i\n", &vsym.Sident[0], v.offset);
}

// generate pseudo symbol to put into functions' Sscope
Symbol *scapture = symbol_name("__captureptr", SCalias, type_pointer(capturestru));
scapture.Sflags |= SFLtrue | SFLfree;
//symbol_add(scapture);
fd.csym.Sscope = scapture;

toDebugClosure(capturestru.Ttag);
}
}


/***************************
* Determine return style of function - whether in registers or
Expand Down
28 changes: 28 additions & 0 deletions test/runnable/testpdb.d
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,34 @@ void test19307(IDiaSession session, IDiaSymbol globals)
testClosureVar(globals, "testpdb.Struct.foo.nested", "this", "__chain", "member");
}

///////////////////////////////////////////////
// https://issues.dlang.org/show_bug.cgi?id=19318
// variables captured from outer functions not visible in debugger
int foo19318(int z) @nogc
{
int x = 7;
auto nested() scope
{
int nested2()
{
return x + z;
}
return nested2();
}
return nested();
}

void test19318(IDiaSession session, IDiaSymbol globals)
{
foo19318(5);

testClosureVar(globals, "testpdb.foo19318", "x");
testClosureVar(globals, "testpdb.foo19318.nested", "this", "x");
testClosureVar(globals, "testpdb.foo19318.nested", "this", "z");
testClosureVar(globals, "testpdb.foo19318.nested.nested2", "this", "x");
testClosureVar(globals, "testpdb.foo19318.nested.nested2", "this", "z");
}

///////////////////////////////////////////////
import core.stdc.stdio;
import core.stdc.wchar_;
Expand Down

0 comments on commit dfc29bc

Please sign in to comment.