I once had a huge pile of Oracle PL/SQL to take care of, which was written for performance rather than ease of maintenance and used a lot of session level global data.
PL/SQL doesn't give you nice stack traces when you have an error, I just knew the entry point and the place where the error occurred.
Even knowing the data coming in to the entry point, use of the globals meant that you often couldn't know for sure what route the code would take.
I wrote a primitive PL/SQL parser (in Perl) to turn the call tree into Prolog rules, and then used Prolog to give me the possible routes between the entry point and the error location, making debugging much easier.
I think it was about 60Mb of source, around 1000 packages and stand-alone procs.
Basically the perl pulled a list of scoped function names from the DDL, did a text index on the executable code, and searched the index for references to those functions, creating a list of [from.function, to.function] pairs that I fed into prolog.
PL/SQL doesn't give you nice stack traces when you have an error, I just knew the entry point and the place where the error occurred.
Even knowing the data coming in to the entry point, use of the globals meant that you often couldn't know for sure what route the code would take.
I wrote a primitive PL/SQL parser (in Perl) to turn the call tree into Prolog rules, and then used Prolog to give me the possible routes between the entry point and the error location, making debugging much easier.