{"id":399,"date":"2011-11-06T20:47:15","date_gmt":"2011-11-06T18:47:15","guid":{"rendered":"http:\/\/lallafa.de\/blog\/?p=399"},"modified":"2011-11-06T20:47:15","modified_gmt":"2011-11-06T18:47:15","slug":"inside-vamos-part-2","status":"publish","type":"post","link":"https:\/\/lallafa.de\/blog\/2011\/11\/inside-vamos-part-2\/","title":{"rendered":"Inside vamos (Part 2)"},"content":{"rendered":"<p>Today we continue our little journey through my newest project and have a look at libraries and structures in the &#8220;virtual&#8221; Amiga RAM of vamos.<\/p>\n<p>Make sure to read <a title=\"vamos runs Amiga CLI programs on my Mac\" href=\"http:\/\/lallafa.de\/blog\/2011\/11\/vamos-runs-amiga-cli-programs-on-my-mac\/\">Part 1 of the series<\/a> first&#8230;<\/p>\n<p>Todays topics:<\/p>\n<ul>\n<li>Amiga Libraries<\/li>\n<li>Amiga Structures<\/li>\n<\/ul>\n<h3><!--more-->1. Amiga Libraries<\/h3>\n<p>We already know from our first expirments that an Amiga library has a large jump table for all functions which we already use to trap the calls and redirect them to our Python vamos code.<\/p>\n<p>The open question is now what functions does a library have and what registers are filled by the application before calling this function. Furthermore, we need to know what we have to return in the registers before returning to the caller. The last question is answered quickly: data registrer D0 is the return value of all lib calls (if the lib call isn&#8217;t void then no register contains a return value). So mapping the python trapped call return value to D0 was quickly done.<\/p>\n<p>For the function description in a library Commodore invented a textual programming language neutral description called the <strong>FD files<\/strong> describing each function call and the arguments required along with the CPU registers where the argument will be found.<\/p>\n<p>To simplify my work with vamos I first wrote a parser for the FD files (that can be found in the Amiga NDKs). This little tool is called <strong>fdtool<\/strong> and also available in my <a title=\"amitools\" href=\"http:\/\/lallafa.de\/blog\/amitools\/\">amitools<\/a> source tree. You simply call it with a single FD file and it shows all functions and the relative jump offset in the table:<\/p>\n<pre>&gt; .\/fdtool NDK_3.1\/Includes\\&amp;Libs\/fd\/exec_lib.fd \r\nNDK_3.1\/Includes&amp;Libs\/fd\/exec_lib.fd\r\n base: _SysBase\r\n #0001\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 30\u00c2\u00a0 0x001e\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 Supervisor [userFunction,a5]\r\n #0002\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 72\u00c2\u00a0 0x0048\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 InitCode [startClass,d0][version,d1]\r\n #0003\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 78\u00c2\u00a0 0x004e\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 InitStruct [initTable,a1][memory,a2][size,d0]\r\n #0004\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 84\u00c2\u00a0 0x0054\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 MakeLibrary [funcInit,a0][structInit,a1][libInit,a2][dataSize,d0][segList,d1]\r\n #0005\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 90\u00c2\u00a0 0x005a\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 MakeFunctions [target,a0][functionArray,a1][funcDispBase,a2]\r\n #0006\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 96\u00c2\u00a0 0x0060\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 FindResident [name,a1]\r\n #0007\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 102\u00c2\u00a0 0x0066\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 InitResident [resident,a1][segList,d1]\r\n #0008\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 108\u00c2\u00a0 0x006c\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 Alert [alertNum,d7]\r\n #0009\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 114\u00c2\u00a0 0x0072\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 Debug [flags,d0]\r\n #0010\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 120\u00c2\u00a0 0x0078\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 Disable \r\n #0011\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 126\u00c2\u00a0 0x007e\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 Enable \r\n #0012\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 132\u00c2\u00a0 0x0084\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 Forbid \r\n #0013\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 138\u00c2\u00a0 0x008a\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 Permit \r\n #0014\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 144\u00c2\u00a0 0x0090\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 SetSR [newSR,d0][mask,d1]\r\n #0015\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 150\u00c2\u00a0 0x0096\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 SuperState \r\n #0016\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 156\u00c2\u00a0 0x009c\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 UserState [sysStack,d0\r\n..<\/pre>\n<p>Its already very useful to decode jumps into the lib (Note: the jump uses a negative offset while the tools displays positive ones).<\/p>\n<p>The next step was to create a code generator that writes stubs for Python that describe all functions:<\/p>\n<pre>.\/fdtool -g NDK_3.1\/Includes\\&amp;Libs\/fd\/exec_lib.fd \r\n (30, 'Supervisor', (('userFunction', 'a5'),)),\r\n (36, 'execPrivate1', None),\r\n (42, 'execPrivate2', None),\r\n (48, 'execPrivate3', None),\r\n (54, 'execPrivate4', None),\r\n (60, 'execPrivate5', None),\r\n (66, 'execPrivate6', None),\r\n (72, 'InitCode', (('startClass', 'd0'), ('version', 'd1'))),\r\n (78, 'InitStruct', (('initTable', 'a1'), ('memory', 'a2'), ('size', 'd0'))),\r\n (84, 'MakeLibrary', (('funcInit', 'a0'), ('structInit', 'a1'), ('libInit', 'a2'), ('dataSize', 'd0'), ('segList', 'd1'))),\r\n (90, 'MakeFunctions', (('target', 'a0'), ('functionArray', 'a1'), ('funcDispBase', 'a2'))),\r\n (96, 'FindResident', (('name', 'a1'),)),\r\n (102, 'InitResident', (('resident', 'a1'), ('segList', 'd1'))),\r\n (108, 'Alert', (('alertNum', 'd7'),)),\r\n (114, 'Debug', (('flags', 'd0'),)),\r\n (120, 'Disable', None),\r\n (126, 'Enable', None),\r\n (132, 'Forbid', None),\r\n (138, 'Permit', None),\r\n (144, 'SetSR', (('newSR', 'd0'), ('mask', 'd1'))),\r\n (150, 'SuperState', None),\r\n<\/pre>\n<p>I simply copy &amp; paste this output in my ExecLibrary class and this table now describes all functions available and also their parameters. This information is not used for trapping in the first place but for logging: Now I can decode each jump into the Lib and display the named function call&#8230;<\/p>\n<pre>19:39:29.159\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 lib:\u00c2\u00a0\u00c2\u00a0 INFO:\u00c2\u00a0 [\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 exec.library]\u00c2\u00a0 { CALL:\u00c2\u00a0 198 AllocMem( byteSize[d0]=def4, requirements[d1]=10001 ) from PC=00205a\r\n19:39:29.159\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 lib:\u00c2\u00a0\u00c2\u00a0 INFO:\u00c2\u00a0 [\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 exec.library]\u00c2\u00a0 } END CALL: d0=000108ac\r\n19:39:29.159\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 lib:\u00c2\u00a0\u00c2\u00a0 INFO:\u00c2\u00a0 [\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 exec.library]\u00c2\u00a0 { CALL:\u00c2\u00a0 732 StackSwap( newStack[a0]=113e8 ) from PC=0020e8\r\n19:39:29.159\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 lib:\u00c2\u00a0\u00c2\u00a0 INFO:\u00c2\u00a0 [\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 exec.library]\u00c2\u00a0 } END CALL: d0=0000000<\/pre>\n<p>With this information in place I could add trapped functions by adding a new table to my Library object: this one maps the function offset (again positive) to an actual Python method inside the class. I can do this for only the functions I need &#8211; all others have a default handler that returns D0=0 and issues a warning trace that this function is still unimplemented.<\/p>\n<p>An excerpt of the Python <strong>ExecLibrary<\/strong> class looks like this:<\/p>\n<pre>def __init__(self):\r\n  exec_funcs = (\r\n\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 (408, self.OldOpenLibrary),\r\n\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 (414, self.CloseLibrary),\r\n\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 ...\r\n\u00c2\u00a0 )\r\n\u00c2\u00a0 self.set_funcs(exec_funcs)\r\n\r\ndef OpenLibrary(self, lib, ctx):\r\n\u00c2\u00a0 name_ptr = ctx.cpu.r_reg(REG_A1)\r\n\u00c2\u00a0 ...\r\n  return lib_addr\r\n<\/pre>\n<p>You see the mapping of Python functions in this example. Note that each Python call gets the same parameters and not the Amiga function calls directlly: It gets a context object and via this context the function can access the virtual CPU and read out the registers it needs&#8230;<\/p>\n<p>The return value of the Python method will be directly written to D0 automatically. Returning None will not alter D0. This is useful for void function calls.<\/p>\n<h3>2. Amiga Structures<\/h3>\n<p>The library jump tables are not the only kind of data an Amiga application directly accesses outside its own memory segments: A lot of public data structures reside in memory and function calls often pass in pointers to them and also private ones. Some functions even require to create new structures and we then need to return their pointers. Furthermore, each library itself has (beside the jump table) a so called &#8220;pos size range&#8221; that contains data structures of &#8220;public&#8221; accessible information. E.g. exec.library has a large pos size with lots of system constants and also information like your own task structure&#8230;<\/p>\n<p>Our task in vamos is now to correctly fill these structures as needed and provide a convinient mechanism in Python to access those data members. Unfortunately, those data structures are only defined in the language headers of Commodore&#8217;s NDKs and there is no generic description like there is the FDs for the calls \ud83d\ude41<\/p>\n<p>Without having a tool to decode some generic data structure definitions I started to convert the C Amiga headers manually into a Python structure definition. Those definition are not structures in Python itself but rather meta objects that describe a structure in the &#8220;virtual&#8221; Amiga Memory of vamos. This tedious process was only performed on demand, i.e. onyl the structures currently needed were transcribed to Pyhon.<\/p>\n<p>Similar to fdtool I have written a <strong>typetool <\/strong>to provide a small command line utility that uses the structures defined in Python and displays them (This is again useful for disassembly reading as you can quickly look up and index and find the structure entry):<\/p>\n<pre>.\/typetool Library\r\n @0000\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 Library {\r\n @0000\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 Node {\r\n0000 @0000\/0000 +0004\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 Node*\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 ln_Succ\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 (ptr=True, sub=False)\r\n0001 @0004\/0004 +0004\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 Node*\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 ln_Pred\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 (ptr=True, sub=False)\r\n0002 @0008\/0008 +0001\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 UBYTE\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 ln_Type\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 (ptr=False, sub=False)\r\n0003 @0009\/0009 +0001\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 BYTE\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 ln_Pri\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 (ptr=False, sub=False)\r\n0004 @0010\/000a +0004\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 char*\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 ln_Name\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 (ptr=True, sub=False)\r\n @0014 =0014\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 } lib_Node\r\n0005 @0014\/000e +0001\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 UBYTE\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 lib_Flags\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 (ptr=False, sub=False)\r\n0006 @0015\/000f +0001\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 UBYTE\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 lib_pad\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 (ptr=False, sub=False)\r\n0007 @0016\/0010 +0002\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 UWORD\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 lib_NegSize\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 (ptr=False, sub=False)\r\n0008 @0018\/0012 +0002\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 UWORD\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 lib_PosSize\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 (ptr=False, sub=False)\r\n0009 @0020\/0014 +0002\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 UWORD\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 lib_Version\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 (ptr=False, sub=False)\r\n0010 @0022\/0016 +0002\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 UWORD\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 lib_Revision\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 (ptr=False, sub=False)\r\n0011 @0024\/0018 +0004\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 APTR\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 lib_IdString\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 (ptr=False, sub=False)\r\n0012 @0028\/001c +0004\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 ULONG\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 lib_Sum\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 (ptr=False, sub=False)\r\n0013 @0032\/0020 +0002\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 UWORD\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 lib_OpenCnt\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 (ptr=False, sub=False)\r\n @0034 =0034\u00c2\u00a0 } \r\n<\/pre>\n<p>This query for the Library structure of Exec displays all entries including nested structures, their byte offset from the beginning, the C type and the name to access each entry.<\/p>\n<p>This structure information is now used for two purposes in vamos: First it provides a convinient way to access structures inside memory for the Python lib calls when they have to access data that was provided by giving structure pointers. The second use of structures is to provide so called <strong>memory labels<\/strong> for logging. Every time vamos allocates a structure (e.g. ExecLib pos space) it also registers a struct memory label for the same address. A label manager keeps all registered labels and if memory tracing is enabled then you can look up an arbitrary address if it can be labelled. A structure label looks like this:<\/p>\n<pre>19:22:23.891\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 mem:\u00c2\u00a0\u00c2\u00a0 INFO:\u00c2\u00a0 R(4): 0102a8: 00000000\u00c2\u00a0 Struct\u00c2\u00a0 [@010210 +000098 ThisTask] Process+152 = pr_CurrentDir(BPTR)+0\r\n19:22:23.892\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 mem:\u00c2\u00a0\u00c2\u00a0 INFO:\u00c2\u00a0 R(4): 0102bc: 00004070\u00c2\u00a0 Struct\u00c2\u00a0 [@010210 +0000ac ThisTask] Process+172 = pr_CLI(BPTR)+0\r\n19:22:23.892\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 mem:\u00c2\u00a0\u00c2\u00a0 INFO:\u00c2\u00a0 R(4): 0102bc: 00004070\u00c2\u00a0 Struct\u00c2\u00a0 [@010210 +0000ac ThisTask] Process+172 = pr_CLI(BPTR)+0\r\n19:22:23.892\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 mem:\u00c2\u00a0\u00c2\u00a0 INFO:\u00c2\u00a0 R(4): 0101d0: 00004080\u00c2\u00a0 Struct\u00c2\u00a0 [@0101c0 +000010 CLI] CLI+16 = cli_CommandName(BSTR)+0\r\n<\/pre>\n<p>So a read access to memory address<strong> 0x0102a8<\/strong> is detected as structure access to <strong>ThisTask.pr_CurrentDir<\/strong>. That&#8217;s what I call comfortable debugging ;)\u00c2\u00a0 Note that the labelling look ups cost quite a lot of performance and that&#8217;s the reason why you have to enable memory tracing with a command line switch (-t\/-T).<\/p>\n<p>The most common use of Structures is to decode lib call arguments. In Python I provide a so called <strong>AccessStruct<\/strong> object that assist reading\/writing structures:<\/p>\n<pre>def StackSwap(self, lib, ctx):\r\n stsw_ptr = ctx.cpu.r_reg(REG_A0)\r\n stsw = AccessStruct(ctx.mem, StackSwapDef, struct_addr=stsw_ptr)\r\n # get new stack values\r\n new_lower = stsw.r_s('stk_Lower')\r\n new_upper = stsw.r_s('stk_Upper')\r\n new_pointer = stsw.r_s('stk_Pointer')<\/pre>\n<p>This is an excerpt of the Python implemenation of the Exec StackSwap call: In A0 a pointer to a StackSwap structure is passed in. We have already declared the function in Python as a defintion (hence the trailing Def):<\/p>\n<pre>class StackSwapStruct(AmigaStruct):\r\n _name = \"StackSwap\"\r\n _format = [\r\n ('APTR', 'stk_Lower'),\r\n ('ULONG', 'stk_Upper'),\r\n ('APTR', 'stk_Pointer')\r\n ]\r\nStackSwapDef = StackSwapStruct()<\/pre>\n<p>With a memory pointer and a structure definition we can create an access object. Now the reads and writes to the entries of the structure a simple calls can be performed with the entry name of the structure&#8230; Ok its slower than direct offset handling but far more confortable and less error prone&#8230;<\/p>\n<p>Beside the structure access vamos also provides a more generic memory access object that allows to read and write blocks of data, reads c-type strings and bcpl strings with a single call:<\/p>\n<pre>def OpenLibrary(self, lib, ctx):\r\n ver = ctx.cpu.r_reg(REG_D0)\r\n name_ptr = ctx.cpu.r_reg(REG_A1)\r\n name = ctx.mem.access.r_cstr(name_ptr)\r\n ..<\/pre>\n<p>That&#8217;s it for today&#8230; I hope you got more insight on the Library and Struct handling and the confortable features available in vamos for working with them.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today we continue our little journey through my newest project and have a look at libraries and structures in the &#8220;virtual&#8221; Amiga RAM of vamos. Make sure to read Part 1 of the series first&#8230; Todays topics: Amiga Libraries Amiga &hellip; <a href=\"https:\/\/lallafa.de\/blog\/2011\/11\/inside-vamos-part-2\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[11,9],"tags":[],"class_list":["post-399","post","type-post","status-publish","format-standard","hentry","category-amiga","category-software"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/piBMF-6r","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/lallafa.de\/blog\/wp-json\/wp\/v2\/posts\/399","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lallafa.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lallafa.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lallafa.de\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/lallafa.de\/blog\/wp-json\/wp\/v2\/comments?post=399"}],"version-history":[{"count":9,"href":"https:\/\/lallafa.de\/blog\/wp-json\/wp\/v2\/posts\/399\/revisions"}],"predecessor-version":[{"id":408,"href":"https:\/\/lallafa.de\/blog\/wp-json\/wp\/v2\/posts\/399\/revisions\/408"}],"wp:attachment":[{"href":"https:\/\/lallafa.de\/blog\/wp-json\/wp\/v2\/media?parent=399"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lallafa.de\/blog\/wp-json\/wp\/v2\/categories?post=399"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lallafa.de\/blog\/wp-json\/wp\/v2\/tags?post=399"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}