dbghelp/pdb: Add line number to inline sites.

Requires to join DEBUG_S_INLINEES subsection with symbol annotations.

Signed-off-by: Eric Pouech <eric.pouech@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Eric Pouech 2021-11-08 15:00:01 +01:00 committed by Alexandre Julliard
parent bfc0edb8cf
commit d8f26a4233
1 changed files with 84 additions and 2 deletions

View File

@ -1814,6 +1814,70 @@ static BOOL codeview_advance_binannot(struct cv_binannot* cvba)
return TRUE; return TRUE;
} }
static inline int binannot_getsigned(unsigned i)
{
return (i & 1) ? -(int)(i >> 1) : (int)(i >> 1);
}
static BOOL cv_dbgsubsect_find_inlinee(const struct msc_debug_info* msc_dbg,
unsigned inlineeid,
const struct cv_module_snarf* cvmod,
const struct CV_DebugSSubsectionHeader_t* hdr_files,
unsigned* srcfile, unsigned* srcline)
{
const struct CV_DebugSSubsectionHeader_t* hdr;
const struct CV_DebugSSubsectionHeader_t* next_hdr;
const struct CV_InlineeSourceLine_t* inlsrc;
const struct CV_InlineeSourceLineEx_t* inlsrcex;
const struct CV_Checksum_t* chksms;
for (hdr = cvmod->dbgsubsect; CV_IS_INSIDE(hdr, cvmod->dbgsubsect + cvmod->dbgsubsect_size); hdr = next_hdr)
{
next_hdr = CV_RECORD_GAP(hdr, hdr->cbLen);
if (hdr->type != DEBUG_S_INLINEELINES) continue;
/* subsection starts with a DWORD signature */
switch (*(DWORD*)CV_RECORD_AFTER(hdr))
{
case CV_INLINEE_SOURCE_LINE_SIGNATURE:
inlsrc = CV_RECORD_GAP(hdr, sizeof(DWORD));
while (CV_IS_INSIDE(inlsrc, next_hdr))
{
if (inlsrc->inlinee == inlineeid)
{
chksms = CV_RECORD_GAP(hdr_files, inlsrc->fileId);
if (!CV_IS_INSIDE(chksms, CV_RECORD_GAP(hdr_files, hdr_files->cbLen))) return FALSE;
*srcfile = source_new(msc_dbg->module, NULL,
(chksms->strOffset < cvmod->strsize) ? cvmod->strimage + chksms->strOffset : "<<str-out-of-bounds>>");
*srcline = inlsrc->sourceLineNum;
return TRUE;
}
++inlsrc;
}
break;
case CV_INLINEE_SOURCE_LINE_SIGNATURE_EX:
inlsrcex = CV_RECORD_GAP(hdr, sizeof(DWORD));
while (CV_IS_INSIDE(inlsrcex, next_hdr))
{
if (inlsrcex->inlinee == inlineeid)
{
chksms = CV_RECORD_GAP(hdr_files, inlsrcex->fileId);
if (!CV_IS_INSIDE(chksms, CV_RECORD_GAP(hdr_files, hdr_files->cbLen))) return FALSE;
*srcfile = source_new(msc_dbg->module, NULL,
(chksms->strOffset < cvmod->strsize) ? cvmod->strimage + chksms->strOffset : "<<str-out-of-bounds>>");
*srcline = inlsrcex->sourceLineNum;
return TRUE;
}
inlsrcex = CV_RECORD_GAP(inlsrcex, inlsrcex->countOfExtraFiles * sizeof(inlsrcex->extraFileId[0]));
}
break;
default:
FIXME("Unknown signature %x in INLINEELINES subsection\n", *(DWORD*)CV_RECORD_AFTER(hdr));
break;
}
}
return FALSE;
}
static struct symt_inlinesite* codeview_create_inline_site(const struct msc_debug_info* msc_dbg, static struct symt_inlinesite* codeview_create_inline_site(const struct msc_debug_info* msc_dbg,
const struct cv_module_snarf* cvmod, const struct cv_module_snarf* cvmod,
struct symt_function* top_func, struct symt_function* top_func,
@ -1827,8 +1891,9 @@ static struct symt_inlinesite* codeview_create_inline_site(const struct msc_debu
DWORD64 addr; DWORD64 addr;
struct symt_inlinesite* inlined; struct symt_inlinesite* inlined;
struct cv_binannot cvba; struct cv_binannot cvba;
BOOL found = FALSE; BOOL srcok, found = FALSE;
unsigned first, offset, length; unsigned first, offset, length, line, srcfile;
const struct CV_Checksum_t* chksms;
if (!cvmod->ipi_ctp || !(cvt = codeview_jump_to_type(cvmod->ipi_ctp, inlinee))) if (!cvmod->ipi_ctp || !(cvt = codeview_jump_to_type(cvmod->ipi_ctp, inlinee)))
{ {
@ -1891,7 +1956,12 @@ static struct symt_inlinesite* codeview_create_inline_site(const struct msc_debu
break; break;
} }
if (!hdr_files) return FALSE; if (!hdr_files) return FALSE;
srcok = cv_dbgsubsect_find_inlinee(msc_dbg, inlinee, cvmod, hdr_files, &srcfile, &line);
if (srcok)
symt_add_func_line(msc_dbg->module, &inlined->func, srcfile, line, top_func->address + offset);
else
srcfile = line = 0;
for (;;) for (;;)
{ {
if (!codeview_advance_binannot(&cvba)) break; if (!codeview_advance_binannot(&cvba)) break;
@ -1904,21 +1974,33 @@ static struct symt_inlinesite* codeview_create_inline_site(const struct msc_debu
case BA_OP_ChangeCodeOffset: case BA_OP_ChangeCodeOffset:
offset += cvba.arg1; offset += cvba.arg1;
length = 1; length = 1;
if (srcok)
symt_add_func_line(msc_dbg->module, &inlined->func, srcfile, line, top_func->address + offset);
break; break;
case BA_OP_ChangeCodeLength: case BA_OP_ChangeCodeLength:
length = cvba.arg1; length = cvba.arg1;
break; break;
case BA_OP_ChangeFile: case BA_OP_ChangeFile:
chksms = CV_RECORD_GAP(hdr_files, cvba.arg1);
if (CV_IS_INSIDE(chksms, CV_RECORD_GAP(hdr_files, hdr_files->cbLen)))
srcfile = source_new(msc_dbg->module, NULL,
(chksms->strOffset < cvmod->strsize) ? cvmod->strimage + chksms->strOffset : "<<str-out-of-bounds>>");
break; break;
case BA_OP_ChangeLineOffset: case BA_OP_ChangeLineOffset:
line += binannot_getsigned(cvba.arg1);
break; break;
case BA_OP_ChangeCodeOffsetAndLineOffset: case BA_OP_ChangeCodeOffsetAndLineOffset:
if (srcok)
symt_add_func_line(msc_dbg->module, &inlined->func, srcfile, line, top_func->address + offset);
line += binannot_getsigned(cvba.arg2);
offset += cvba.arg1; offset += cvba.arg1;
length = 1; length = 1;
break; break;
case BA_OP_ChangeCodeLengthAndCodeOffset: case BA_OP_ChangeCodeLengthAndCodeOffset:
offset += cvba.arg2; offset += cvba.arg2;
length = cvba.arg1; length = cvba.arg1;
if (srcok)
symt_add_func_line(msc_dbg->module, &inlined->func, srcfile, line, top_func->address + offset);
break; break;
default: default:
WARN("Unsupported op %d\n", cvba.opcode); WARN("Unsupported op %d\n", cvba.opcode);