Re: Learning ASM
Paul Bell <[email protected]> Thu, 11 Oct 2018 07:49:06 -0400
| Newsgroups | gmane.comp.java.objectweb.asm |
|---|---|
| Message-ID | <CA+ttMd_8mxc9qvYxmQRaqbgxSUFc2iEK_1Uzu2LWB-R_2aAopQ@mail.gmail.com> |
This is a multi-part message in MIME format... ------------=_1539258564-16155-1 Content-Type: multipart/alternative; boundary="0000000000008763ab0577f28ffa" --0000000000008763ab0577f28ffa Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hello again, Two questions, one old, one new, both quite specific: In the INVOKEVIRTUAL example above, how can my Java agent code obtain the 'x' variable (at stack location 1), the 'hello' argument (at stack location 0) and the fully qualified method name (java/lang/Object/equals)? Suppose one wanted to *single-step* from one instruction to another (much in the manner of Eclipse debug F5). Based on what I've read I assume that there is NOT a 1-1 relationship between Java source "instructions" and the resulting bytecode, i.e., unlike X86 or mainframe assembly language, a single source statement may generate *several *bytecode instructions. For example, adding 2 integers might require pushing both onto the stack, adding them, pushing their sum onto the stack, and then storing that sum back into a variable. I suppose that this requires several bytecode instructions. From a debugging perspective I am not interested in single-stepping through each of these several bytecode instructions. Rather, with an eye to the corresponding source code, I'd like to "hook" the first and last of these instructions. Is there any way to know what bytecode instructions correspond to the first and last bytecode instructions generated for a single source statement? Thank you. On Wed, Oct 3, 2018 at 9:09 AM <[email protected]> wrote: > > > ------------------------------ > > *De: *"Paul Bell" <[email protected]> > *=C3=80: *"Remi Forax" <[email protected]> > *Cc: *"asm" <[email protected]> > *Envoy=C3=A9: *Mercredi 3 Octobre 2018 12:58:09 > *Objet: *Re: [asm] Learning ASM > > Hi R=C3=A9mi, > > Thank you for getting back to me about this and apologies for my tardy > reply. > > When you say "...if you put a *breakpoint *in one of the > MethodVisitor.visit*Insn", are you talking about a breakpoint instruction > (0xCA, I think)? If so, it's my understanding that, absent a JVMTI agent, > or the Eclipse debug perspective, this won't work. Please note that I am > using only the -javaagent from the command line, i.e., no Eclipse, no JVM= TI > agent. It would be great if a breakpoint "event" (to use the JVMTI > terminology) could be caught by ASM, but I don't think that's possible > (again, I know very little about ASM). > > > no, i was talking about debugging the code of the agent itself, at least > the part that calls ASM. > > > With respect to intercepting INVOKEVIRTUAL calls, how can my Java agent > code obtain the name of the method being called by INVOKEVIRTUAL? This > example, taken from one of the jasmin pages, shows Java code that calls > method "equals" on some object and the resulting bytecode: > > * Object x; ... x.equals("hello")* > > aload_1 ; push local variable 1 (i.e. 'x') onto stack > ldc "hello" ; push the string "hello" onto stack > > ; invoke the equals method > invokevirtual java/lang/Object/equals(Ljava/lang/Object;)Z > ; the boolean result is now on the stack > > > How can my Java agent code obtain the 'x' variable (at stack location 1),= the 'hello' argument (at stack location 0), and the fully-qualified method= name (java/lang/Object/equals)? > > > The agent can intercept the bytecode as an array of bytes, then you can > use ASM to read the bytecode using the ClassReader, transform it into a > ClassWriter and regenerate a byte new byte array with the code you want > inserted whenever you want. > An agent has no API to directly influence the bytecode executed by a VM > because most VMs do consume the bytecode directly but rewrite it to a form > that suit them more. > > The agent API is in java.lang.instrument > > https://docs.oracle.com/en/java/javase/11/docs/api/java.instrument/java/l= ang/instrument/package-summary.html > > An agent can change the bytecode by registrering a ClassTransformer using > > https://docs.oracle.com/en/java/javase/11/docs/api/java.instrument/java/l= ang/instrument/Instrumentation.html#addTransformer(java.lang.instrument.Cla= ssFileTransformer,boolean) > > And how to rewrite the bytecode using the a ClassReader ClassVisitor > ClassWriter is described in the guide, i have linked in my previous messa= ge. > > Thanks again! > > -Paul > > > R=C3=A9mi > > > On Tue, Oct 2, 2018 at 9:16 AM Remi Forax <[email protected]> wrote: > >> Hi Paul, >> >> ------------------------------ >> >> *De: *"Paul Bell" <[email protected]> >> *=C3=80: *"asm" <[email protected]> >> *Envoy=C3=A9: *Mardi 2 Octobre 2018 14:40:18 >> *Objet: *[asm] Learning ASM >> >> Hello, >> >> I am just now learning ASM and this is my first post. >> >> I've cobbled together a working Java agent that uses ASM to modify >> methods in the code I want to trace/debug/monitor. Specifically, I modify >> static methods, instance methods, and constructors. These modifications, >> inserted at methods' entry, call into my tracing program. >> >> There's an awful lot I don't know about ASM and I would be grateful for >> help with a few things (for now): >> >> - How can ASM be used to "single step" through program execution? By >> "single step" I mean similar to the Eclipse debug breakpoint facility= where >> pressing F5 allows you to step into the next instruction. >> >> >> ASM do bytecode transformation by transforming the bytecode in a series >> of visitor calls, if you put a breakpoint in one of the >> MethodVisitor.visit*Insn you override, you will see the method been call= ed >> for each bytecode managed by this method. >> >> >> - How can I "hook" INVOKEVIRTUAL calls? I would like to know when a >> method calls another method. >> >> >> override MethodVisitor.visitMethodInsn et check if the opcode is >> Opcodes.INVOKEVIRTUAL >> >> >> - What are "labels" and how are they used? >> >> >> labels are target of gotos, catch blocks, etc. >> You can create one with new Label(), insert it in the bytecode flow with >> visitLabel() and use it as parameter of any visit* methods. >> >> Eric has written a nice guide that explain how to use ASM and how ASM >> works under the cover, >> https://asm.ow2.io/asm4-guide.pdf >> >> >> Thanks very much. >> >> -Paul >> >> >> R=C3=A9mi >> >> > --0000000000008763ab0577f28ffa Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">Hello again,<div><br></div><div>Two questions, one old, on= e new, both quite specific:</div><div><br></div><div>In the INVOKEVIRTUAL e= xample above, how can my Java agent code obtain the 'x' variable (a= t stack location 1), the 'hello' argument (at stack location 0) and= the fully qualified method name (java/lang/Object/equals)<font color=3D"#0= 00000" face=3D"arial, helvetica, sans-serif"><span style=3D"font-size:16px;= white-space:pre-wrap">?</span></font></div><div><font color=3D"#000000" fac= e=3D"arial, helvetica, sans-serif"><span style=3D"font-size:16px;white-spac= e:pre-wrap"><br></span></font></div><div><font color=3D"#000000" face=3D"ar= ial, helvetica, sans-serif"><span style=3D"white-space:pre-wrap">Suppose on= e wanted to <i style=3D"">single-step</i> from one instruction to another (= much in the manner of Eclipse debug F5). Based on what I've read I assu= me that there is NOT a 1-1 relationship between Java source "instructi= ons" and the resulting bytecode, i.e., unlike X86 or mainframe assembl= y language, a single source statement may generate <i style=3D"">several </= i>bytecode instructions. For example, adding 2 integers might require pushi= ng both onto the stack, adding them, pushing their sum onto the stack, and = then storing that sum back into a variable. I suppose that this requires se= veral bytecode instructions. From a debugging perspective I am not interest= ed in single-stepping through each of these several bytecode instructions. = Rather, with an eye to the corresponding source code, I'd like to "= ;hook" the first and last of these instructions. Is there any way to k= now what bytecode instructions correspond to the first and last bytecode in= structions generated for a single source statement?<span style=3D"font-size= :16px"><br></span></span></font></div><div><font color=3D"#000000" face=3D"= arial, helvetica, sans-serif"><span style=3D"font-size:16px;white-space:pre= -wrap"><br></span></font></div><div><font color=3D"#000000" face=3D"arial, = helvetica, sans-serif"><span style=3D"font-size:16px;white-space:pre-wrap">= Thank you.</span></font></div></div><br><div class=3D"gmail_quote"><div dir= =3D"ltr">On Wed, Oct 3, 2018 at 9:09 AM <<a href=3D"mailto:forax@univ-ml= v.fr">[email protected]</a>> wrote:<br></div><blockquote class=3D"gmail_= quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1= ex"><div><div style=3D"font-family:arial,helvetica,sans-serif;font-size:12p= t;color:#000000"><div><br></div><div><br></div><hr id=3D"m_-431825538719312= 7284zwchr"><div><blockquote style=3D"border-left:2px solid #1010ff;margin-l= eft:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;te= xt-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt"><= b>De: </b>"Paul Bell" <<a href=3D"mailto:[email protected]" t= arget=3D"_blank">[email protected]</a>><br><b>=C3=80: </b>"Remi Fo= rax" <<a href=3D"mailto:[email protected]" target=3D"_blank">forax@= univ-mlv.fr</a>><br><b>Cc: </b>"asm" <<a href=3D"mailto:asm= @ow2.org" target=3D"_blank">[email protected]</a>><br><b>Envoy=C3=A9: </b>Merc= redi 3 Octobre 2018 12:58:09<br><b>Objet: </b>Re: [asm] Learning ASM<br></b= lockquote></div><div><blockquote style=3D"border-left:2px solid #1010ff;mar= gin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:norm= al;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12= pt"><div dir=3D"ltr">Hi=C2=A0 <span style=3D"color:rgb(0,0,0);font-family:arial,helvetica,sans-serif">R= =C3=A9mi,</span><div><span style=3D"color:rgb(0,0,0);font-family:arial,helv= etica,sans-serif"><br></span></div><div><span style=3D"color:rgb(0,0,0);fon= t-family:arial,helvetica,sans-serif">Thank you for getting back to me about= this and apologies for my tardy reply.</span></div><div><span style=3D"col= or:rgb(0,0,0);font-family:arial,helvetica,sans-serif"><br></span></div><div= ><span style=3D"color:rgb(0,0,0);font-family:arial,helvetica,sans-serif">Wh= en you say "...if you put a <i>breakpoint </i>in one of the MethodVisi= tor.visit*Insn", are you talking about a breakpoint instruction (0xCA,= I think)? If so, it's my understanding that, absent a JVMTI agent, or = the Eclipse debug perspective, this won't work. Please note that I am u= sing only the -javaagent from the command line, i.e., no Eclipse, no JVMTI = agent. It would be great if a breakpoint "event" (to use the JVMT= I terminology) could be caught by ASM, but I don't think that's pos= sible (again, I know very little about ASM).</span></div></div></blockquote= ><div><br></div><div>no, i was talking about debugging the code of the agen= t itself, at least the part that calls ASM.<br></div><div><br></div><blockq= uote style=3D"border-left:2px solid #1010ff;margin-left:5px;padding-left:5p= x;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font= -family:Helvetica,Arial,sans-serif;font-size:12pt"><div dir=3D"ltr"><div><s= pan style=3D"color:rgb(0,0,0);font-family:arial,helvetica,sans-serif"><br><= /span></div><div><span style=3D"color:rgb(0,0,0);font-family:arial,helvetic= a,sans-serif">With respect to intercepting INVOKEVIRTUAL calls, how can my = Java agent code obtain the name of the method being called by INVOKEVIRTUAL= ? This example, taken from one of the jasmin pages, shows Java code that ca= lls method "equals" on some object and the resulting bytecode:</s= pan></div><div><b style=3D"color:rgb(0,0,0);font-family:"Times New Rom= an";font-size:medium"><pre><font size=3D"-1"> Object x; ... x.equals("hello")</font></pre></b></div><div><span style=3D"c= olor:rgb(0,0,0);font-family:arial,helvetica,sans-serif"><br></span></div><d= iv><span style=3D"color:rgb(0,0,0)"><pre style=3D"font-weight:bold;font-siz= e:medium;font-family:"Times New Roman""><font size=3D"-1"> alo= ad_1 ; push local variable 1 (i.e. 'x') onto stack ldc "hello" ; push the string "hello" onto stack ; invoke the equals method invokevirtual java/lang/Object/equals(Ljava/lang/Object;)Z ; the boolean result is now on the stack</font></pre><pre style=3D"font= -weight:bold;font-size:medium;font-family:"Times New Roman""><fon= t size=3D"-1"><br></font></pre><pre><font face=3D"arial, helvetica, sans-se= rif">How can my Java agent code obtain the 'x' variable (at stack l= ocation 1), the 'hello' argument (at stack location 0), and the ful= ly-qualified method name (java/lang/Object/equals)?</font></pre></span></di= v></div></blockquote><div><br></div><div>The agent can intercept the byteco= de as an array of bytes, then you can use ASM to read the bytecode using th= e ClassReader, transform it into a ClassWriter and regenerate a byte new by= te array with the code you want inserted whenever you want.<br></div><div>A= n agent has no API to directly influence the bytecode executed by a VM beca= use most VMs do consume the bytecode directly but rewrite it to a form that= suit them more.<br></div><div><br></div><div>The agent API is in java.lang= .instrument<br></div><div><a href=3D"https://docs.oracle.com/en/java/javase= /11/docs/api/java.instrument/java/lang/instrument/package-summary.html" tar= get=3D"_blank">https://docs.oracle.com/en/java/javase/11/docs/api/java.inst= rument/java/lang/instrument/package-summary.html</a><br></div><div><br></di= v><div>An agent can change the bytecode by registrering a ClassTransformer = using<br></div><div><a href=3D"https://docs.oracle.com/en/java/javase/11/do= cs/api/java.instrument/java/lang/instrument/Instrumentation.html#addTransfo= rmer(java.lang.instrument.ClassFileTransformer,boolean)" target=3D"_blank">= https://docs.oracle.com/en/java/javase/11/docs/api/java.instrument/java/lan= g/instrument/Instrumentation.html#addTransformer(java.lang.instrument.Class= FileTransformer,boolean)</a><br></div><div><br></div><div>And how to rewrit= e the bytecode using the a ClassReader ClassVisitor ClassWriter is describe= d in the guide, i have linked in my previous message.<br></div><div><br></d= iv><blockquote style=3D"border-left:2px solid #1010ff;margin-left:5px;paddi= ng-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration= :none;font-family:Helvetica,Arial,sans-serif;font-size:12pt"><div dir=3D"lt= r"><div><span style=3D"color:rgb(0,0,0)"><pre><font face=3D"arial, helvetic= a, sans-serif">Thanks again!</font></pre><pre><font face=3D"arial, helvetic= a, sans-serif">-Paul</font></pre></span></div></div></blockquote><div><br><= /div><div>R=C3=A9mi<br></div><div><br></div><blockquote style=3D"border-lef= t:2px solid #1010ff;margin-left:5px;padding-left:5px;color:#000;font-weight= :normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,= sans-serif;font-size:12pt"><br><div class=3D"gmail_quote"><div dir=3D"ltr">= On Tue, Oct 2, 2018 at 9:16 AM Remi Forax <<a href=3D"mailto:forax@univ-= mlv.fr" target=3D"_blank">[email protected]</a>> wrote:<br></div><blockq= uote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc = solid;padding-left:1ex"><div><div style=3D"font-family:arial,helvetica,sans= -serif;font-size:12pt;color:#000000"><div>Hi Paul,<br></div><br><hr id=3D"m= _-4318255387193127284m_-8970503987493700044zwchr"><div><blockquote style=3D= "border-left:2px solid #1010ff;margin-left:5px;padding-left:5px;color:#000;= font-weight:normal;font-style:normal;text-decoration:none;font-family:Helve= tica,Arial,sans-serif;font-size:12pt"><b>De: </b>"Paul Bell" <= <a href=3D"mailto:[email protected]" target=3D"_blank">[email protected]<= /a>><br><b>=C3=80: </b>"asm" <<a href=3D"mailto:[email protected]= " target=3D"_blank">[email protected]</a>><br><b>Envoy=C3=A9: </b>Mardi 2 Octo= bre 2018 14:40:18<br><b>Objet: </b>[asm] Learning ASM<br></blockquote></div= ><div><blockquote style=3D"border-left:2px solid #1010ff;margin-left:5px;pa= dding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decorat= ion:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt"><div dir=3D= "ltr"><div dir=3D"ltr">Hello,<br></div><br><div>I am just now learning ASM = and this is my first post.</div><br><div>I've cobbled together a workin= g Java agent that uses ASM to modify methods in the code I want to trace/de= bug/monitor. Specifically, I modify static methods, instance methods, and c= onstructors. These modifications, inserted at methods' entry, call into= my tracing program.</div><br><div>There's an awful lot I don't kno= w about ASM and I would be grateful for help with a few things (for now):</= div><div><ul><li>How can ASM be used to "single step" through pro= gram execution? By "single step" I mean similar to the Eclipse de= bug breakpoint facility where pressing F5 allows you to step into the next = instruction.</li></ul></div></div></blockquote><br><div>ASM do bytecode tra= nsformation by transforming the bytecode in a series of visitor calls, if y= ou put a breakpoint in one of the MethodVisitor.visit*Insn you override, yo= u will see the method been called for each bytecode managed by this method.= =C2=A0 <br></div><br><blockquote style=3D"border-left:2px solid #1010ff;mar= gin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:norm= al;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12= pt"><div dir=3D"ltr"><div><ul><li>How can I "hook" INVOKEVIRTUAL = calls? I would like to know when a method calls another method.</li></ul></= div></div></blockquote><br><div>override MethodVisitor.visitMethodInsn et c= heck if the opcode is Opcodes.INVOKEVIRTUAL<br></div><br><blockquote style= =3D"border-left:2px solid #1010ff;margin-left:5px;padding-left:5px;color:#0= 00;font-weight:normal;font-style:normal;text-decoration:none;font-family:He= lvetica,Arial,sans-serif;font-size:12pt"><div dir=3D"ltr"><div><ul><li>What= are "labels" and how are they used?</li></ul></div></div></block= quote><br><div>labels are target of gotos, catch blocks, etc.<br></div><div= >You can create one with new Label(), insert it in the bytecode flow with v= isitLabel() and use it as parameter of any visit* methods.<br></div><br><di= v>Eric has written a nice guide that explain how to use ASM and how ASM wor= ks under the cover,<br></div><div><a href=3D"https://asm.ow2.io/asm4-guide.= pdf" target=3D"_blank">https://asm.ow2.io/asm4-guide.pdf</a><br></div><br><= br><blockquote style=3D"border-left:2px solid #1010ff;margin-left:5px;paddi= ng-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration= :none;font-family:Helvetica,Arial,sans-serif;font-size:12pt"><div dir=3D"lt= r"><div>Thanks very much.</div><br><div>-Paul</div></div></blockquote><br><= div>R=C3=A9mi<br></div><br> </div></div></div></blockquote></div><br></blockquote></div></div></div></b= lockquote></div> --0000000000008763ab0577f28ffa-- ------------=_1539258564-16155-1 Content-Type: text/plain; charset="UTF-8" Content-Disposition: inline Content-Transfer-Encoding: 8bit -- You receive this message as a subscriber of the [email protected] mailing list. To unsubscribe: mailto:[email protected] For general help: mailto:[email protected]?subject=help OW2 mailing lists service home page: http://www.ow2.org/wws ------------=_1539258564-16155-1--