Here's the techniques I generally use when debugging more complex modifications that result in CTDs while executing :
1) Narrow it down to a single function.
1a) Apply and Revert various combinations of modfile as needed to narrow down the scope of the CTD as best possible
1b) When changes are "linked", use early return statements to skip executing a particular functions
2) Once narrowed down to a function, skip executing particular pieces of code to narrow down the CTD to a particular line
2a) Return statements can be added to skip execution of code past a certain point in the function, e.g. :
will prevent line2 from executing, so if the above doesn't CTD it means that line2 (or later) is the culprite
2b) Conditional jumps (e.g. 0x07 token statements) can be converted to unconditional (i.e. 0x06) to skip all code within a conditional. If a CTD stops happening after such a change, then the CTD is within the body of the conditional block
3) Once narrowed down to a particular line, figure out the problem with the line
3a) Make sure both absolute and relative jump offsets are correct (new v0.90+ UPKmodder checks for validity of absolute jump offsets, but not relative)
3b) Some composited lines can be broken apart to test pieces. For example :
<statement1> = <statement2>
can be broken into :
by replacing the 0x0F Assignement token with a 0x0B null-op. Functionally the two statements wouldn't do anything, but their code is still executed. Having broken them down into separate lines, the techniques from section 2 can be used to determine which portion of code is causing the CTD.