This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

How is software breakpoint implemented?

Anonymous
Anonymous

Hi,

 

I would like to ask some questions on software breakpoint implementation.

 

Observation:

One can add/remove/modify software breakpoints after the executable code has been loaded into memory, or even after the program is halted as another breakpoint.

Conclusion:

Software doesn’t require rebuild or re-compilation.

 

Question:

Then how is breakpoint implemented? Consider the most naïve implementation that breakpoint is implemented as adding several lines of special instruction before the line of breakpoint, this certainly required recompilation and re-linking. Clearly, this possibility has been ruled out by our conclusion above.

 

There might be another two alternatives:

 

Alternative I:

 

Patching” the memory where the code resides:

 

 

Note:

One can either patching all breakpoint lines at once, or patch only the next two possible branching target breakpoints when its parent node has been reached (see the semantic tree below). I don’t see any difference between them and it should up to the implementation.

Alternative II:

 

Designate two special registers in the CPU for implementing this.

 

Why would we require two of them rather than one? This is basically because each branching, executed or not, can lead to two different new program counters / addresses - In data structure, two child nodes of a binary tree.

 

Case I:

 

SW 1

Line 1

 

 

Line 2

 

SW 2

Line 3

 

 

Line 4

 

 

Line 5

 

SW 3

Line 6

 

The characteristic of this case is that the order of execution is linear. Therefore, the only possible breakpoint is the next, so upon halting at SW 1, the debugger has to tell the CPU, through emulator for TI chips or directly writes to CPU registers on desktop PC, the next breakpoint location by writing to either of the two dedicated CPU breakpoint target registers:

 

 

After the user pressed “run” again, the CPU would compare each new program counter with SW1, and halt if matches.

 

Case II:

 

SW 0

value = expression

 

 

Case value

SW 1

Switch 1

 

 

{

}

 

SW 2

Switch 2

 

 

{

}

 

SW 3

Switch 3

 

 

{

}

 

 

.

.

.

 

SW 1000

Switch 1000

 

 

{

}

 

To exclude the case of computed value before running (known at compilation), we further stipulate that value is only possible to be known at run-time, for example, if expression contains at least one user input term.

 

In this scenario, upon finishing of SW 0, there might be as many as 1000 new target address. But this is only an illusion, since the semantic tree is always binary. Therefore, storing two possible PCs as shown in the diagram below is enough. Each time a new breakpoint is reached, the debugger-emulator should update the contents of these two registers

 

With this scheme the same resulting can be achieved without “patching” the memory.

 

 

 

Advantage of alternative II.

 

The advantage is that it doesn’t modify code itself, thus eliminating the case above. However, since for each instruction the CPU needs to do the comparison between values in these two registers, two comparisons in total, this might result in a severe performance penalty if the circuit for comparison is not fast enough.

 

Conclusion:

 

Since self-modified code is far less common the normal case where code are not changeable during execution, I think alternative I, “patching memory”, should be the actual implementation on all platforms (processor + IDE).

 

 

 

My question is how is software breakpoint in C6000 actually implemented? Is it solely based on alternative I? Or I, or is a mixture of them? I wish to get a detailed answer on this.

 

 

 

 

 

Thanks,

Zheng

  • Zheng Zhao said:
    My question is how is software breakpoint in C6000 actually implemented?

    As far as I know, CCS will first save the opcode at the address where the breakpoint is set to somewhere else, and then replace it with a breakpoint opcode (probably a halt instruction). I believe the original opcode is saved in memory on the emulator itself and CCS keeps track of this so that it can associate the original opcode with the address where the breakpoint is.

     

  • Anonymous
    0 Anonymous in reply to Ki

    Ki-Soo,

    So it corresponds to Alternative I, "patching memory"?

     

    Zheng

  • Similar concept, though it is a different opcode that is written and i don't think it is an interrupt.

  • Anonymous
    0 Anonymous in reply to Ki

    Ki-Soo,

    I see it, thanks very much.

     

    Zheng