This is an extension of a series of articles I wrote some time ago for AX2009 - this just brings it up to date to do it with AX2012. This enables you to take a snapshot of your AOS and see what's running on it - call stacks and user sessions. If you're not familiar with analysing memory dumps then check this post first, it explains how to get set up etc..
http://blogs.msdn.com/b/emeadaxsupport/archive/2011/04/10/so-your-aos-crashed-is-hanging-or-you-just-want-to-see-what-it-s-doing.aspx
Here’s a run through finding the X++ call stack and the AX user for AX2012. When you open the dump in WinDbg, run the command “kv” to see the call stack, you’ll see output like this:
0:007> kvChild-SP RetAddr : Args to Child : Call Site00000000`040b4c40 00000001`406ffc75 : ffffffff`fffffffe 00000000`00000001 00000000`00000001 00000001`403bc721 : Ax32Serv!cqlCursor::connection+0x1400000000`040b4c70 00000001`406ffec6 : 00000000`1e84a7a0 00000000`1e56c720 00000000`00000001 00000000`040b50b0 : Ax32Serv!cqlCursor::DropTempDBTableInstance+0x7500000000`040b4eb0 00000001`403b9771 : 00000000`00000001 00000000`00000001 00000000`040b50b0 00000001`40437346 : Ax32Serv!cqlCursor::Dispose+0x2600000000`040b4ee0 00000001`403bc714 : 00000000`1e56c720 00000001`404351f0 00000000`1ac20d28 00000001`407d8d4b : Ax32Serv!cqlCursor::~cqlCursor+0x10100000000`040b4f60 00000001`40369815 : 00000000`1e56c720 00000000`194c0d00 00000000`1b912800 00000001`407d8ead : Ax32Serv!cqlCursor::`vector deleting destructor'+0x1400000000`040b4f90 00000001`403801d5 : 00000000`1e56c720 00000000`040b6100 00000000`1e0bfe40 00000001`4058067b : Ax32Serv!cqlCursor::freeRef_AdHoc+0x3500000000`040b4fc0 00000001`40582026 : 00000000`040b50b0 00000000`00000006 00000000`040b51a0 00000001`4049e2b1 : Ax32Serv!assignCursor+0x7500000000`040b4ff0 00000001`40582d95 : 00000000`000000c8 00000000`00000000 00000000`040b51b0 00000000`040b51a0 : Ax32Serv!CQLFreeVars+0x11600000000`040b5040 00000001`40430c43 : 00000000`1b912800 00000000`00000005 00000000`00000005 00000000`00000005 : Ax32Serv!interpret::CQLEvalProc+0x71500000000`040b52c0 00000001`4043370a : 00000000`03720cc8 000007fe`8f8fc3a1 00000000`18ebfb90 00000000`1b913940 : Ax32Serv!interpret::doEval+0x3e300000000`040b55c0 00000001`40434517 : 00000000`18ebfb00 00000000`1e522736 00000000`1e665e60 00000000`00930200 : Ax32Serv!interpret::evalFunc+0x2ca00000000`040b56a0 00000001`404351f0 : ffffffff`fffffffe 00000001`4065167a ffffffff`fffffffe 00000000`040b6190 : Ax32Serv!interpret::xal_eval_func+0xc7700000000`040b6030 00000001`4049e127 : 00000000`1b912800 00000000`1b912800 00000000`040b6190 00000000`040b7000 : Ax32Serv!interpret::xal_eval_id+0xd000000000`040b6070 00000001`4049e268 : 00000000`1b912800 00000000`00000000 00000000`1b912800 00000000`040b70e0 : Ax32Serv!interpret::evalLoop+0x16700000000`040b60d0 00000001`40582b53 : 00000000`00000001 00000000`00000000 00000000`040b6180 00000000`00000000 : Ax32Serv!interpret::eval+0x58
For the X++ stack we care about the ax32serv!interpret::evalfunc frames. Let’s take the evalfunc line nearest to the top of the stack as an example:
00000000`040b55c0 00000001`40434517 : 00000000`18ebfb00 00000000`1e522736 00000000`1e665e60 00000000`00930200 : Ax32Serv!interpret::evalFunc+0x2ca
Take the third column shown above in green and then run “du <the location>” as shown below. This gives you the X++ method name:
0:007> du 00000000`1e52273600000000`1e522736 "saveBudgetCheckResultErrorWarnin"00000000`1e522776 "gDetails"
Now to find the class, take the first column in that line and run “dd <the location>” as shown below, this gives you the class ID in hexadecimal:
0:007> dd 00000000`040b55c0+4400000000`040b5604 000f554e 1b913940 00000000 0000000000000000`040b5614 00000000 00000000 00000000 0000000000000000`040b5624 00000000 00000000 00000000 0000000000000000`040b5634 00000000 00000000 00000000 0000000000000000`040b5644 00000000 ffffff00 00000000 1e665e6000000000`040b5654 00000000 fffffffe ffffffff 0000000100000000`040b5664 00000000 1b913940 00000000 1e52273600000000`040b5674 00000000 1b912800 00000000 040b7000
To find out what the class name is from this, first you can convert the ID to decimal, just run “? <the ID>”
0:007> ? 000f554e Evaluate expression: 1004878 = 00000000`000f554e
Above 1004878 is the classID, you can find the class name in an X++ job, like this:
info(classid2name(1004878));
Now for you to find the AX user you run the command “!tls -1”, this is following the instructions from this post but I am giving you different offsets here:
0:007> !tls -1TLS slots on thread: 2ed4.176c0x0000 : 00000000000000000x0001 : 00000000000000000x0002 : 00000000000000000x0003 : 00000000000000000x0004 : 00000000000000000x0005 : 00000000000000000x0006 : 00000000000000000x0007 : 0000000000e299000x0008 : 00000000000000000x0009 : 00000000000000000x000a : 00000000000000000x000b : 00000000000000000x000c : 00000000000000000x000d : 00000000000000000x000e : 00000000000000000x000f : 00000000000000000x0010 : 00000000000000000x0011 : 00000000000000000x0012 : 00000000000000000x0013 : 00000000000000000x0014 : 00000000000000000x0015 : 00000000000000000x0016 : 00000000000000000x0017 : 00000000005c70f00x0018 : 00000000000000000x0019 : 00000000000000000x001a : 00000000000000000x001b : 00000000000000000x001c : 00000000000000000x001d : 00000000000000000x001e : 000000000f2442a00x001f : 00000000005daca00x0020 : 000000000f177e600x0021 : 00000000018292100x0022 : 000000001916a6000x0023 : 00000000000000000x0024 : 00000000000000000x0025 : 00000000000000000x0026 : 0000000000000000…<cut short for display>…
Then take the location above and run the command below, this is to find the user’s session block (the class instance that represents their session). Note that in this example I’ve picked the 0x0022 entry in the list that came from the !tls -1, this won’t always be the same entry – unfortunately with public symbols (i.e. outside of Microsoft) you can’t do the !tls part more accurately, you’ll need to try each entry and has a value other than zero and you’ll know if it’s right in the next step if you see a username at 17c.
0:007> dq 000000001916a600+6800000000`1916a668 00000000`194c0d00 00000000`0f26f79000000000`1916a678 00000000`00000000 00000000`0000000000000000`1916a688 00001d5b`00000000 00000001`3feebdc000000000`1916a698 00000000`00000001 00000000`0000000000000000`1916a6a8 74007300`69004c00 65006700`6100500000000000`1916a6b8 fff30002`00000000 00073ea8`0e01000000000000`1916a6c8 02000000`00010001 00000000`000001ff00000000`1916a6d8 10a8effc`a833b3d8 00000000`19152760
Then take the location in green above, and at various offsets you’ll find information about the user as shown below.
User’s AX username:0:007> du 00000000`194c0d00+17c00000000`194c0e7c "kkidder"
User’s AX company:0:007> du 00000000`194c0d00+29800000000`194c0f98 "dat"
User’s client machine name:0:007> du 00000000`194c0d00+57c00000000`194c127c "eeax2008"
Happy debugging!
/Tariq Bell