softwareCobbler / luceedebug

line debugger for lucee
GNU Lesser General Public License v2.1
44 stars 15 forks source link

Proper settings and Unverified Breakpoint #23

Closed Leftbower closed 1 year ago

Leftbower commented 1 year ago

I'm struggling to understand the correct syntax to set this up in VSCode. I am using Commandbox with the host-updater module so each dev site runs on port 443 with its own hostname. My hosts file would look similar to this:

127.127.0.30     test1.dev.local
127.127.0.31     test2.dev.local

In this setup, I'm unsure where to put what in the jvm args? Using the stock settings in the docs, but with my path to the jar, results in an error starting up the server:

agent library failed to init: instrument

I get closer when I replace "localhost" with my host file's hostname (e.g. "test1.dev.local"). The server starts and when I start the debug profile the "CALL STACK" panel fills up, but then I get the "unverified breakpoint" discussed in issue #18

I also tried replacing the cfHost (and corresponding "hostname" in the launch.json) to test1.dev.local, but suffer the exact same results.

It would probably help if I better understood what "localhost" is meant to refer to in the agentlib address as well as the jdwpHost and also what cfHost should refer to when NOT in a dockerized setting?

softwareCobbler commented 1 year ago

Being able to connect from VS Code, to the point where the callstack pane shows a listing of JVM thread names, indicates everything booted up fine, so that is a promising sign of life.

The unverified breakpoint issue could be a bug, but it could also be that the classfiles associated with the particular sourcefile in question hasn't been loaded by lucee yet, or that precompiled classfiles cached from previous non-debug server runs are being reused. The latter case sounds likely in a non-containerized setup. Deleting the class cache to force recompilations might be helpful; to troubleshoot, you could javap $someClassFile | grep -i "compiled from" some of them, if they don't have anything (or it's not an absolute path) then they are definitely from previous "non-debug" runs, and luceedebug can't do anything interesting with them.

Leftbower commented 1 year ago

I deleted all precompiled classfiles to no avail. I then did a fresh install of the server to make sure I didn't miss any and same issue.

One thing I noticed though is that when I try to get into the Lucee admin, it blows up wit this error:

lucee.runtime.exp.NativeException: luceedebug/coreinject/DebugManager
  at application_cfc$cf.newInstance(/admin/Application.cfc)
  at lucee.runtime.component.ComponentLoader.initComponent(ComponentLoader.java:632)
  at lucee.runtime.component.ComponentLoader._loadComponent(ComponentLoader.java:556)
  at lucee.runtime.component.ComponentLoader.loadComponent(ComponentLoader.java:448)
  at lucee.runtime.listener.ModernAppListener._onRequest(ModernAppListener.java:116)
  at lucee.runtime.listener.MixedAppListener.onRequest(MixedAppListener.java:44)
  at lucee.runtime.PageContextImpl.execute(PageContextImpl.java:2493)
  at lucee.runtime.PageContextImpl._execute(PageContextImpl.java:2478)
  at lucee.runtime.PageContextImpl.executeCFML(PageContextImpl.java:2449)
  at lucee.runtime.engine.Request.exe(Request.java:45)
  at lucee.runtime.engine.CFMLEngineImpl._service(CFMLEngineImpl.java:1216)
  at lucee.runtime.engine.CFMLEngineImpl.serviceCFML(CFMLEngineImpl.java:1162)
  at lucee.loader.engine.CFMLEngineWrapper.serviceCFML(CFMLEngineWrapper.java:97)
  at lucee.loader.servlet.CFMLServlet.service(CFMLServlet.java:51)
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
  at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
  at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
  at org.cfmlprojects.regexpathinfofilter.RegexPathInfoFilter.doFilter(RegexPathInfoFilter.java:47)
  at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67)
  at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
  at org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:176)
  at org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145)
  at org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92)
  at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:405)
  at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67)
  at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
  at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
  at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
  at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
  at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
  at runwar.undertow.SSLClientCertHeaderHandler.handleRequest(SSLClientCertHeaderHandler.java:144)
  at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
  at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117)
  at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
  at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
  at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
  at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
  at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
  at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
  at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
  at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
  at io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52)
  at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
  at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:275)
  at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:79)
  at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:134)
  at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:131)
  at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
  at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
  at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
  at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:255)
  at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:79)
  at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:100)
  at io.undertow.server.Connectors.executeRootHandler(Connectors.java:391)
  at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:852)
  at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
  at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2019)
  at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1558)
  at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1449)
  at org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1282)
  at java.base/java.lang.Thread.run(Thread.java:829)
 Caused by: java.lang.NoClassDefFoundError: luceedebug/coreinject/DebugManager
  ... 61 more
softwareCobbler commented 1 year ago

The dreaded NoClassDefFoundError. Some kind of classloader problem. Could you list your JDK and Lucee versions? Do you have any kind of bespoke classloading/OSGi setup?

Leftbower commented 1 year ago

Lucee 5.3.10+97 OpenJDK Runtime Environment Temurin-11.0.17+8 (build 11.0.17+8) No bespoke classloading/OSGi setup... even tried with a new site with just an index.cfm and get the above error when trying to load the Lucee admin.

softwareCobbler commented 1 year ago

Was able to repro and pushed a fix, if you do a fresh build it ought to be better. It seems that the admin portion of Lucee is its own isolated OSGi bundle and we weren't handling that properly.

Leftbower commented 1 year ago

OK, the new build fixed the Lucee admin OSGi error. Now just still have the unverified breakpoint issue. Updated extension to 2.0.3

softwareCobbler commented 1 year ago

As in, they just won't ever hit? Unverified in and of itself isn't bad, until you run the file and they still don't become verified. This could be a path mapping issue ... maybe a case (in)sensitivity thing ... you're on windows, yes?

Leftbower commented 1 year ago

Correct, they never become verified. I am on Windows.

My jvm args:

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=bh.dev.local:9999
-javaagent:c:/dev/luceedebug/luceedebug.jar=jdwpHost=bh.dev.local,jdwpPort=9999,cfHost=bh.dev.local,cfPort=10000,jarPath=c:/dev/luceedebug/luceedebug.jar

And my launch.json looks like this:

{
    "type": "cfml",
    "request": "attach",
    "name": "test",
    "hostName": "bh.dev.local",
    "port": 10000
}

My hosts file has this: 127.127.0.33 bh.dev.local

jamiejackson commented 1 year ago

This shouldn't affect your outcome, since you're already able to connect, but you may want to use this, instead, to simplify the JVM args:

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=localhost:9999
-javaagent:c:/dev/luceedebug/luceedebug.jar=jdwpHost=localhost,jdwpPort=9999,cfHost=bh.dev.local,cfPort=10000,jarPath=c:/dev/luceedebug/luceedebug.jar

@softwareCobbler may correct me if I'm wrong, but I don't think there's any reason a lay user should change address/jdwpHost from localhost, so consider that hostname as a literal. (It's for internal communication between the agent and JDWP, so no reason to tinker with it.)

I also had a member of my team (the only Windows user) who wasn't able to get things working. We put that on the shelf for a while, but I'm not sure we've gotten verification yet that luceedebug works on Windows.

I wonder whether the paths aren't matching based on case (as @softwareCobbler alluded to) and/or slash direction differences.

@Leftbower, I propose an experiment. Could you do the following?

Once you have that, we can try a pathTransforms mapping at the root level, specify a breakpoint in your root index.cfm, then go from there.

Leftbower commented 1 year ago

Created a new, blank site in Commandbox. Changed the above JVM to localhost as suggested. No change. Both the expandPath in index.cfm and the cd in Windows cmd are indentical (i.e. "C:\dev\apps\lbtest") I do not have pathTransforms setup in launch.json because - as per above test - I didn't believe they were needed?

jamiejackson commented 1 year ago

Thanks, @Leftbower.

Because those paths match (which isn't true of remote or containerized servers, of course), the pathTransforms is ostensibly unnecessary.

No luck with a breakpoint in that simple site's index.cfm, I suppose?

I wonder if the backslashes or colon are borking the mappings. Until WIndows support is troubleshot, I wonder if there's any hack you could try, like:

"pathTransforms": [
  {
    "idePrefix": "C:/dev/apps/lbtest",
    "serverPrefix": "C:/dev/apps/lbtest"
  },
]

Or something goofy like WSL paths.

Leftbower commented 1 year ago

Thanks for your help @jamiejackson.

Correct, no luck with the breakpoint in index.cfm. Added the pathTransform as suggested, but no luck there. I don't think it's a matter of casing as Windows is generally case insensitve, but furthermore all of my paths are lowercased, so there're no differences? I assume that the fact the agent jar is being found and loaded up proves that, right? (e.g. the CALL STACK panel is populated)

Perhaps we Windows users are just destined to dump() our way through debugging :-)

jamiejackson commented 1 year ago

Correct, no luck with the breakpoint in index.cfm.

Darn.

I don't think it's a matter of casing as Windows is generally case insensitive.

I also don't think it's a matter of case.

assume that the fact the agent jar is being found and loaded up proves that, right?

Right, because you're using the lowercase c and java doesn't seem to mind.

Perhaps we Windows users are just destined to dump() our way through debugging :-)

No way! You may just be the first Windows guinea pig. We'll get it sorted.

softwareCobbler commented 1 year ago

Just pushed some stuff to help debug path mapping issues. It looks like maybe there's some complications with how vscode sends out drive letters.

After connecting to the server, from the command pallet (I think pressing F1 brings it up), type "luceedebug show class and breakpoint info", it should look like: image

It will open an editor pane with info like the following

Breakpoints luceedebug has:
  (ide)    d:\lucee-express\lucee-express-5.4.0.23-SNAPSHOT\webapps\ROOT\index.cfm:2 (unbound)
  (server) d:\lucee-express\lucee-express-5.4.0.23-SNAPSHOT\webapps\ROOT\index.cfm:2 (unbound)

Files luceedebug knows about (all filenames are as the server sees them, and match against breakpoint 'server' paths):
  /admin/resources/menu.cfm
  ...snip...
  d:\lucee-express\lucee-express-5.4.0.23-snapshot\webapps\root\application.cfc
  d:\lucee-express\lucee-express-5.4.0.23-snapshot\webapps\root\index.cfm
  d:\lucee-express\lucee-express-5.4.0.23-snapshot\webapps\root\web-inf\lucee\context\application.cfc
  d:\lucee-express\lucee-express-5.4.0.23-snapshot\webapps\root\web-inf\lucee\context\component.cfc
  pageimpl.java

The trick is to get the paths (case-sensitively) to line up. In the above configuration, I couldn't hit index.cfm because "root" is not the same as "ROOT". I had to add a path transform like:

"pathTransforms": [
    {
        "idePrefix": "d:\\lucee-express\\lucee-express-5.4.0.23-SNAPSHOT\\webapps\\ROOT",
        "serverPrefix": "d:\\lucee-express\\lucee-express-5.4.0.23-snapshot\\webapps\\root"
    }
],

Of particular interest is that the editor offers a macro-like helper like "${workspaceRoot}" as shorthand, but it was saying that the workspace was D:\..., but then the inbuilt DAP server would push breakpoints with d:\..., so there's plenty of room for case mistakes.

jamiejackson commented 1 year ago

Nice addition! I've needed that kind of information a lot over the last couple weeks.

jamiejackson commented 1 year ago

I saw you made a canonicalization change last night. Was that related to this ticket?

I was just able to get things working on Windows, and I'm not sure if it's because of your change or not.

CommandBox server.json:

{
    "name":"lucee@5.3.10.97",
    "jvm":{
        "args":[
            "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=localhost:9999",
            "-javaagent:C:/Users/jamie/projects/luceedebug/luceedebug/build/libs/luceedebug.jar=jdwpHost=localhost,jdwpPort=9999,debugHost=0.0.0.0,debugPort=10000,jarPath=C:/Users/jamie/projects/luceedebug/luceedebug/build/libs/luceedebug.jar"
        ],
        "javaVersion":"openjdk11_jdk"
    },
    "app":{
        "cfengine":"lucee@5.3.10.97"
    }
}

VS Code launch.json:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "cfml",
            "request": "attach",
            "name": "Attach to server",
            "hostName": "localhost",
            "port": 10000
        }
    ]
}

Debug output:

Breakpoints luceedebug has:
  (ide)    c:\Users\jamie\projects\luceedebug\sample\index.cfm:5 (bound)
  (server) c:\users\jamie\projects\luceedebug\sample\index.cfm:5 (bound)

Files luceedebug knows about (all filenames are as the server sees them, and match against breakpoint 'server' paths):
  c:\users\jamie\.commandbox\server\7d0c5a764415367927375b99ef8f97d1-lucee@5.3.10.97\lucee-5.3.10.97\web-inf\lucee-server\context\library\function\writedump.cfm
  c:\users\jamie\.commandbox\server\7d0c5a764415367927375b99ef8f97d1-lucee@5.3.10.97\lucee-5.3.10.97\web-inf\lucee-server\context\library\tag\ajaximport.cfc
  c:\users\jamie\.commandbox\server\7d0c5a764415367927375b99ef8f97d1-lucee@5.3.10.97\lucee-5.3.10.97\web-inf\lucee-server\context\library\tag\ajaxproxy.cfc
  c:\users\jamie\.commandbox\server\7d0c5a764415367927375b99ef8f97d1-lucee@5.3.10.97\lucee-5.3.10.97\web-inf\lucee-server\context\library\tag\div.cfc
  c:\users\jamie\.commandbox\server\7d0c5a764415367927375b99ef8f97d1-lucee@5.3.10.97\lucee-5.3.10.97\web-inf\lucee-server\context\library\tag\dump.cfc
  c:\users\jamie\.commandbox\server\7d0c5a764415367927375b99ef8f97d1-lucee@5.3.10.97\lucee-5.3.10.97\web-inf\lucee-server\context\library\tag\layout.cfc
  c:\users\jamie\.commandbox\server\7d0c5a764415367927375b99ef8f97d1-lucee@5.3.10.97\lucee-5.3.10.97\web-inf\lucee-server\context\library\tag\layoutarea.cfc
  c:\users\jamie\.commandbox\server\7d0c5a764415367927375b99ef8f97d1-lucee@5.3.10.97\lucee-5.3.10.97\web-inf\lucee-server\context\library\tag\lucee\core\ajax\ajaxbase.cfc
  c:\users\jamie\.commandbox\server\7d0c5a764415367927375b99ef8f97d1-lucee@5.3.10.97\lucee-5.3.10.97\web-inf\lucee-server\context\library\tag\lucee\core\ajax\ajaxbinder.cfc
  c:\users\jamie\.commandbox\server\7d0c5a764415367927375b99ef8f97d1-lucee@5.3.10.97\lucee-5.3.10.97\web-inf\lucee-server\context\library\tag\lucee\core\ajax\ajaxproxyhelper.cfc
  c:\users\jamie\.commandbox\server\7d0c5a764415367927375b99ef8f97d1-lucee@5.3.10.97\lucee-5.3.10.97\web-inf\lucee-server\context\library\tag\map.cfc
  c:\users\jamie\.commandbox\server\7d0c5a764415367927375b99ef8f97d1-lucee@5.3.10.97\lucee-5.3.10.97\web-inf\lucee-server\context\library\tag\mapitem.cfc
  c:\users\jamie\.commandbox\server\7d0c5a764415367927375b99ef8f97d1-lucee@5.3.10.97\lucee-5.3.10.97\web-inf\lucee-server\context\library\tag\mediaplayer.cfc
  c:\users\jamie\.commandbox\server\7d0c5a764415367927375b99ef8f97d1-lucee@5.3.10.97\lucee-5.3.10.97\web-inf\lucee-server\context\library\tag\window.cfc
  c:\users\jamie\.commandbox\server\7d0c5a764415367927375b99ef8f97d1-lucee@5.3.10.97\lucee-5.3.10.97\web-inf\lucee-web\context\component.cfc
  c:\users\jamie\projects\luceedebug\sample\index.cfm
  cipage.java
  componentpage.java
  componentpageimpl.java
  pageimpl.java
jamiejackson commented 1 year ago

@Leftbower , @softwareCobbler confirmed that his recent commit addressed this kind of thing and I was able to debug on a Windows machine.

Please try again and report back with your debugging info if you're still having problems.

Leftbower commented 1 year ago

@jamiejackson, @softwareCobbler new update works - thanks so much for all of your efforts!