This post explains how to find the ax user that caused an AOS crash - before reaching this stage you need to first have captured a memory dump, and then set up WinDbg ready to do some analysis, we have posts which explain both of those steps:

Capturing memory dumps:

http://blogs.msdn.com/b/emeadaxsupport/archive/2010/05/12/possibilities-to-create-memory-dumps-from-crashing-processes.aspx

Setting up WinDbg:

 http://blogs.msdn.com/b/emeadaxsupport/archive/2011/04/10/setting-up-windbg-and-using-symbols.aspx

Once you have your memory dumps and have set up WinDbg, just open WinDbg, go to file- open a crash dump, and open the *.dmp file you created. Then there are a few basic commands you can run in WinDbg which will allow you to identify the AX user associated with the thread that crashed an AOS (for an AOS crash dump).

!tls -1

The above command will show all thread local storage locations, you need to copy each location one at at a time and then run:

In AX2009 64 bit:
dq 0000000007ca5290+60

In AX4 32 bit:

dd 01b52708+60

You need to add the “+60” to the location copied from the thread local storage. This will return some further memory locations, take the first location and then run:

In AX2009 64 bit:

du 00000000`2ec1e6a0+15c 

In AX4 32 bit:

du 0x0b6bf460+e4

You need to add the “+15c” or “+e4” to the end of the location. This should return the user’s name, if it doesn’t then go back to the results from !tls and take the next location and run the dq and du commands again. In addition to the user you can also add other offsets to the end of the location to find some other variables:

In AX2009 64 bit:
+258 = current AX company
+2fc = name of user’s client machine

In AX4 32 bit:
+140 = current AX company
+1a8 = name of user’s client machine

Here is an example of those commands being run in WinDbg for an AOS crash dump. Note that the example uses AX2009 64 bit, for AX4 32 bit the memory locations will only be 8 digits long and the offsets we add on to them are different (listed in the detail above) but otherwise it is the same process.


0:010> !tls -1
TLS slots on thread: 1138.c3c
0x0000 : 0000000000000000
0x0001 : 00000000011598c0
0x0002 : 0000000000000000
0x0003 : 0000000000000000
0x0004 : 0000000000000000
0x0005 : 0000000000000000
0x0006 : 0000000000000000
0x0007 : 0000000000000000
0x0008 : 0000000000000000
0x0009 : 0000000000000000
0x000a : 0000000000000000
0x000b : 0000000000000000
0x000c : 0000000000000000
0x000d : 0000000000000000
0x000e : 0000000000000000
0x000f : 0000000000000000
0x0010 : 0000000000000000
0x0011 : 0000000000000000
0x0012 : 0000000000000000
0x0013 : 0000000000000000
0x0014 : 0000000000000000
0x0015 : 0000000000000000
0x0016 : 0000000000000000
0x0017 : 00000000010f5df0
0x0018 : 0000000000000000
0x0019 : 0000000000000000
0x001a : 0000000003b21bf0
0x001b : 0000000001149b30
0x001c : 0000000000000000
0x001d : 0000000000000000
0x001e : 0000000000000000
0x001f : 0000000000000000
0x0020 : 0000000000000000
0x0021 : 0000000000000000
0x0022 : da64d4b4b83bec96
0x0023 : 0000000000000000
0x0024 : 0000000000000000
0x0025 : 0000000000000000
0x0026 : 0000000000000000
0x0027 : 0000000000000000
0x0028 : 0000000001123a80
0x0029 : 0000000000000000
0x0040 : 0000000000000000

0:010> dq 0000000003b21bf0+60
00000000`03b21c50  00000000`01d373c0 00000000`01165f30
00000000`03b21c60  00470000`00000000 00000000`00000000
00000000`03b21c70  000001bc`00000000 00000000`0042e440
00000000`03b21c80  00780077`00320001 8f0000a2`2884a6e6
00000000`03b21c90  07060504`03020100 0f0e0d0c`0b0a0908
00000000`03b21ca0  17161514`13121110 2221201f`1b1a19dd
00000000`03b21cb0  2a292827`26252423 3433302f`2e2d2c2b
00000000`03b21cc0  3c3b3a39`38373635 4847ce41`403f3e3d

0:010> du 00000000`01d373c0+15c
00000000`01d3751c  "Admin"

0:010> du 00000000`01d373c0+258
00000000`01d37618  "dat"

0:010> du 00000000`01d373c0+2fc
00000000`01d376bc  "TABELLDEV"

What we are actually is doing with these commands is  - we know that at an offset of 60 from one of the thread local storage locations will be the user’s session block, then once we find the session block at an offset of 15c from that will be the username variable.

You can apply the exact same technique also if your AOS is running high CPU, or hanging, just take a memory dumps from it and run the same commands as described above on each thread (you can switch to each thread from "View->processes and threads" in WinDbg).

Next you might want to find out what X++ the user was running at the time, see this post:

http://blogs.msdn.com/b/emeadaxsupport/archive/2011/04/10/finding-the-x-call-stack-that-caused-a-crash.aspx

There is an easier way to do this for AX2009 x64 - we have created scripts to automate the process in WinDbg - see this post:

http://blogs.msdn.com/b/emeadaxsupport/archive/2011/04/10/finding-the-ax-user-and-the-x-call-stack-from-a-memory-dump-the-easy-way.aspx

--author: Tariq Bell
--editor: Tariq Bell
--date: 10/04/2011