<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Sue Loh's blog : Debugging, Kernel &amp; misc. File System issues</title><link>http://blogs.msdn.com/sloh/archive/tags/Debugging_2C00_+Kernel+_2600_+misc.+File+System+issues/default.aspx</link><description>Tags: Debugging, Kernel &amp; misc. File System issues</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Windows CE eHow-tos and Tutorials!  WOW!!</title><link>http://blogs.msdn.com/sloh/archive/2005/05/25/421840.aspx</link><pubDate>Wed, 25 May 2005 21:49:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:421840</guid><dc:creator>sloh</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/sloh/comments/421840.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sloh/commentrss.aspx?PostID=421840</wfw:commentRss><description>&lt;P&gt;I saw a blip of this at MEDC, and just checked it out myself.&amp;nbsp; How cool!&amp;nbsp; It's like a DevCon for all to share!&lt;/P&gt;
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/embedded/getstart/basics/tutorialsce/default.aspx"&gt;http://msdn.microsoft.com/embedded/getstart/basics/tutorialsce/default.aspx&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Most of it is pretty basic stuff,&amp;nbsp;but if you're new to Windows CE, you should check&amp;nbsp;some of these&amp;nbsp;out!&amp;nbsp; (If you are new to performance tools like Remote Kernel Tracker which I've been posting about, take a look at the&amp;nbsp;&lt;A&gt;Microsoft Windows CE 5.0 Advanced Lab&lt;/A&gt;&amp;nbsp;that's on that site.)&lt;/P&gt;
&lt;P&gt;Sue&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=421840" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sloh/archive/tags/CE+Performance+Tools/default.aspx">CE Performance Tools</category><category domain="http://blogs.msdn.com/sloh/archive/tags/Debugging_2C00_+Kernel+_2600_+misc.+File+System+issues/default.aspx">Debugging, Kernel &amp; misc. File System issues</category></item><item><title>Using RAM over 512MB</title><link>http://blogs.msdn.com/sloh/archive/2005/05/25/421750.aspx</link><pubDate>Wed, 25 May 2005 18:23:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:421750</guid><dc:creator>sloh</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/sloh/comments/421750.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sloh/commentrss.aspx?PostID=421750</wfw:commentRss><description>&lt;P&gt;&lt;STRONG&gt;Q:&lt;/STRONG&gt; &lt;FONT size=2&gt;I can use only 512MB of RAM from&amp;nbsp;my device. How can I address the remaining RAM ? &lt;a href="http://blogs.msdn.com/sloh/archive/2004/09/09/227599.aspx"&gt;On one of your posts&lt;/A&gt; you said that there is a way to go with more that 512 MB RAM. Can you help me on this issue?&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;STRONG&gt;A:&lt;/STRONG&gt;&amp;nbsp;Windows CE can't address more than 512MB.&amp;nbsp; There's no way to make the OS use it the way it uses other RAM.&amp;nbsp; OEMAddressTable, OEMGetExtensionDRAM&amp;nbsp;and OEMEnumExtensionDRAM are all limited to 512MB.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;The only thing you can do is write applications that specifically know about the extra memory.&amp;nbsp; They can use&amp;nbsp;&lt;FONT size=2&gt;VirtualAlloc with address 0 to reserve some virtual address space, and then use VirtualCopy with the PAGE_PHYSICAL to map the physical memory above 512MB into the virtual address space.&amp;nbsp; In this manner the application can use the additional RAM. &lt;/FONT&gt;&amp;nbsp;&lt;FONT size=2&gt;But the memory won't be used by the system the way other memory is.&amp;nbsp; It won't go into the pool that's used for general operation; other applications won't ever get that memory.&amp;nbsp; Your system could use up all of the first 512MB and then "run out of memory" because it can't use the other 512MB.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;If your device&amp;nbsp;needs a lot of resources like this, you might want to look into Windows XP Embedded instead.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT size=2&gt;&lt;STRONG&gt;Q:&lt;/STRONG&gt; Are there any plans to address this problem in future releases of Windows CE?&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT size=2&gt;&lt;STRONG&gt;A:&lt;/STRONG&gt; I cannot comment on what will or will not be in future releases.&amp;nbsp; I can only say, so far I don't think it is a high priority.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT size=2&gt;&amp;nbsp;&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=421750" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sloh/archive/tags/Debugging_2C00_+Kernel+_2600_+misc.+File+System+issues/default.aspx">Debugging, Kernel &amp; misc. File System issues</category></item><item><title>How does the OS use the registry?</title><link>http://blogs.msdn.com/sloh/archive/2005/04/11/407286.aspx</link><pubDate>Mon, 11 Apr 2005 20:07:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:407286</guid><dc:creator>sloh</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/sloh/comments/407286.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sloh/commentrss.aspx?PostID=407286</wfw:commentRss><description>&lt;FONT size=2&gt;
&lt;P&gt;&lt;STRONG&gt;Q: &lt;/STRONG&gt;As an embedded programmer I am new to all windows development. And as such I am ignorant of the registry. It seems to play a crucial part in the initialization of the OS (device drivers, services, etc) Do you know of a good source of information about how the OS (not individual applications) uses the registry?&lt;/P&gt;&lt;FONT size=2&gt;
&lt;P&gt;&lt;STRONG&gt;A: &lt;/STRONG&gt;Sorry, I don't have any good sources of information to point you at. The registry is sort of a cross between a database and a file system -- the data is stored hierarchically like a file system, in small values with different types. The OS mostly uses the registry for reading in configuration information that you (or applications) can change. There isn't one big document for all registry information that is used by the system, but I know our documentation team has been making an effort to document all the settings on an area-by-area basis. For example, &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/wcedata5/html/wce50oriFileSystemsDataStoreRegistrySamples.asp"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;http://msdn.microsoft.com/library/en-us/wcedata5/html/wce50oriFileSystemsDataStoreRegistrySamples.asp&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;/P&gt;&lt;FONT size=2&gt;
&lt;P&gt;Most parts of the OS have default registry settings that they use, some of which may be controlled by relatively high-level flags you can set like PRJ_* and IMG*. &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/wceosdev5/html/wce50conPRJEnvironmentVariables.asp"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;http://msdn.microsoft.com/library/en-us/wceosdev5/html/wce50conPRJEnvironmentVariables.asp&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;/P&gt;&lt;FONT size=2&gt;
&lt;P&gt;The OS should be able to boot and run based on these variables, without you having to tweak many (any?) individual settings. Then you can tweak things to modify OS behavior as needed. The hard question I can't answer is what settings you might want to tweak. I guess you will have to find those out as you go.&lt;/P&gt;
&lt;P&gt;Sorry I'm not more help than that,&lt;/P&gt;
&lt;P&gt;Sue&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=407286" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sloh/archive/tags/Debugging_2C00_+Kernel+_2600_+misc.+File+System+issues/default.aspx">Debugging, Kernel &amp; misc. File System issues</category></item><item><title>GetTickCount – Truth and Fiction</title><link>http://blogs.msdn.com/sloh/archive/2005/04/05/405724.aspx</link><pubDate>Wed, 06 Apr 2005 02:16:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:405724</guid><dc:creator>sloh</dc:creator><slash:comments>10</slash:comments><comments>http://blogs.msdn.com/sloh/comments/405724.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sloh/commentrss.aspx?PostID=405724</wfw:commentRss><description>&lt;P class=MsoNormal&gt;I was surprised and dismayed to read a recent article in Embedded Systems Programming (&lt;A href="http://www.embedded.com/showArticle.jhtml?articleID=159902113"&gt;http://www.embedded.com/showArticle.jhtml?articleID=159902113&lt;/A&gt;) that gets so many things wrong about the GetTickCount API and portrays Windows CE so negatively.&lt;/P&gt;
&lt;P class=MsoNormal&gt;Apparently I’m behind on my reading, since the same author also wrote a previous article on the same subject, to which Mike Hall wrote a rebuttal on his own blog: &lt;a href="http://blogs.msdn.com/mikehall/archive/2005/01/28/362498.aspx"&gt;http://blogs.msdn.com/mikehall/archive/2005/01/28/362498.aspx&lt;/A&gt;&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Reading the more recent article makes me want to write my own rebuttal.&lt;/P&gt;
&lt;P class=MsoNormal&gt;GetTickCount is a pretty simple API from the caller’s perspective.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Every millisecond the tick count increments, and you can use GetTickCount to retrieve the number of milliseconds since boot. &lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;Since GetTickCount returns only a 32-bit number, after about 49 days, the counter wraps. &lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;This is &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcecoreos5/html/wce50lrfGetTickCount.asp"&gt;documented behavior&lt;/A&gt;, and to properly use GetTickCount you have to understand that. &lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;Typically GetTickCount is used to time the duration between two events, in which case you’re generally safe if you subtract two values; subtraction is safe in the presence of rollover.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;(eg. If you get a tick count of &lt;FONT face="Courier New" color=#a52a2a size=2&gt;&lt;STRONG&gt;0xFFFFFF00&lt;/STRONG&gt;&lt;/FONT&gt; before the rollover, and a tick count of &lt;FONT face="Courier New" color=#a52a2a size=2&gt;&lt;STRONG&gt;0x200&lt;/STRONG&gt;&lt;/FONT&gt; after the rollover, subtraction gives you get a difference of &lt;FONT face="Courier New" color=#a52a2a size=2&gt;&lt;STRONG&gt;0x300&lt;/STRONG&gt;&lt;/FONT&gt; as expected.)&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;The only time subtraction can get you into hot water is if there’s a chance the time delta will exceed 49 days, because you may end up needing a difference that’s larger than you can represent in 32 bits.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;In which case GetTickCount is the wrong API for you.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;I guess in that case you would probably need to implement something using GetSystemTime and SystemTimeToFileTime.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Applications that use GetTickCount get into trouble if they are subtracting over such a long time period, or if they are using something besides subtraction with the tick count.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;For example,&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;FONT face="Courier New" color=#a52a2a size=2&gt;&lt;STRONG&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (GetTickCount() &amp;gt; MyTickValue) { ... }&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;will also get you into trouble.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;If I were to guess, that’s where I’d say most applications probably go wrong using this API.&lt;/P&gt;
&lt;P class=MsoNormal&gt;To help catch such errors in applications and drivers, Windows CE does a little thing on debug builds – it initializes the tick count such that it rolls over 3 minutes after boot.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;The author talks about our 3-minute rollover as if it’s indicative of a problem in the OS, when really it’s just a meager attempt to help catch bugs in applications.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;It’s not much help really, if you ask me, but it might help catch a bug or two.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;I’d love to improve on it, but it’s tough to arrange for the timer to roll over at a really useful time for testing your application.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;For example you might think we could create an IOCTL you could call, to set the timer at run-time.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;But making the timer jump at run-time could mess things up.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Suddenly drivers and applications would think 47 days have passed, maybe network drivers time out, all your appointments fire, who knows…&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;I’m making things up since I don’t really know how networking or appointments are implemented, but you get the idea.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;If you really want to be careful about testing your application or driver that uses GetTickCount, probably the best thing to do is create a wrapper that your code uses to call GetTickCount, and arrange for your wrapper to manipulate the times.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;I’d love to see suggestions, and if you can come up with something good we can do in the OS, hey, maybe we will take your advice.&lt;/P&gt;
&lt;P class=MsoNormal&gt;So now I’ll describe how GetTickCount is implemented internally.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;First off, the function is technically owned completely by the OEM, though we provide as many implementations as we can manage, so that OEMs can use those.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;The implementation varies per CPU and per OAL, but in general, there’s a 32-bit counter, CurMSec, that is incremented once per millisecond with a timer interrupt.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;That millisecond timer interrupt is also used for other things, like scheduling threads.&lt;/P&gt;
&lt;P class=MsoNormal&gt;To conserve power, when the kernel has no threads to schedule, the system goes into an idle state (implemented by the OEM’s OEMIdle function) where the timer interrupt is extended to a longer period.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;That allows the CPU to spend a longer time in a low-power state.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;The idle period is ended when an interrupt fires (the extended timer interrupt or some other interrupt).&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;When the system leaves the idle state, OEMIdle updates CurMSec with the amount of time that the system was idle, using whatever timer the hardware has.&lt;/P&gt;
&lt;P class=MsoNormal&gt;All the magic is really in the OEM’s implementation of OEMIdle.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;If you want some code to look at, see &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcehardware5/html/wce50conenablingpowermanagement.asphttp://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcehardware5/html/wce50conenablingpowermanagement.asp"&gt;the CE 5.0 help article&lt;/A&gt;.&lt;/P&gt;
&lt;P class=MsoNormal&gt;Now, back to the article.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Here are my responses:&lt;/P&gt;
&lt;UL&gt;
&lt;LI class=MsoNormal&gt;One of the things that floors me about this article is that it claims that GetTickCount counts downward, not upward.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;That is just plain wrong. &lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;I don’t know what gave the author that impression but the counter starts out at 0 and goes up.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;If you see any documentation or code that claims otherwise, please tell me and we’ll get it corrected. 
&lt;LI class=MsoNormal&gt;The author also asks whether the counter “sticks” at the same value after rollover, which it doesn’t.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;He seems to imply that it does though. 
&lt;LI class=MsoNormal&gt;GetTickCount also works just fine on 16-bit and 64-bit CPUs, though the author implies that it doesn’t. 
&lt;LI class=MsoNormal&gt;The article brings up cases where counters are non-monotonic, where the counter jumps backwards by a few ticks.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;If that happens, it means the timer is not implemented correctly by the OEM.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Most likely something in OEMIdle is not right.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;We do provide documentation of how to implement a timer (&lt;A href="http://msdn.microsoft.com/library/en-us/wcehardware5/html/wce50conImplementationOfVariableTickScheduler.asp"&gt;here’s some&lt;/A&gt;), standard implementations for different CPUs, and &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcedebug5/html/wce50conOALTimerTest.asp"&gt;tests to verify that the timer is implemented correctly&lt;/A&gt;.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;But I’m sure some people would argue that we don’t do enough to help OEMs get this right, and maybe they’re right.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Let’s discuss it.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;What else would you like to see?&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;What trouble have you had? 
&lt;LI class=MsoNormal&gt;All the other examples of badness that the author uses come from desktop Windows as far as I can tell, and they are problems with applications that use GetTickCount improperly, not with Windows itself. 
&lt;LI class=MsoNormal&gt;You could argue that this is too complicated, that GetTickCount should just read the timer hardware straight, and scale to milliseconds.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;I think the main reason it was done this way was to standardize between hardware with a count-compare type timer and hardware with a count-down timer.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;It also avoids doing division to convert to milliseconds, especially 64-bit division since 64-bit timers are common. 
&lt;LI class=MsoNormal&gt;The author actually suggests using a stopwatch to measure elapsed time during a performance test.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Even if that was accurate enough, it’s a pain and it’s not automatable.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;How could you run tests regularly to make sure that nothing got worse?&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;I fully support the author’s idea that you should loop many times, so that the performance test runs long enough that you &lt;I&gt;could&lt;/I&gt; time it with a stopwatch.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;But that’s for reasons of repeatability, to get rid of variance.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;I don’t believe a stopwatch is the right answer.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;For timing code run-times, GetTickCount and QueryPerformanceCounter have satisfied every need I’ve seen so far.&lt;/LI&gt;&lt;/UL&gt;
&lt;P class=MsoNormal&gt;I guess the thing I disliked the most was that the author took a list of implementation complications, application bugs from desktop Windows, incorrect information and “what if’s,” and turned it into a negative portrayal of Windows CE.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Maybe I am just too sensitive about the product I pour so much energy into.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Too many people assume that Microsoft developers don’t care, when the truth is very much the opposite. &lt;/P&gt;
&lt;P class=MsoNormal&gt;Oh man has this discussion gotten long.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Have I ever got just a &lt;I&gt;few&lt;/I&gt; words to say about something?&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Oh well.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Write back if you have opinions to add or if you think I got any technical details wrong.&lt;/P&gt;
&lt;P class=MsoNormal&gt;Sue&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=405724" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sloh/archive/tags/Debugging_2C00_+Kernel+_2600_+misc.+File+System+issues/default.aspx">Debugging, Kernel &amp; misc. File System issues</category></item><item><title>Resolving Symbols Manually on Windows CE (ADDRESS --&gt; SYMBOL)</title><link>http://blogs.msdn.com/sloh/archive/2005/02/28/381706.aspx</link><pubDate>Mon, 28 Feb 2005 19:37:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:381706</guid><dc:creator>sloh</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/sloh/comments/381706.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sloh/commentrss.aspx?PostID=381706</wfw:commentRss><description>&lt;P&gt;You know you've been there.&amp;nbsp; You are looking at a callstack, and the one function you want to know the identity of, failed to resolve symbols or &lt;a href="http://blogs.msdn.com/kitlfirst/archive/2005/02/22/377629.aspx"&gt;has bad symbols&lt;/A&gt;.&amp;nbsp; Dang!&amp;nbsp; If only you knew what function &lt;FONT face="Courier New" color=#a52a2a&gt;0x12345678&lt;/FONT&gt; refers to, you'd find your bug.&lt;/P&gt;
&lt;P&gt;First thing's first: you have to understand the Windows CE virtual memory layout.&amp;nbsp; You have to understand what slots are, and recognize slot 0 &amp;amp; 1 addresses versus addresses from process slots.&amp;nbsp; That’s why &lt;a href="http://blogs.msdn.com/sloh/archive/2005/02/25/380475.aspx"&gt;I blogged about that first&lt;/A&gt;.&amp;nbsp; If you internalized all of those details already, then you’d know that &lt;FONT face="Courier New" color=#a52a2a&gt;0x12345678&lt;/FONT&gt; was inside the process that’s running in the slot starting at &lt;FONT face="Courier New" color=#a52a2a&gt;0x12000000&lt;/FONT&gt;.&amp;nbsp; In fact, it’s at offset &lt;FONT face="Courier New" color=#a52a2a&gt;0x00345678&lt;/FONT&gt; from the start of that .exe.&amp;nbsp; Heck, you’re almost to the symbol already!&lt;/P&gt;
&lt;P&gt;But this shows that the 2 main steps to resolving a symbol are: figuring out what module the address lies within, and figuring out what symbol lies at that offset within the module.&amp;nbsp; If you need to get all the way down to the line of source code involved, you can figure that out too, by figuring out what line of source code is at that offset within the function.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT size=4&gt;Figuring out what module it is&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;To figure out what function or variable is at a particular address, first you need to know what module (DLL or EXE) is loaded into that chunk of RAM.&amp;nbsp; So first you eyeball the address and decide whether it’s a DLL or an EXE.&amp;nbsp; Since EXE code &amp;amp; data starts at the bottom of the slot, and DLL code &amp;amp; data starts at the top, it’s pretty easy to figure out.&amp;nbsp; &lt;FONT face="Courier New" color=#a52a2a&gt;0x12345678&lt;/FONT&gt; is an EXE, &lt;FONT face="Courier New" color=#a52a2a&gt;0x13987654&lt;/FONT&gt; is a DLL.&lt;/P&gt;
&lt;P&gt;Then you look for the DLL or EXE that is the closest match.&amp;nbsp; There are a bunch of ways to do this.&amp;nbsp; You can open up the Modules and Symbols Window, sort by address, and find the module that matches.&amp;nbsp; If you are looking up the symbol for a function, sort by “Image Address Range.”&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;&lt;STRONG&gt;Modules and Symbols Window&lt;BR&gt;Module&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Image Address Range&amp;nbsp;&amp;nbsp;&amp;nbsp; Relocated Data Address Range&lt;/STRONG&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#a52a2a size=2&gt;lmemdebug.dll&amp;nbsp; 0x01AC0000-0x01AC4FFF&lt;BR&gt;kbdmouse.dll&amp;nbsp;&amp;nbsp; 0x01BA0000-0x01BC1FFF&lt;BR&gt;devmgr.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x03EE0000-0x03EE9FFF&amp;nbsp; 0x01FE9000-0x01FE92A4&lt;BR&gt;fsdmgr.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x03F50000-0x03F60FFF&amp;nbsp; 0x01FF7000-0x01FF73F0&lt;BR&gt;coredll.dll&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x03F80000-0x03FD8FFF&amp;nbsp; 0x01FFB000-0x01FFBD64&lt;BR&gt;filesys.exe&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x04010000-0x04041FFF&lt;BR&gt;shell.exe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x06010000-0x06022FFF&lt;BR&gt;device.exe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x08010000-0x08012FFF&lt;BR&gt;gwes.exe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x0C010000-0x0C0CBFFF&lt;BR&gt;services.exe&amp;nbsp;&amp;nbsp; 0x12010000-0x12017FFF&lt;BR&gt;nk.exe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x81200000-0x8123DFFF&amp;nbsp; 0x81FA0000-0x81FFD7BF&lt;BR&gt;hd.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x8123E000-0x8123FFFF&amp;nbsp; 0x82002000-0x82002954&lt;BR&gt;osaxst0.dll&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x81240000-0x81246FFF&amp;nbsp; 0x82003000-0x82006328&lt;BR&gt;giisr.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x81249000-0x8124AFFF&amp;nbsp; 0x82008000-0x82008504&lt;BR&gt;osaxst1.dll&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x82042000-0x82046FFF&lt;BR&gt;kd.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x82047000-0x82060FFF&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;If you’re looking up the symbol for a variable, then for a DLL or EXE with a “Relocated Data Address Range” the variable would fall inside that range; for a DLL or EXE that does not have relocated data, the variable would fall inside the image address range.&amp;nbsp; So you may need to sort on both in order to find the right address range.&lt;/P&gt;
&lt;P&gt;Another option you have is that you can type “gi proc” or “gi mod” in the Target Control Window to get the location where the code is loaded.&amp;nbsp; The exception for this is the kernel, nk.exe, which reports a different value under “gi proc” than where its code is loaded.&amp;nbsp; (These lists don’t show relocated data addresses, so they’re only useful for looking up function symbols.)&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;STRONG&gt;Target Control Window&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;Windows CE&amp;gt;gi proc&lt;BR&gt;PROC: Name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; hProcess: CurAKY :dwVMBase:CurZone&lt;BR&gt;&lt;FONT color=#a52a2a&gt;&amp;nbsp;P00: NK.EXE&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 03fb4002 00000001 c2000000 00000000&lt;BR&gt;&amp;nbsp;P01: filesys.exe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 03f4b69e 00000002 04000000 00000020&lt;BR&gt;&amp;nbsp;P02: shell.exe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 03dcae86 00000004 06000000 00000000&lt;BR&gt;&amp;nbsp;P03: device.exe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; e3d60f6e 00000008 08000000 00000000&lt;BR&gt;&amp;nbsp;P05: gwes.exe&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4389f8aa 00000020 0c000000 00000000&lt;BR&gt;&amp;nbsp;P08: services.exe&amp;nbsp;&amp;nbsp;&amp;nbsp; 03497182 00000100 12000000 00000000&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&lt;BR&gt;Windows CE&amp;gt;gi mod&lt;BR&gt;&amp;nbsp;MOD: Name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pModule :dwInUSE :dwVMBase:CurZone&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#a52a2a size=2&gt;&amp;nbsp;M35: coredll.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 83fb4794 7ffbffff 03f80000 00000000&lt;BR&gt;&amp;nbsp;M45: devmgr.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 83d36250 00000008 03ee0000 00000000&lt;BR&gt;&amp;nbsp;M58: fsdmgr.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 83fb1ea0 00000002 03f50000 00000000&lt;BR&gt;&amp;nbsp;M60: giisr.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 8390c5dc 00000009 81249000 00000000&lt;BR&gt;&amp;nbsp;M65: hd.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 83fb425c 00000001 8123e000 00000000&lt;BR&gt;&amp;nbsp;M75: kbdmouse.dll&amp;nbsp;&amp;nbsp;&amp;nbsp; 8383be54 00000020 01ba0000 00000000&lt;BR&gt;&amp;nbsp;M76: kd.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 82ce7e40 00000001 82047000 00000000&lt;BR&gt;&amp;nbsp;M80: lmemdebug.dll&amp;nbsp;&amp;nbsp; 83d60d30 0000003c 01ac0000 00000000&lt;BR&gt;&amp;nbsp;M98: osaxst0.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 83fb44c0 00000001 81240000 00000000&lt;BR&gt;&amp;nbsp;M99: osaxst1.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 83103d6c 00000001 82042000 00000000&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Other possible options – if you have data from a Remote Kernel Tracker / CeLog output file (.clg), that file usually contains a “re-sync” (the output of the CeLogReSync API) where CeLog dumps a list of all the existing threads, processes and modules.&amp;nbsp; (This list doesn’t contain relocated data addresses either.)&amp;nbsp; Here is some sample output from the “readlog” command-line tool which parses CeLog output files, edited a little to fit this web format.&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;&lt;STRONG&gt;Readlog.exe Output File&lt;BR&gt;&lt;/STRONG&gt;--:--:--.---.--- : Marker, counter frequency=1193180 Hz, default thread quantum=100&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT color=#a52a2a&gt;&amp;nbsp;0:18:33.578.716 : ProcessCreate, dwVMBase=0x81200000, NK.EXE&lt;BR&gt;&amp;nbsp;0:18:33.578.779 : ProcessCreate, dwVMBase=0x04000000, filesys.exe&lt;BR&gt;&amp;nbsp;0:18:33.578.870 : ProcessCreate, dwVMBase=0x06000000, shell.exe&lt;BR&gt;&amp;nbsp;0:18:33.578.901 : ProcessCreate, dwVMBase=0x08000000, device.exe&lt;BR&gt;&amp;nbsp;0:18:33.579.666 : ProcessCreate, dwVMBase=0x0C000000, gwes.exe&lt;BR&gt;&amp;nbsp;0:18:33.579.979 : ProcessCreate, dwVMBase=0x12000000, services.exe&lt;BR&gt;&amp;nbsp;0:18:33.581.421 : ModuleLoad, dwBase=0x82047000, kd.dll&lt;BR&gt;&amp;nbsp;0:18:33.581.450 : ModuleLoad, dwBase=0x82042000, osaxst1.dll&lt;BR&gt;&amp;nbsp;0:18:33.582.422 : ModuleLoad, dwBase=0x01BA0000, kbdmouse.dll&lt;BR&gt;&amp;nbsp;0:18:33.582.559 : ModuleLoad, dwBase=0x81249000, giisr.dll&lt;BR&gt;&amp;nbsp;0:18:33.583.481 : ModuleLoad, dwBase=0x03EE0000, devmgr.dll&lt;BR&gt;&amp;nbsp;0:18:33.583.494 : ModuleLoad, dwBase=0x01AC0000, lmemdebug.dll&lt;BR&gt;&amp;nbsp;0:18:33.583.673 : ModuleLoad, dwBase=0x03F50000, fsdmgr.dll&lt;BR&gt;&amp;nbsp;0:18:33.583.699 : ModuleLoad, dwBase=0x03F80000, coredll.dll&lt;BR&gt;&amp;nbsp;0:18:33.583.714 : ModuleLoad, dwBase=0x81240000, osaxst0.dll&lt;BR&gt;&amp;nbsp;0:18:33.583.727 : ModuleLoad, dwBase=0x8123E000, hd.dll&lt;BR&gt;&lt;/FONT&gt;--:--:--.---.--- : Sync End Marker&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Another option you have is to use the ToolHelp APIs (CreateToolhelp32Snapshot, etc) to programmatically gather this data.&lt;/P&gt;
&lt;P&gt;It’s relatively straightforward to figure out, given an address, which module that address falls inside.&amp;nbsp; Use the “Price Is Right” matching: whichever module is closest to that address, without going over, is the matching module.&amp;nbsp; [“The Price is Right” is an old US TV game show.]&amp;nbsp; Address &lt;FONT face="Courier New" color=#a52a2a&gt;0x8123FFFF&lt;/FONT&gt; is inside hd.dll; &lt;FONT face="Courier New" color=#a52a2a&gt;0x81240000&lt;/FONT&gt; is inside osaxst0.dll.&lt;/P&gt;
&lt;P&gt;The main thing you have to be careful about is recognizing addresses that are inside process slots, and converting them to slot 0 addresses.&amp;nbsp; Address &lt;FONT face="Courier New" color=#a52a2a&gt;0x09EE5678&lt;/FONT&gt; is inside devmgr.dll, not device.exe.&amp;nbsp; (ERRATA: See comments below for the error in this statement.&amp;nbsp; I've left the text here unchanged so that you know what I was talking about.&amp;nbsp; For the sake of the remainder of this write-up, just pretend devmgr.dll loads at address range &lt;FONT face="Courier New" color=#a52a2a&gt;0x01EE0000-0x01EE9FFF&lt;/FONT&gt; instead of the range I listed in all the examples above.)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT size=4&gt;Figuring out what function or global variable it is&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Once you know what DLL or EXE the address is within, you can simply subtract the DLL or EXE base address from the address in question, to get the offset of the address from the start of the DLL or EXE.&amp;nbsp; So address &lt;FONT face="Courier New" color=#a52a2a&gt;0x09EE5678&lt;/FONT&gt; is at offset &lt;FONT face="Courier New" color=#a52a2a&gt;0x00005678&lt;/FONT&gt; from the start of devmgr.dll.&lt;/P&gt;
&lt;P&gt;Then you look up the offset from the .map file for the DLL or EXE.&amp;nbsp; You should already have the .map files from most modules you work with, but if you are missing one, it may be because the &lt;STRONG&gt;WINCEMAP&lt;/STRONG&gt; environment variable must be set to 1 when the module is&amp;nbsp; linked, in order to produce the .map file.&lt;/P&gt;
&lt;P&gt;Here’s an excerpt from devmgr.map.&amp;nbsp; The important things in the .map file are the function names and the addresses on the right side (highlighted):&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#a52a2a size=2&gt;Preferred load address is 10000000&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#a52a2a size=2&gt;&amp;nbsp;0001:000044b0 &lt;FONT&gt;_ConvertStringToGuid&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 100054b0&lt;/FONT&gt; f devcore:devpnp.obj&lt;BR&gt;&amp;nbsp;0001:00004546 &lt;FONT&gt;_FindDeviceInterface&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 10005546&lt;/FONT&gt; f devcore:devpnp.obj&lt;BR&gt;&amp;nbsp;0001:0000456c &lt;FONT&gt;_I_AdvertiseDeviceInterface 1000556c&lt;/FONT&gt; f devcore:devpnp.obj&lt;BR&gt;&amp;nbsp;0001:00004774 &lt;FONT&gt;_PnpAdvertiseInterfaces&amp;nbsp;&amp;nbsp;&amp;nbsp; 10005774&lt;/FONT&gt; f devcore:devpnp.obj&lt;BR&gt;&amp;nbsp;0001:00004a9b &lt;FONT&gt;_PnpDeadvertiseInterfaces&amp;nbsp; 10005a9b&lt;/FONT&gt; f devcore:devpnp.obj&lt;BR&gt;&amp;nbsp;0001:00004ae5 &lt;FONT&gt;_InitializePnPNotifications 10005ae5&lt;/FONT&gt; f devcore:devpnp.obj&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;The address on the right is saying where the function would live in RAM if the DLL was loaded at its PreferredLoadAddress – which is stored at the top of the .map file, but is almost always &lt;FONT face="Courier New" color=#a52a2a&gt;0x10000000&lt;/FONT&gt; for a DLL.&amp;nbsp; Which makes it easy, because you just chop off the top part of the address to find out where the function would live if the DLL was loaded starting at 0.&amp;nbsp; So offset &lt;FONT face="Courier New" color=#a52a2a&gt;0x00005678&lt;/FONT&gt; from the beginning of devmgr.dll is the symbol &lt;FONT face="Courier New" color=#a52a2a&gt;I_AdvertiseDeviceInterface&lt;/FONT&gt;.&amp;nbsp; Any offset between &lt;FONT face="Courier New" color=#a52a2a&gt;0x0000556C&lt;/FONT&gt; and &lt;FONT face="Courier New" color=#a52a2a&gt;0x00005773&lt;/FONT&gt; inside devmgr.dll falls inside &lt;FONT face="Courier New" color=#a52a2a&gt;I_AdvertiseDeviceInterface&lt;/FONT&gt;.&amp;nbsp; And, since devmgr.dll is loaded at address &lt;FONT face="Courier New" color=#a52a2a&gt;0x03EE0000&lt;/FONT&gt;, any address between &lt;FONT face="Courier New" color=#a52a2a&gt;0x03EE556C&lt;/FONT&gt; and &lt;FONT face="Courier New" color=#a52a2a&gt;0x03EE5773&lt;/FONT&gt; corresponds to &lt;FONT face="Courier New" color=#a52a2a&gt;I_AdvertiseDeviceInterface&lt;/FONT&gt;.&amp;nbsp; So again you are basically using “Price is Right” matching.&lt;/P&gt;
&lt;P&gt;EXEs are a little different, but even easier.&amp;nbsp; Most EXEs will be linked with a PreferredLoadAddress of &lt;FONT face="Courier New" color=#a52a2a&gt;0x00010000&lt;/FONT&gt;, but that is the spot the Windows CE kernel always loads an EXE at anyway.&amp;nbsp; So there’s no subtraction involved – just use the address to the right of the symbol.&lt;/P&gt;
&lt;P&gt;Once you get used to doing this stuff, it’s not that hard, just a little manual labor.&amp;nbsp; In general the formula for going from ADDRESS à SYMBOL is:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(.map file offset) = (address) – (module base addr) + (module preferred load addr)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;And remember to use “Price is Right” matching for the module and the symbol: whichever has the closest address without going over is the closest match.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT size=4&gt;Figuring out what source line it is &lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;You can even get down to the source line if you have the COD files to look at.&amp;nbsp; I have rarely had to do this kind of lookup, but it is occasionally useful.&amp;nbsp; The two main uses I’ve had for it are: figuring out exactly which line of source/disassembly a crash or debug break occurred on, and figuring out which instance of a function call is involved in a callstack.&amp;nbsp; For example if function &lt;FONT face="Courier New" color=#a52a2a&gt;Foo&lt;/FONT&gt; calls function &lt;FONT face="Courier New" color=#a52a2a&gt;Bar&lt;/FONT&gt; twice, and I’m looking at a callstack which involves &lt;FONT face="Courier New" color=#a52a2a&gt;Foo&lt;/FONT&gt; calling &lt;FONT face="Courier New" color=#a52a2a&gt;Bar&lt;/FONT&gt;, I may want to know which invocation of &lt;FONT face="Courier New" color=#a52a2a&gt;Bar&lt;/FONT&gt; it was inside &lt;FONT face="Courier New" color=#a52a2a&gt;Foo&lt;/FONT&gt;.&amp;nbsp; The address given for &lt;FONT face="Courier New" color=#a52a2a&gt;Foo&lt;/FONT&gt; in the stack is the address where the jump to &lt;FONT face="Courier New" color=#a52a2a&gt;Bar&lt;/FONT&gt; occurred, so I can use the address given for &lt;FONT face="Courier New" color=#a52a2a&gt;Foo&lt;/FONT&gt; in the stack to figure out what line of code the jump occurred on.&lt;/P&gt;
&lt;P&gt;COD files come from compiling the code with the&amp;nbsp;&lt;STRONG&gt;WINCECOD&lt;/STRONG&gt; environment variable set to 1.&amp;nbsp; By default &lt;STRONG&gt;WINCECOD&lt;/STRONG&gt; is not set, so you will not have COD files by default.&amp;nbsp; And COD files are not shipped with the Platform Builder CDs or with the Windows CE source.&amp;nbsp; So unless you have buildable source for the OS, this work is only possible for your own code.&lt;/P&gt;
&lt;P&gt;You may have noticed that the MAP file lists the OBJ file the function came from.&amp;nbsp; For example &lt;FONT face="Courier New" color=#a52a2a&gt;I_AdvertiseDeviceInterface&lt;/FONT&gt; came from the devpnp.obj file which was linked into devcore.lib.&amp;nbsp; This means the code was in “devpnp.c” or “devpnp.cpp.”&amp;nbsp; If you know where this source file is, you can go to the right directory, set &lt;STRONG&gt;WINCECOD&lt;/STRONG&gt;=1, build –c, and then open the COD file from &lt;FONT face="Courier New"&gt;obj\%_TGTCPU%\%WINCEDEBUG%&lt;/FONT&gt;.&amp;nbsp; It’ll be named after the C or CPP file – in this case devpnp.cod.&amp;nbsp; The function name will appear several times in the COD file, but in only one case will the function name be followed by the word “PROC,” and this is the beginning of the assembly code for that function.&amp;nbsp; Here’s a sample that’s munged a little from reality.&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#a52a2a size=2&gt;&lt;FONT&gt;_I_AdvertiseDeviceInterface PROC&lt;/FONT&gt; NEAR&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ; COMDAT&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#a52a2a size=2&gt;; 348&amp;nbsp; : {&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#a52a2a size=2&gt;&amp;nbsp; &lt;FONT&gt;001e8&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 55&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push ebp&lt;BR&gt;&amp;nbsp; &lt;FONT&gt;001e9&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 8b ec&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp; ebp, esp&lt;BR&gt;&amp;nbsp; &lt;FONT&gt;001eb&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 81 ec 14 02 00&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 00&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sub&amp;nbsp; esp, 532&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ; 00000214H&lt;BR&gt;&amp;nbsp; &lt;FONT&gt;001f1&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; a1 00 00 00 00&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp; eax, DWORD PTR ___cke&lt;BR&gt;&amp;nbsp; &lt;FONT&gt;001f6&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 53&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push ebx&lt;BR&gt;&amp;nbsp; &lt;FONT&gt;001f7&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 56&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push esi&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#a52a2a size=2&gt;; 349&amp;nbsp; :&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ULONG result = ERROR_SUCCESS;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#a52a2a size=2&gt;&amp;nbsp; &lt;FONT color=#a52a2a&gt;001f8&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 33 f6&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; xor&amp;nbsp; esi, esi&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;As you can see, the source code and line numbers are included in the COD file next to the assembly code that implements the source.&amp;nbsp; Each assembly instruction is labeled with an address.&amp;nbsp; So the COD file provides the mapping from function offset to source line.&amp;nbsp; Sometimes the assembly for the function is labeled starting with 0, and sometimes not.&amp;nbsp; (I believe it may depend on which compiler is being used – meaning it varies by CPU type.)&amp;nbsp; If not, you have to take the function start label into account.&amp;nbsp; So in this example the function starts at label &lt;FONT face="Courier New" color=#a52a2a&gt;0x001E8&lt;/FONT&gt;.&lt;/P&gt;
&lt;P&gt;So the formula for the line of assembly to look for is:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(assembly label) = (.map file offset) – (function start addr from .map) + (function start label from .cod)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;And to complete my example, subtracting the start offset of &lt;FONT face="Courier New" color=#a52a2a&gt;I_AdvertiseDeviceInterface&lt;/FONT&gt; &lt;FONT face="Courier New" color=#a52a2a&gt;0x0000556C&lt;/FONT&gt; from the address &lt;FONT face="Courier New" color=#a52a2a&gt;0x00005678&lt;/FONT&gt;, I find that the address I'm interested in is at offset &lt;FONT face="Courier New" color=#a52a2a&gt;0x0000010C&lt;/FONT&gt; from the beginning of the function.&amp;nbsp; Add that to the start label &lt;FONT face="Courier New" color=#a52a2a&gt;0x001E8&lt;/FONT&gt; of &lt;FONT face="Courier New" color=#a52a2a&gt;I_AdvertiseDeviceInterface&lt;/FONT&gt; from the COD file, and I am looking for the assembly line labeled &lt;FONT face="Courier New" color=#a52a2a&gt;0x002F4&lt;/FONT&gt;.&amp;nbsp; This line will tell me exactly what assembly code is at that address, and what line of source code that corresponds to.&lt;BR&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=381706" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sloh/archive/tags/Debugging_2C00_+Kernel+_2600_+misc.+File+System+issues/default.aspx">Debugging, Kernel &amp; misc. File System issues</category></item><item><title>Looking for a good tool for doing hex math</title><link>http://blogs.msdn.com/sloh/archive/2005/02/25/380607.aspx</link><pubDate>Fri, 25 Feb 2005 23:34:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:380607</guid><dc:creator>sloh</dc:creator><slash:comments>12</slash:comments><comments>http://blogs.msdn.com/sloh/comments/380607.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sloh/commentrss.aspx?PostID=380607</wfw:commentRss><description>&lt;p&gt;While I'm writing about all of these address tricks -- I figured I'd ask around if there's a good tool for manipulating hex values.&amp;nbsp; I just use "calc" which comes with Windows; if you put it into scientific mode it will handle hex values for you.&amp;nbsp; But it doesn't have very good shifting or bitwise&amp;nbsp;functionality, and it always uses 64-bit values.&amp;nbsp; Most of the time I want to subtract and get the 32-bit value, not FFFFFFFF FFFFFFFF.&amp;nbsp; I&amp;nbsp;like how easy it is to flip between hex and decimal in calc, but I wish I could do it without using the mouse.&lt;/p&gt; &lt;p&gt;So I figured I'd ask and see if anyone else knows of a better tool.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=380607" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sloh/archive/tags/Debugging_2C00_+Kernel+_2600_+misc.+File+System+issues/default.aspx">Debugging, Kernel &amp; misc. File System issues</category></item><item><title>Windows CE Virtual Memory Layout for Debugging</title><link>http://blogs.msdn.com/sloh/archive/2005/02/25/380475.aspx</link><pubDate>Fri, 25 Feb 2005 20:15:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:380475</guid><dc:creator>sloh</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/sloh/comments/380475.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sloh/commentrss.aspx?PostID=380475</wfw:commentRss><description>&lt;P&gt;I want to blog about how to resolve symbols manually, and realized I would have to assume that the reader would understand the CE VM layout.&amp;nbsp; So I figure I’d better explain that first.&amp;nbsp; You don’t need to know everything about the VM layout in order to work with Windows CE, but it can be handy at times to at least understand the basics.&amp;nbsp; You need to understand some of it in order to be effective at debugging.&lt;/P&gt;
&lt;P&gt;There are a few spots in this discussion that I could go into more “whys” but I avoided them because the answers aren’t necessary in order to debug.&amp;nbsp; We can discuss them separately if they bug you.&lt;/P&gt;
&lt;P&gt;Anybody who has worked with CE for very long knows that there are a maximum of 32 processes, and each process gets a maximum of 32MB of virtual address space to work inside.&amp;nbsp; Part of the reason for that is because Windows CE keeps all processes’ address spaces available at all times, even when those processes are not running.&amp;nbsp; What it means is that the lower part of the address space is split into 32MB “slots.”&amp;nbsp; The important details to internalize are:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;32MB in hex is &lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;0x02000000&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;Slot 0 is &lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;0x00000000&lt;/STRONG&gt;&lt;/FONT&gt; through &lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;0x01FFFFFF&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;Slot 1 is &lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;0x02000000&lt;/STRONG&gt;&lt;/FONT&gt; through &lt;STRONG&gt;&lt;FONT face="Courier New" color=#a52a2a&gt;0x03FFFFFF&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;The last process ends at &lt;STRONG&gt;&lt;FONT face="Courier New" color=#a52a2a&gt;0x41FFFFFF&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Memory from &lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;0x42000000&lt;/STRONG&gt;&lt;/FONT&gt; to &lt;STRONG&gt;&lt;FONT face="Courier New" color=#a52a2a&gt;0x7FFFFFFF&lt;/FONT&gt;&lt;/STRONG&gt; is mostly the “shared area” used for VirtualAllocs and memory-mapped files.&amp;nbsp; In other words there will never be any symbols there.&lt;/LI&gt;
&lt;LI&gt;Memory above &lt;STRONG&gt;&lt;FONT face="Courier New" color=#a52a2a&gt;0x80000000&lt;/FONT&gt;&lt;/STRONG&gt; is “kernel stuff” – the kernel does run there, as well as DLLs that load into the kernel, like installable interrupt service routine (ISR) DLLs.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;If you do the math, that adds up to 33 slots.&amp;nbsp; Slots 0 &amp;amp; 1 are special slots that aren’t used by processes, and I’ll explain that in a bit.&amp;nbsp; That leaves 31 slots for process to run inside – and the 32nd process is the kernel, which lives elsewhere in RAM somewhere above the &lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;0x80000000&lt;/STRONG&gt;&lt;/FONT&gt; mark.&amp;nbsp; &lt;EM&gt;[OK detail hounds, in CE 3.0 and earlier, the kernel ran in slot 1 instead of in the upper 2GB.]&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;Slot 0 is a special slot whose contents change depending on what process is running.&amp;nbsp; The current process is always mapped into slot 0 in addition to having its own unique slot.&amp;nbsp; Most of the addresses a processes is given to work with, are in slot 0.&amp;nbsp; Get the address of a variable or function from an EXE in the debugger, and you’ll see something like &lt;STRONG&gt;&lt;FONT face="Courier New" color=#a52a2a&gt;0x00012345&lt;/FONT&gt;&lt;/STRONG&gt;.&amp;nbsp; But if that variable is from a process that’s running in the slot from &lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;0x12000000&lt;/STRONG&gt;&lt;/FONT&gt; to &lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;0x13FFFFFF&lt;/STRONG&gt;&lt;/FONT&gt;, that same variable will be present at address &lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;0x12012345&lt;/STRONG&gt;&lt;/FONT&gt;.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Try it out.&amp;nbsp; Break into the debugger while your EXE is running.&amp;nbsp; Use the Modules &amp;amp; Symbols Window to figure out what slot your process is in, then change a slot 0 address into one from the process slot and see if you get the same data.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Understanding slot 0 is actually very important for debugging.&amp;nbsp; If you hit the “break” button at a random time, your process might not be running at that time.&amp;nbsp; If you use the Watch Window to try to look at a global variable inside your process – the debugger might know what address the variable is at, without knowing the value of the variable.&amp;nbsp; For example, &lt;a href="http://blogs.msdn.com/kitlfirst/archive/2005/02/22/377629.aspx"&gt;John Eldridge already blogged a bit &lt;/A&gt;about how to use the Watch Window to look at a variable inside a specific module.&amp;nbsp; Suppose you did this:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;&lt;STRONG&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Watch Window&lt;BR&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {,,helloworld.exe} &amp;amp;MyGlobalVar&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x00012345&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {,,helloworld.exe} MyGlobalVar&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ???&lt;BR&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&amp;nbsp;&lt;BR&gt;If helloworld.exe isn’t the process that’s running at the moment you break into the debugger, the debugger knows what the address of the global variable is, but not the value.&amp;nbsp; But you can manually map the slot 0 address to the right slot, if you know what slot the process is running in.&amp;nbsp; If helloworld.exe is running in the slot starting at &lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;0x12000000&lt;/STRONG&gt;&lt;/FONT&gt;, then you can add the slot start address to the slot 0 address, like this:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Watch Window&lt;BR&gt;&lt;FONT color=#a52a2a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {,,helloworld.exe} &amp;amp;MyGlobalVar&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x00012345&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {,,helloworld.exe} MyGlobalVar&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ???&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *((DWORD*)0x12012345)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 72&lt;/FONT&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;(yes, that’s not a DWORD-aligned address, please close your eyes if it bugs you)&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;Also, if you switch the debugger to helloworld.exe, it can figure things out.&amp;nbsp; I usually use the Callstack Window and select a thread from helloworld.exe to switch to.&amp;nbsp; Then the contents of the Watch Window might change.&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;&lt;STRONG&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Watch Window&lt;BR&gt;&lt;FONT color=#a52a2a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {,,helloworld.exe} &amp;amp;MyGlobalVar&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x00012345&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {,,helloworld.exe} MyGlobalVar&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 72&lt;BR&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&amp;nbsp;&lt;BR&gt;The difference is that now the slot 0 address refers to the same slot the debugger is currently pointed at.&lt;/P&gt;
&lt;P&gt;Slot 1 is also a special slot.&amp;nbsp; All DLLs that are stored in the “MODULES” section of ROM load in slot 1.&amp;nbsp; The code – not the data – for as many DLLs as possible loads in slot 1.&amp;nbsp; Only ROM DLLs load in slot 1.&amp;nbsp; If you drop a new copy of a DLL onto a device, to replace a DLL that was in ROM, that new DLL will not load in slot 1.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Check it out.&amp;nbsp; Open the Modules &amp;amp; Symbols Window and view the addresses that various DLLs are loaded at.&amp;nbsp; Some will be in slot 0, some will be in slot 1.&amp;nbsp; A few will be in the kernel range.&lt;/LI&gt;
&lt;LI&gt;So now look back at &lt;a href="http://blogs.msdn.com/kitlfirst/archive/2005/02/22/377629.aspx"&gt;the addresses John Eldridge posted on his blog entry&lt;/A&gt;, and you can see that the DLL addresses he posted were all from slot 1.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Slot 1 stays the same no matter what the current process is.&amp;nbsp; That’s why only code can load there; if two processes load the same slot 1 DLL, they will share the same code, but the two instances of the DLL will have different globals.&amp;nbsp; The globals are stored in the process slot – so they will most often be referenced in slot 0 just like everything else the process owns.&lt;/P&gt;
&lt;P&gt;The main point to all of this description of slot 0 &amp;amp; 1 is that you need to understand when the memory you need to look at is process-specific, and how to view process-specific memory.&amp;nbsp; If a DLL loads into multiple processes, and you want to look at a global variable inside the DLL, the value could be different in different processes.&amp;nbsp; You need to know which process you’re looking at, and how to change it if necessary.&lt;/P&gt;
&lt;P&gt;One other detail that’s handy to know, is that EXE code loads at the very bottom of the slot (closest to &lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;0x00000000&lt;/STRONG&gt;&lt;/FONT&gt;), while DLL code &amp;amp; data load from the top of the slot down (closest to &lt;STRONG&gt;&lt;FONT face="Courier New" color=#a52a2a&gt;0x1FFFFFFF&lt;/FONT&gt;&lt;/STRONG&gt;).&amp;nbsp; In between are heap allocations, thread stacks, small VirtualAllocs, and other “goodies” that don’t have symbols.&lt;/P&gt;
&lt;P&gt;With practice you will develop one of the &lt;FONT color=#0000ff&gt;&lt;STRONG&gt;ninja debugging skillz&lt;/STRONG&gt;&lt;/FONT&gt;: recognizing the location of an address just by looking at it.&amp;nbsp; Here’s some practice:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;0x00012345&lt;/STRONG&gt;&lt;/FONT&gt; is probably code or global variables from an EXE.&amp;nbsp; &lt;STRONG&gt;&lt;FONT face="Courier New" color=#a52a2a&gt;0x0056789A&lt;/FONT&gt;&lt;/STRONG&gt; is probably not.&amp;nbsp; Why?&amp;nbsp; Too big, that’s a gigantic EXE.&amp;nbsp; It’s more likely to be stack or heap, some other dynamically allocated memory, not EXE or DLL contents.&amp;nbsp; It’s easy to ballpark if you can look at the actual size of the EXE.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;&lt;FONT face="Courier New" color=#a52a2a&gt;0x03123456&lt;/FONT&gt;&lt;/STRONG&gt; is a slot 1 DLL.&amp;nbsp; So is &lt;STRONG&gt;&lt;FONT face="Courier New" color=#a52a2a&gt;0x02123456&lt;/FONT&gt;&lt;/STRONG&gt;.&lt;/LI&gt;
&lt;LI&gt;Address &lt;STRONG&gt;&lt;FONT face="Courier New" color=#a52a2a&gt;0x3456789A&lt;/FONT&gt;&lt;/STRONG&gt; is inside the process that’s running in the slot that starts at &lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;0x34000000&lt;/STRONG&gt;&lt;/FONT&gt;; you can use the Modules and Symbols window to figure out which process that is.&amp;nbsp; But it’s most likely not code or global variables – for the exact same reason as &lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;0x0056789A&lt;/STRONG&gt;&lt;/FONT&gt; in my first bullet.&amp;nbsp; This is just a “slot-mapped” version of the same address.&lt;/LI&gt;
&lt;LI&gt;Address &lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;0x019ABCDE&lt;/STRONG&gt;&lt;/FONT&gt; is probably from a DLL.&amp;nbsp; It's near the top of the slot so it's more likely to be a DLL than heap or stack.&amp;nbsp; The same with &lt;STRONG&gt;&lt;FONT face="Courier New" color=#a52a2a&gt;0x3519ABCDE&lt;/FONT&gt;&lt;/STRONG&gt;.&amp;nbsp; Get used to noticing whether the 2nd nibble of the address is odd or even.&lt;/LI&gt;
&lt;LI&gt;Address &lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;0x6789ABCD&lt;/STRONG&gt;&lt;/FONT&gt; is not from a module.&amp;nbsp; Maybe something from VirtualAlloc or a memory-mapped file, but you’ll never find a symbol that matches that address.&lt;/LI&gt;
&lt;LI&gt;While we’re at it, okay, I am using bad sample addresses. &lt;FONT face="Courier New" color=#a52a2a&gt;&lt;STRONG&gt;0x00012345&lt;/STRONG&gt;&lt;/FONT&gt; is not DWORD-aligned.&amp;nbsp; Things are much more likely to be aligned on a 4-byte boundary: ending in 0, 4, 8 or C.&amp;nbsp; Using consecutive numbers just seems more “friendly” to me, so I’m sorry if that bugs you.&amp;nbsp; If you noticed, then you already have some &lt;FONT color=#0000ff&gt;&lt;STRONG&gt;ninja debugging skillz&lt;/STRONG&gt;&lt;/FONT&gt;.&amp;nbsp; It’s a good thing to be attuned to, since non-x86 processors can’t cope with accessing 4-byte values that are not 4-byte aligned.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Doug Boling, one of our MVPs, &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncenet/html/advmemmgmt.asp"&gt;has written a paper&lt;/A&gt; that explains the virtual address space, and its implications, in much more detail.&amp;nbsp; You should review that if you have more questions.&amp;nbsp; I was just trying to cover the aspects that are important for debugging.&lt;/P&gt;
&lt;P&gt;Next I’ll write about how to resolve symbols for addresses (how to go from address&amp;nbsp;--&amp;gt; symbol), and after that I’ll write about the other direction, how to figure out an address for a particular function or variable (symbol&amp;nbsp;--&amp;gt; address).&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;[Note: This applies to all Windows CE versions up through 5.0; with the exception I already noted about the kernel running in slot 1 in CE 3.0 and earlier.]&lt;BR&gt;&lt;/EM&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=380475" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sloh/archive/tags/Debugging_2C00_+Kernel+_2600_+misc.+File+System+issues/default.aspx">Debugging, Kernel &amp; misc. File System issues</category></item><item><title>Debugging tricks</title><link>http://blogs.msdn.com/sloh/archive/2005/02/24/379980.aspx</link><pubDate>Fri, 25 Feb 2005 02:27:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:379980</guid><dc:creator>sloh</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/sloh/comments/379980.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sloh/commentrss.aspx?PostID=379980</wfw:commentRss><description>&lt;p&gt;John Eldridge has posted some debugging tricks on his blog, and that has inspired me to write up some of my own.&amp;nbsp; I'll start working on that...&amp;nbsp; In the meantime I wanted to share a link to his tips:&amp;nbsp; &lt;A href="http://blogs.msdn.com/kitlfirst/"&gt;http://blogs.msdn.com/kitlfirst/&lt;/a&gt;&lt;/p&gt; &lt;p&gt;John has way more &lt;font color="#0000ff"&gt;&lt;strong&gt;ninja debugging skillz&lt;/strong&gt;&lt;/font&gt; than me, but I've picked up a few&amp;nbsp;in my&amp;nbsp;time at MSFT.&amp;nbsp; I'll talk about how to resolve symbols manually using .map and .cod files, debugger extensions, and some ways to debug on a standalone device when a debugger's not an option.&lt;/p&gt; &lt;p&gt;Sue&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=379980" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sloh/archive/tags/Debugging_2C00_+Kernel+_2600_+misc.+File+System+issues/default.aspx">Debugging, Kernel &amp; misc. File System issues</category></item><item><title>It has been a while</title><link>http://blogs.msdn.com/sloh/archive/2005/02/17/375398.aspx</link><pubDate>Thu, 17 Feb 2005 20:21:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:375398</guid><dc:creator>sloh</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/sloh/comments/375398.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sloh/commentrss.aspx?PostID=375398</wfw:commentRss><description>&lt;p&gt;I would use being busy as an excuse, except I'm always busy.&amp;nbsp; ;-)&amp;nbsp; Call it, lack of creativity about coming up with blog entries.&amp;nbsp; I don't know how &lt;A href="http://blogs.msdn.com/mikehall/"&gt;Mike Hall &lt;/a&gt;does it.&lt;/p&gt; &lt;p&gt;Anyway I've gotten a couple of questions about allocating large amounts of memory, that really come down to understanding&amp;nbsp;the Windows CE virtual memory architecture, and especially to understanding the 32MB per process limit.&amp;nbsp; So I thought I'd post a link to Doug Boling's useful paper, &lt;a href="http://msdn.microsoft.com/library/en-us/dncenet/html/advmemmgmt.asp"&gt;http://msdn.microsoft.com/library/en-us/dncenet/html/advmemmgmt.asp&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=375398" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sloh/archive/tags/Debugging_2C00_+Kernel+_2600_+misc.+File+System+issues/default.aspx">Debugging, Kernel &amp; misc. File System issues</category></item><item><title>CE memory division between "storage" &amp; "program" memory</title><link>http://blogs.msdn.com/sloh/archive/2004/09/09/227599.aspx</link><pubDate>Fri, 10 Sep 2004 00:29:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:227599</guid><dc:creator>sloh</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/sloh/comments/227599.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sloh/commentrss.aspx?PostID=227599</wfw:commentRss><description>&lt;p&gt;Somehow I've been involved in a bunch of discussions on this subject lately, so I figured I might as well lay out some of the issues.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt;&amp;nbsp; What are the ways to set the way memory splits between storage &amp;amp; program memory?&amp;nbsp; Or in other words, how do I set the size of the object store?&lt;/p&gt; &lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt;&amp;nbsp; You have 3 options:&amp;nbsp; Set the size in OAL code by implementing the pOEMCalcFSPages function.&amp;nbsp; Set the size in OAL settings by changing&amp;nbsp;the value of&amp;nbsp;FSRAMPERCENT in config.bib.&amp;nbsp; Set the size&amp;nbsp;at run-time&amp;nbsp;by calling the SetSystemMemoryDivision function.&amp;nbsp; The CE&amp;nbsp;control panel "system" applet has a slider that users can drag to adjust the size; that just calls SetSystemMemoryDivision.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; What is the minimum size for the object store?&amp;nbsp; If all of my device settings are stored on a persistent file system, so that I don't use the object store at all, can I set the object store to 0?&lt;/p&gt; &lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; There is no way to completely get rid of the object store, even in the most recent OS version (5.0).&amp;nbsp; The absolute minimum value you can use is 28KB.&amp;nbsp;&amp;nbsp;If you're using FSRAMPERCENT, use&amp;nbsp;FSRAMPERCENT=0x00000004 which gives you 32KB.&amp;nbsp; If you are actually using the object store for some data, I can't really give you a minimum.&amp;nbsp; (eg. I can't say what the min. size required to boot successfully is.)&amp;nbsp; I suggest you find it by booting and seeing how much of the object store is consumed, using GetStoreInformation or GetDiskFreeSpace.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Q: &lt;/strong&gt;What is the maximum size for the object store?&lt;/p&gt; &lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; 256MB.&amp;nbsp; But since FSRAMPERCENT can't go that high, you'll have to use pOEMCalcFSPages for that.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; What is the minimum size for the program memory?&amp;nbsp; How do I guarantee that my device can boot?&lt;/p&gt; &lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt;&amp;nbsp;Again, t&lt;span class="464483020"&gt;here isn't any one minimum size I can give you.&amp;nbsp; It varies based on what components you have included in your image, and based on your own code.&amp;nbsp; &lt;/span&gt;&lt;span class="464483020"&gt;What I suggest is that you find out what the minimum number of free pages&amp;nbsp;was, after booting a system that has enough RAM.&amp;nbsp; Use the "mi" command from the target control window, and look for the "minfree pages" value.&amp;nbsp; That is a "low water mark" for the lowest number of free pages that were available at any one time.&amp;nbsp; Subtract that from the total pages to find out the maximum number of pages that were used at any one time.&amp;nbsp; I think the object store pages count in that total, so you should subtract the size of the object store, to get the maximum number of pages that were used for program memory.&amp;nbsp; T&lt;/span&gt;&lt;span class="464483020"&gt;hen add some space for safety -- say 24 pages.&amp;nbsp; (I just made that number up.)&amp;nbsp; Then use that as your minimum size for program memory.&amp;nbsp; So, that means use this formula:&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span class="464483020"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(minimum RAM size) = (total pages) - (minfree pages) - (number of object store pages) + (safety margin)&lt;/span&gt;&lt;/p&gt;&lt;span class="464483020"&gt; &lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; What is the maximum size for the program memory?&lt;/p&gt; &lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; 512MB, minus the 28KB minimum for the object store.&amp;nbsp; There is a way to extend past 512MB but that is a story for another day.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; How does FSRAMPERCENT work?&amp;nbsp; It is confusing.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span class="464483020"&gt;&lt;strong&gt;A:&lt;/strong&gt; Yes, it is confusing.&amp;nbsp; To help you understand where it is coming from: back in the days when memory was much smaller, OEMs wanted ways to give stair-step functions of memory, so that they could create multiple devices that vary only by the amount of RAM inside them.&amp;nbsp; FSRAMPERCENT says, for each of the first four 2MB chunks of RAM, how many 4KB pages per 1MB should be given to the object store.&amp;nbsp; So you could say, if my device has 2MB of RAM use this much; if it has 4MB use this other amount, etc.&amp;nbsp; pOEMCalcFSPages is a later way to solve the same problem, and is much more flexible.&amp;nbsp; Anyway here are some tips for reading and setting FSRAMPERCENT:&lt;/span&gt;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;span class="464483020"&gt;&lt;/span&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;To interpret a value like 0x40302010, take each byte separately.&amp;nbsp; Each byte represents the number of 4KB blocks per MB for 2MB.&amp;nbsp; So 0x40 x 4KB = 256KB per MB for 2MB; so the top byte&amp;nbsp;gives 512KB of RAM to the object store, and the remaining 1.5MB to program memory.&amp;nbsp; Likewise 0x30 --&amp;gt; 384KB storage, 1.625MB program; 0x20 --&amp;gt; 256KB storage, 1.75MB program; 0x10 --&amp;gt; 128KB storage, 1.875MB program.&amp;nbsp; Add them together for the total: 1.25MB storage and 6.75MB program.&amp;nbsp; Check that they add to 8MB.&amp;nbsp; Beyond the first 8MB, all the memory is used as program memory (I think).&amp;nbsp; Don't take my word for it.&amp;nbsp; :-)&lt;/span&gt; &lt;/font&gt;&lt;/font&gt; &lt;li&gt;&lt;font face="Times New Roman"&gt;&lt;font size="3"&gt;&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;To specify that N&amp;nbsp;bytes of RAM (where&amp;nbsp;28KB &amp;lt;= N &amp;lt; 2MB) should be given to the object store, round to the nearest 8KB boundary [N], then set the bottom byte of FSRAMPERCENT to&amp;nbsp;([N] / (4096 * 2)).&amp;nbsp; So for 28K, round up to 32K, divide by 8KB to get FSRAMPERCENT=0x04.&amp;nbsp; To specify amounts&amp;nbsp;between 2MB and 8MB set the bottom bytes to 0xFF, subtracting 2MB for each.&lt;/span&gt; &lt;/font&gt;&lt;/font&gt; &lt;li&gt;&lt;font face="Times New Roman" size="3"&gt;&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;To specify that P% of RAM (where&amp;nbsp;0 &amp;lt;=&amp;nbsp;P &amp;lt;= 100) should be given to the object store,&amp;nbsp;set each byte of FSRAMPERCENT to&amp;nbsp;((P / 100)&amp;nbsp;* (1MB&amp;nbsp;/ 4KB)), or&amp;nbsp;in simplified form (P * 2.56).&amp;nbsp; So for example to use 12.5% of RAM for the object store, use (12.5 * 2.56) = 32&amp;nbsp;= 0x20.&amp;nbsp; So the 4-byte value of FSRAMPERCENT would be 0x20202020.&amp;nbsp; To use 33.3% of RAM, set FSRAMPERCENT to&amp;nbsp;0x55555555.&lt;/span&gt;&lt;/font&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&lt;span class="464483020"&gt;&lt;strong&gt;Q:&lt;/strong&gt; When I change the division dynamically using SetSystemMemoryDivision or by moving the control panel slider, does that value persist?&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span class="464483020"&gt;&lt;/span&gt;&lt;span class="464483020"&gt;&lt;strong&gt;A:&lt;/strong&gt; If your device always warm-boots, the object store will always be there so its size will not change on reboot.&amp;nbsp; If your device always cold-boots, then the object store is recreated on every boot.&amp;nbsp;&amp;nbsp;The division is NOT saved anywhere so it will not persist across cold boots.&amp;nbsp; Every time you cold boot you get whatever size is specified&amp;nbsp;by FSRAMPERCENT / pOEMCalcFSPages.&amp;nbsp; &lt;em&gt;(The other variant of this question is: Why doesn't the registry value that stores the memory division seem to persist when the rest of my registry does?&amp;nbsp; The answer is that there is no such registry value.)&lt;/em&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span class="464483020"&gt;&lt;strong&gt;Q:&lt;/strong&gt;&amp;nbsp;Does all of this apply to PocketPC / MS Smartphone?&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span class="464483020"&gt;&lt;strong&gt;A:&lt;/strong&gt; Well, yes, except that PocketPC (and maybe SP, I'm not sure) has a background thread that dynamically moves the memory division in the background, so that you always have some storage memory and always have some program memory.&amp;nbsp; So any changes you make on PPC/SP will quickly go away when that thread kicks in.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span class="464483020"&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=227599" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sloh/archive/tags/Debugging_2C00_+Kernel+_2600_+misc.+File+System+issues/default.aspx">Debugging, Kernel &amp; misc. File System issues</category></item></channel></rss>