Thanks to visit codestin.com
Credit goes to github.com

Skip to content

EE calls ICorJitInfo::setBoundaries() with invalid sourceType #52624

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
tonybaloney opened this issue May 11, 2021 · 7 comments
Open

EE calls ICorJitInfo::setBoundaries() with invalid sourceType #52624

tonybaloney opened this issue May 11, 2021 · 7 comments
Assignees
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI Priority:2 Work that is important, but not critical for the release
Milestone

Comments

@tonybaloney
Copy link
Contributor

tonybaloney commented May 11, 2021

This relates to the EE ryuJIT debug interface and the ability to request sequence points for a debugger.

I've implemented ICorJitInfo::getBoundaries() to return an array of sequence points that I'm interested in with the IL mappings:

void getBoundaries(
        CORINFO_METHOD_HANDLE   ftn,                // [IN] method of interest
        unsigned int           *cILOffsets,         // [OUT] size of pILOffsets
        uint32_t                 **pILOffsets,         // [OUT] IL offsets of interest
        ICorDebugInfo::BoundaryTypes *implicitBoundaries // [OUT] tell jit, all boundaries of this type
        ) override {
        BaseMethod* meth = reinterpret_cast<BaseMethod *>(ftn);
        *cILOffsets = meth->getSequencePointCount();
        *pILOffsets = meth->getSequencePointOffsets();
        *implicitBoundaries = ICorDebugInfo::BoundaryTypes::DEFAULT_BOUNDARIES;
    }

The source types are https://github.com/dotnet/runtime/blob/main/src/coreclr/inc/cordebuginfo.h#L41-L50 :

enum SourceTypes
    {
        SOURCE_TYPE_INVALID        = 0x00, // To indicate that nothing else applies
        SEQUENCE_POINT             = 0x01, // The debugger asked for it.
        STACK_EMPTY                = 0x02, // The stack is empty here
        CALL_SITE                  = 0x04, // This is a call site.
        NATIVE_END_OFFSET_UNKNOWN  = 0x08, // Indicates a epilog endpoint
        CALL_INSTRUCTION           = 0x10  // The actual instruction of a call.

    };

I would expect the call back to have ICorJitInfo::SEQUENCE_POINT as the enum for the sourceType struct for the sequence points I requested, but instead they have the value 0 (maps to SOURCE_INVALID):

    void setBoundaries(
        CORINFO_METHOD_HANDLE   ftn,            // [IN] method of interest
        uint32_t                 cMap,           // [IN] size of pMap
        ICorDebugInfo::OffsetMapping *pMap      // [IN] map including all points of interest.
        //      jit allocated with allocateArray, EE frees
        ) override {
        BaseMethod* meth = reinterpret_cast<BaseMethod*>(ftn);
        for (size_t i = 0; i< cMap; i++){
           // HERE MY sequence points are SOURCE_INVALID instead of SEQUENCE_POINT
            if (pMap[i].source == ICorDebugInfo::SEQUENCE_POINT) {
                meth->recordSequencePointOffsetPosition(pMap[i].ilOffset, pMap[i].nativeOffset);
            }
        }
        m_sequencePoints = meth->getSequencePoints();
    }

This is generated by, void CodeGen::genIPmappingGen() which looks to call Compiler::eeSetLIinfo()

void Compiler::eeSetLIinfo(
    unsigned which, UNATIVE_OFFSET nativeOffset, IL_OFFSET ilOffset, bool stkEmpty, bool callInstruction)
{
    assert(opts.compDbgInfo);
    assert(eeBoundariesCount > 0);
    assert(which < eeBoundariesCount);

    if (eeBoundaries != nullptr)
    {
        eeBoundaries[which].nativeIP     = nativeOffset;
        eeBoundaries[which].ilOffset     = ilOffset;
        eeBoundaries[which].sourceReason = stkEmpty ? ICorDebugInfo::STACK_EMPTY : 0;
        eeBoundaries[which].sourceReason |= callInstruction ? ICorDebugInfo::CALL_INSTRUCTION : 0;
    }
}

I can't see a condition under which it would correctly assign the SEQUENCE_POINT value?

This looks like a bug in that condition.

If it is, I'd be happy to submit a PR to fix.

category:cq
theme:jit-ee-interface
skill-level:beginner
cost:small
impact:small

@ghost ghost added area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI untriaged New issue has not been triaged by the area owner labels May 11, 2021
@tonybaloney
Copy link
Contributor Author

FYI @AndyAyersMS

@AndyAyersMS
Copy link
Member

AndyAyersMS commented May 12, 2021

The jit currently uses the top to bits of the IL offset to represent calls and stack empty points...

// We define two IL offset types, as follows:
//
// IL_OFFSET: either a distinguished value, or an IL offset.
// IL_OFFSETX: either a distinguished value, or the top two bits are a flags, and the remaining bottom
// bits are a IL offset.
//
// In both cases, the set of legal distinguished values is:
// BAD_IL_OFFSET -- A unique illegal IL offset number. Note that it must be different from
// the ICorDebugInfo values, below, and must also not be a legal IL offset.
// ICorDebugInfo::NO_MAPPING -- The IL offset corresponds to no source code (such as EH step blocks).
// ICorDebugInfo::PROLOG -- The IL offset indicates a prolog
// ICorDebugInfo::EPILOG -- The IL offset indicates an epilog
//
// The IL offset must be in the range [0 .. 0x3fffffff]. This is because we steal
// the top two bits in IL_OFFSETX for flags, but we want the maximum range to be the same
// for both types. The IL value can't be larger than the maximum IL offset of the function
// being compiled.
//
// Blocks and statements never store one of the ICorDebugInfo values, even for IL_OFFSETX types. These are
// only stored in the IPmappingDsc struct, ipmdILoffsx field.
typedef unsigned IL_OFFSET;
const IL_OFFSET BAD_IL_OFFSET = 0x80000000;
const IL_OFFSET MAX_IL_OFFSET = 0x3fffffff;
typedef unsigned IL_OFFSETX; // IL_OFFSET with stack-empty or call-instruction bit
const IL_OFFSETX IL_OFFSETX_STKBIT = 0x80000000; // Note: this bit is set when the stack is NOT empty!
const IL_OFFSETX IL_OFFSETX_CALLINSTRUCTIONBIT = 0x40000000; // Set when the IL offset is for a call instruction.
const IL_OFFSETX IL_OFFSETX_BITS = IL_OFFSETX_STKBIT | IL_OFFSETX_CALLINSTRUCTIONBIT;
IL_OFFSET jitGetILoffs(IL_OFFSETX offsx);
IL_OFFSET jitGetILoffsAny(IL_OFFSETX offsx);
bool jitIsStackEmpty(IL_OFFSETX offsx);
bool jitIsCallInstruction(IL_OFFSETX offsx);

So other kinds of boundaries aren't tracked by the jit. If we need to track other boundaries we'll need to find some new way to store this information as we probably can't reliably steal any more bits.

A general mechanism would be to use this field as an index into a table that carries the extra info, instead of representing it directly. We could still have special index values for common cases like no IL offset. The table could be memoizing since this information tends to be immutable (thus there'd be a 1-1 mapping between indices and the values of the table entries).

This work would entail an initial refactoring of the jit to properly abstract access to this data before we started extending it out. It would likely be worthwhile because we soon will need to be able to track IL offsets within inlinees and so will need some sort of extendable representation.

@AndyAyersMS
Copy link
Member

@jakobbotsch some thoughts on a more flexible representation for the IL offset.

Also note we currently keep track of the "inline context" per statement; that might be another thing we refactor into this external table (so it has an embedded representation of the inline nesting, say).

@JulieLeeMSFT
Copy link
Member

Assigining @jakobbotsch for his input.

@jakobbotsch some thoughts on a more flexible representation for the IL offset.

@JulieLeeMSFT JulieLeeMSFT removed the untriaged New issue has not been triaged by the area owner label Jun 7, 2021
@JulieLeeMSFT
Copy link
Member

Moving to future since it is unlikely to happen in .NET 6.

@JulieLeeMSFT JulieLeeMSFT added this to the Future milestone Jun 7, 2021
@JulieLeeMSFT JulieLeeMSFT added the Priority:2 Work that is important, but not critical for the release label Jun 7, 2021
@jakobbotsch
Copy link
Member

I'm currently working on refactoring the debug info, we should be able to handle this once that is done.

@tonybaloney
Copy link
Contributor Author

Will this happen? I'll close the issue otherwise

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI Priority:2 Work that is important, but not critical for the release
Projects
None yet
Development

No branches or pull requests

4 participants