Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
####### # # E-scripts on DaVinci (only things not in scintilla.e or iup.e) # # Note 1: use the eev command (defined in eev.el) and the # ee alias (in my .zshrc) to execute parts of this file. # Executing this file as a whole makes no sense. # An introduction to eev can be found here: # # (find-eev-quick-intro) # http://angg.twu.net/eev-intros/find-eev-quick-intro.html # # Note 2: be VERY careful and make sure you understand what # you're doing. # # Note 3: If you use a shell other than zsh things like |& # and the for loops may not work. # # Note 4: I always run as root. # # Note 5: some parts are too old and don't work anymore. Some # never worked. # # Note 6: the definitions for the find-xxxfile commands are on my # .emacs. # # Note 7: if you see a strange command check my .zshrc -- it may # be defined there as a function or an alias. # # Note 8: the sections without dates are always older than the # sections with dates. # # This file is at <http://angg.twu.net/e/davinci.e> # or at <http://angg.twu.net/e/davinci.e.html>. # See also <http://angg.twu.net/emacs.html>, # <http://angg.twu.net/.zshrc[.html]>, # <http://angg.twu.net/escripts.html>, # and <http://angg.twu.net/>. # ####### (find-es "davinci") (find-es "iup") (find-es "scintilla") Note: I'm trying to split my notes about the DaVinci project into several e-script files (iup.e, davinci.e, peek.e, ...) - but at the moment there are lots of duplications and lots of garbage... # «.correspondencia» (to "correspondencia") # «.cronograma-inicial» (to "cronograma-inicial") # «.tcmd.tcl» (to "tcmd.tcl") # «.tcmd-screenshot» (to "tcmd-screenshot") # «.ldb-rewriting-functions» (to "ldb-rewriting-functions") # «.ldbenv» (to "ldbenv") # «.eepitch-gdb» (to "eepitch-gdb") # «.testing-intro.lua» (to "testing-intro.lua") # «.wish-event-loop» (to "wish-event-loop") # «.iup-event-loop» (to "iup-event-loop") # «.peek.lua» (to "peek.lua") # «.peek.lua:diagrams» (to "peek.lua:diagrams") # «.peek.lua:doc» (to "peek.lua:doc") # «.debugging-wish» (to "debugging-wish") ##### # # Links para partes da correspondência com o Scuri # 2007jul03 # ##### # «correspondencia» (to ".correspondencia") # (code-c-d "davinciprivate" "~/DAVINCI/") # (code-c-d "davincimails200706" "~/DAVINCI/mails-2007jun.html") # (code-ps "davinciedital" "~/DAVINCI/EditalUniversal_daVinci.pdf") # (code-pdftotext "davinciedital" "~/DAVINCI/EditalUniversal_daVinci.pdf") # (find-davinciprivatefile "") # (find-davincieditalpage 1) # (find-davincieditaltext) # (find-davincimails200706w3m "" "tarefa" "console") # (find-davincimails200706w3m "" "tarefa" "editor") # (find-davincimails200706w3m "" "tarefa" "debug") # (find-davincimails200706w3m "" "tarefa" "gerenciador de projetos") ##### # # Cronograma inicial # 2007jul03 # ##### # «cronograma-inicial» (to ".cronograma-inicial") Horas Descrição ( ) Ldb (1) Baixar versão atual ( ) Preparar exemplos de uso (pra usar com eepitch), incluindo: (2) Um que liste os nomes das funções no call stack (2) Um que liste variáveis locais numa dessas funções (1) Um que liste upvalues de uma dessas funções ( ) Um que sete breakpoints ( ) Um com single-stepping (dois modos: em terminologia do GDB, step/next) (4) Ver como o Rici está transformando closures em nomes de funções (2) Limpar e documentar isso: (find-angg "LUA/lua50init.lua" "preparef2n") (1) Localizar o código do Ldb que converte frame height <-> marker + offset ( ) Lua: aprender o que falta da parte em C (2) Que estruturas representam (open/closed) upvalues? (4) Completar o diagrama em (find-es "lua-intro" "bytecode:captures") ( ) Fazer uma versão gráfica desse diagrama (com inkscape ou xfig) (4) Entender as funções que acessam o stack com índices positivos e negativos (4) Descobrir quais são as estruturas do pool de strings (4) Ressucitar o (find-angg "LUA/lua50init.lua" "load_PP") (4) Comparar com (find-pilw3m "24.2.3.html" "stackDump") (4) Ver o que o Rici fez de correspondente no ldb (2) Encontrar o código de GC que varre as posições válidas do stack (4) Descobrir como o código do traceback dá nomes para closures/funções ( ) Lua: aprender o que falta da debug lib (4) Rodar os exemplos do PiL (4) Ler a documentação do TecMake (1) Descobrir que valores dar pras environment vars que ele usa (3) Testar esses valores e encontrar um subset mínimo (2) Descobrir como rodá-lo em modo verboso (4) Tentar compilar o IUP com ele (dessa vez a sério) ( ) Tentar compilar o LuaCmd com ele (não, isso ainda não) ( ) Binários do IUP e do LuaCmd (1) Baixar (4) Tentar rodar o IUP a partir dos binários (4) Tentar rodar o LuaCmd a partir dos binários (2) IUP: procurar (e rodar) exemplos de uso na documentação (2) LuaCmd: procurar (e rodar) exemplos de uso na documentação (0) Conseguir o endereço de MSN do Scuri (1) Descobrir quem são as pessoas com quem eu devo falar na PUC (1) Mandar e-mail pra elas sobre compilar o IUP com o TecMake - (0) Tentar marcar um horário ( ) Descobrir o e-mail do Alexandre que ficou interessado no dednat4 ( ) Passar na PUC ( ) Conhecer as pessoas do TecGraf e do IUP ( ) Imprimir o artigo sobre a VM e encaderná-lo (espiral) ( ) Pedir ajuda com o TecMake ( ) Perguntar pro Sérgio (?) mais sobre o compilador de Lua em Lua (0) Aprender SciTe (parte em Lua - a partir do SciTe) (6) Ler os docs no luawiki (8) Testar os exemplos (0) Descobrir como chamar named commands pelo nome (como M-x no emacs) (0) Descobrir como criar named commands novos ( ) Aprender SciTe e Scintilla (parte social) (2) Descobrir onde estão as mailing lists (1) Me inscrever nelas (2) Baixar arquivos das mailing lists (2) Pôr um link pra minha página sobre o davinci no luawiki ( ) Bindings de Lua pro Scintilla ( ) Descobrir como o Kein-Hong Man fez os bindings para SciTe ( ) Descobrir se ele fez algo pro Scintilla também (4) Criar uma página sobre o DaVinci (0) Ligá-la com a minha página de Lua (luaforth.html) (0) Ligá-la com os e-scripts (davinci.e, lua5.e, lua-intro.e) (0) Ligá-la com as páginas do luawiki ( ) Aprender SciTe (parte em C) (0) Compilar a partir das fontes Debian (ok) (3) Compilar o Scintilla e o Scite a partir das fontes upstream (0) Verificar se o módulo Lua está habilitado por default no Debian (0) Verificar se o módulo Lua está habilitado por default no upstream (1) Localizar os bindings (1) Escolher um binding pouco usado (1) Mudar o código dele - incluir um printf("Hello\n") (1) Confirmar que isso funciona (e que o stdout funciona) ( ) Descobrir como criar um named command novo (em C) ( ) Descobrir como chamar named commands pelo nome (como M-x no emacs) ( ) Fazer um named command que imprima "Hello" ( ) Descobrir como usar a região ( ) Fazer um named command que imprima a região no stdout ( ) Documentação do eev (1) Implementar um truque novo no blogme: [_ texto] (2) Htmlizar o roadmap (que está em papel). ( ) Ver se com o roadmap já dá pras pessoas (algumas) decifrarem os e-scripts ( ) Fazer uma documentação (mínima) para o eepitch: (1) screenshot de verdade (1) ascii screenshot (2) incluir no eev-article.html (1) Consertar os docs sobre M-k e M-K (1) Consertar os links sobre M-k e M-K aqui: (find-efunctiondescr 'eev-mode) (2) Htmlizar o (find-efunctiondescr 'eev-mode) ( ) GDB (no Emacs) (2) Fazer um eepitch-gdb, para mandar comandos para o gdb (2) Encontrar um setting de 3 janelas que funcione com o eepitch (2) Adaptar os exemplos envolvendo GDB e Lua para o eepitch (1) Fazer screenshots e ascii screenshots ( ) TCmd (1) Terminar o código: (find-es "tcl" "text-widget") (0) Exportar o arquivo para a angg (como ~/TCL/tcmd.tcl) ( ) Localizar o screenshot do SciTe rodando algo como um TCmd em Python (1) Implementar a divisão em janelas (file e vars) (1) Descobrir como marcar uma linha em vermelho (com o tag currentline) (0) Descobrir como remover todos os overlays com o tag currentline (1) Implementar comando: setfile (0) Implementar comando: setvars (1) Implementar comando: setline (1) Implementar uma função "tcmd" em Lua (writefile + system/getoutput) (setq last-kbd-macro (kbd "<delete> <right> C-k <delete> SPC")) (+ 1 2 2 1 4 2 1 2 4 4 4 4 4 4 2 4 4 4 1 3 2 4 1 4 4 2 2 0 1 1 0 0 6 8 0 0 2 1 2 2 4 0 0 0 0 3 0 0 1 1 1 1 1 2 1 1 2 1 1 2 2 2 2 1 1 0 1 1 0 1 0 1 1 ) ;; -> 134 http://www.tecgraf.puc-rio.br/iup/en/guide.html#buildlib ##### # # tcmd.tcl # 2007jul04 # ##### # «tcmd.tcl» (to ".tcmd.tcl") # (find-angg "DAVINCI/tcmd.tcl") # (find-angg "TH/davinci.blogme") # http://angg.twu.net/DAVINCI/tcmd.tcl # http://angg.twu.net/DAVINCI/tcmd.tcl.html # http://angg.twu.net/DAVINCI/tcmd-1.png # http://www.tecgraf.puc-rio.br/luacmd/debug.gif # http://www.tecgraf.puc-rio.br/luacmd/ ##### # # TCmd: code to take a screenshot # 2007jul04 # ##### # «tcmd-screenshot» (to ".tcmd-screenshot") # (set-face-bold-p 'comint-highlight-input nil) # (set-face-bold-p 'comint-highlight-input t) * (eepitch-shell) * (eepitch-kill) * (eepitch-shell) cd ~/DAVINCI/tcmd.tcl & echo setfile ~/usrc/lua-5.1.2/test/fib.lua > /tmp/ee.tcmd.tcl kill -USR2 $(cat /tmp/ee.tcmd.pid) echo -e 'setvars "n = 4\nN = 1"' > /tmp/ee.tcmd.tcl kill -USR2 $(cat /tmp/ee.tcmd.pid) echo setline 5 > /tmp/ee.tcmd.tcl kill -USR2 $(cat /tmp/ee.tcmd.pid) echo setline 6 > /tmp/ee.tcmd.tcl kill -USR2 $(cat /tmp/ee.tcmd.pid) kill $(cat /tmp/ee.tcmd.pid) # Upload: Scp ~/DAVINCI/tcmd-1.png edrx@angg.twu.net:slow_html/DAVINCI/ ##### # # ldb - rewriting some functions # 2007jul10 # ##### # «ldb-rewriting-functions» (to ".ldb-rewriting-functions") -- (find-ldbfile "ldb.lua" "function statemeta.proxystack(state)") -- (find-ldbfile "ldb.lua" "function statemeta:makecontext(env)") -- (find-ldbfile "ldb.lua" "function makeinfovar(info, sentinel, erroffset)") -- (find-ldbfile "ldb.lua" "function State(sentinel, env)") -- (find-ldbfile "ldb.lua" "function statemeta.proxystack(state)") -- (find-ldbfile "ldb.lua" "function Memoize(func)") -- a part of rici's "Memoize", rewritten memoize_meta = function (func) return { __index = function(tbl, key) local value = func(key); tbl[key] = value; return value end } end -- a part of rici's "statemeta.proxystack", rewritten stackframe_meta = function (state, stack) return { __add = function (self, offset) if type(offset) == "number" then return stack[stack[self] + offset] end end, __sub = function (self, offset) if type(offset) == "number" then return stack[stack[self] - offset] end end, __index = function (self, key) local info = state[stack[self]] if infokeys[key] then return info[key] elseif infofuncs[key] then return infofuncs[key](info) else return info.var[key] end end, __newindex = function (self, key, val) local info = state[stack[self]] if infokeys[key] or infofuncs[key] then error(key.." cannot be modified") else info.var[key] = val end end } end -- the main part of rici's "statemeta.proxystack", rewritten statemeta.proxystack = function (state) local stack = {} setmetatable(stack, memoize_meta(function (level) if type(level) == "number" and state[level] then local rv = setmetatable({}, stackframe_meta(state, stack)) stack[rv] = level return rv end end) return stack end -- My first attempt to rewrite rici's "statemeta.proxystack". Delete this. statemeta.proxystack = function (state) local stack -- defined below local function StackFrame() return setmetatable({}, { __add = function (self, offset) if type(offset) == "number" then return stack[stack[self] + offset] end end, __sub = function (self, offset) if type(offset) == "number" then return stack[stack[self] - offset] end end, __index = function (self, key) local info = state[stack[self]] if infokeys[key] then return info[key] elseif infofuncs[key] then return infofuncs[key](info) else return info.var[key] end end, __newindex = function (self, key, val) local info = state[stack[self]] if infokeys[key] or infofuncs[key] then error(key.." cannot be modified") else info.var[key] = val end end }) stack = Memoize(function (level) if type(level) == "number" and state[level] then local rv = setmetatable({}, stackframe_meta(state, stack)) stack[rv] = level return rv end end) return stack end -- (find-pilfile "") -- (find-pilgrep "grep -nH -e emoize *") -- (find-pilw3m "17.1.html") -- (find-lua51file "") ##### # # ldb - making it use an environment (ldbenv) and no locals # 2007jul16 # ##### # «ldbenv» (to ".ldbenv") # (find-ldbfile "") # (find-ldbfile "ldb.lua") # (find-ldbfile "ldb.lua" "return env.ldb") We should do "return env.ldb, env" - or something like that. Test this: ldbenv = setmetatable({ }, { __index = _G }) setfenv(ldbenv) Then define some "global" functions that call one another and some "real" globals, like "print", that are inherited through __index. ##### # # Sections about eepitch and GUD for the eev-article # 2007jul12 # ##### # «eepitch-gdb» (to ".eepitch-gdb") # http://angg.twu.net/eev-article.html # (find-eevarticlesection "channels") # (find-eevarticlesection "eepitch") # (find-angg ".emacs" "eepitch-gdb") (This is a draft, full of errors, describing some code that does not yet exist (ee-tbr), etc. Also, I don't know Rubikitch's real name, so I used a random Japanese name...) Sending lines to processes running in Emacs buffers: eepitch ============================================================ Emacs can run external programs interactively inside buffers; in the screenshot in Figure 5 there's a shell running in the buffer "*shell*" in the lower window. Technically, what is going on is much more complex than what we described in the previous section. The shell runs in a pseudo-terminal (pty), but ptys are usually associated to rectangular grids of characters with a definite width and height, while in an Emacs buffer the width of each line, and the total number of lines,are only limited by memory constraints. Many interactive programs expect their input to come through their more-or-less minimalistic line editors, that may try to send to the terminal commands like "clear the screen" or "go to column x at line y"; how should these things be handled in a shell buffer? Also, the user can move freely in a shell buffer, and edit its contents as text, but in some situations the user will hit the "Return" key, Emacs should select a part of the current line - except maybe some initial characters that are seen as a prompt - and send that to the shell process, as if the user had typed exactly that; so, Emacs takes over the line editor of the shell process completely. The translation between character sequences going through the pty and buffer-editing functions is very tricky, full of non-obvious design choices, and even though it has been around for more than 20 years it still has some (inevitable) quirks. I almost never used shell buffers, so I found the following idea, by OGAMI Itto, very surprising when he sent it to the eev mailing list in 2005. (Figure 5 will be a screenshot that I haven't taken yet.) (It will be simpler than the scvreenshot from Fig. 6, that is this: http://angg.twu.net/IMAGES/eepitch-gdb.png ) The current window, above in Figure 5, is editing an e-script, and the other window shows a shell buffer - that we will refer to as the "target buffer". When the user types a certain key - by default F8 - the current line is sent to the target buffer, and the point is moved down to the next line; pressing F8 n times in sequence sendsn lines, one by one. One detail: "sending a line" means inserting its contents - except the newline - at the current position in the target buffer, and then running there the action associated to the "Return" key. "Return" is almost always a special key, bound to different actions in different major modes, so just inserting a newline would not work. [wouldn't simulate what happens when a user types "Return"]. (anchor here) Note that, in a sense, the action of F8 is much more complex than that of F9, described in the last section; but user might perceive F8 as being much simpler, as there are no external programs involved (Expect, eegchannel, xterm), and no setup hassles - all the machinery to make Emacs buffers invoke external processes in buffers pretending to be terminals ("comint mode") comes built-in with Emacs since the early 1980s. Ogami's idea also included three "bonus features": window setup, reconstruction of the target buffer, and star-escapes. In the default Emacs setting some commands - M-x shell between them - might split the current Emacs frame in two windows; none of eev's hyperlink functions do that, and I have always felt that it is more naturalto use eev with a setting (pop-up-windows set to nil) that disables window splittings except when explicitly requested by the user. Anyway: M-x shell ensures that a "*shell*" buffer is visible in a window, and that a shell process is running in it; this setup code for F8, (eepitch '(shell)) splits the window (if the frame has just one window), and runs `(shell)' in the other window - with the right defaults - to force that window to display a shell buffer with a live shell process running in it; it also sets a variable, eepitch-target-buffer, to that buffer, so that the next `F8's will have a definite buffer to send lines too - as target buffers need not necessarily be shell buffers. As for the star-escapes, it's the same idea as with F9: when a line starts with a red star glyph, running F8 on it executes everything on it - after the red star - as Lisp, and if there are no errors the point is moved down. So lines starting with a red star can be used to set up an eepitch target, to switch to another target, or to do special actions - like killing a certain target so that it will be reconstructed anew by the next F8. Note that once that we recognize that a region of an e-script is to be used by eepitch there is only one key to be used to "run" each of its lines, both the ones with red stars and the ones without: F8. However, as with F9, the user must know what to expect after each step. A badly-written e-script for eepitch may try, for example, to "cd" into a directory that doesn not exist, and if the next line is, say, "tar -xvzf $S/http/foo/bar.tgz" then it will try to unpack a tarball into the wrong place, creating a big mess. Using eepitch to control unprepared shells ------------------------------------------ # (find-eevfile "eev.el" "EEVDIR") # (find-eevfile "eev.el") As we have seen in section 4, M-x eev sends the region to a "prepared shell"; if the shell has the right settings for the environment variables $EEVTMPDIR and $EE, and if it has the shell function `ee', then running `ee' in the shell "sources" the temporary script - corresponding to the regin - in verbose mode. Well, if Emacs loads eev.el and the environment variables $EEVDIR, $EEVTMPDIR and $EE are not set, then they are set, respectively, to the directory where eev.el was read from, to the subdirectory of it given by $EEVDIR/tmp, and to the file $EEVTMPDIR/ee.sh. Processes started from Emacs inherit these environment variables, so a shell buffer created by running F8 on these two lines, * (eepitch-shell) function ee () { set -v; . $EE; set +v; } will be running a prepared shell. Such buffers can be used to let users understand better how prepared shells work, and decide if they want to patch their initialization files for the shell (see eev-rctool) so that their shells will be "prepared" by default. [IT (Note: I haven't yet played much with this idea - discuss running eev-rctool on such shells (and a function that creates a buffer with an e-script for that), and loading psne.sh from an unprepared shell).] Controlling debuggers with eepitch ---------------------------------- # (find-node "(emacs)Debuggers") # (find-node "(gdb)Top") On *NIX it is common to keep debuggers separated into two parts: a back-end, with a simple textual interface, and a front-end, that controls the back-end via its textual interface but presents a better interface, showing source files and breakpoints in a nice way, etc. The GNU Debugger, GDB, is a back-end, and it can be used to debug and single-step several compiled languages; the "Grand Unified Debugger" mode of Emacs, a.k.a. GUD, is a front-end for GDB and other back-ends. Usually, GUD splits an Emacs frame into two windows, one for interaction with GDB (or other back-end, but let's say just "GDB" for simplicity), and another one for displaying the source file where the execution is. Some of the output of GDB - lines meaning, e.g., "we're at the source file foo.c, at line 25" - are filtered by GUD and are not shown in the GUD buffer; and the user can press special key sequences on source files that generate commands to GDB - like, "set a breakpoint on this line". In order to control GDB with eepitch we need a window setting with three windows, like in the screenshot in Figure 6. http://angg.twu.net/IMAGES/eepitch-gdb.png ^ Figure 6 will be this The way to set up that does not integrate very well with the "standard" eepitch at this moment, but that should come with time. E-scripting GDB with eepitch ---------------------------- # (find-node "(gdb)Set Breaks" "`tbreak ARGS'") # (find-node "(elisp)The Buffer List") We can use elisp hyperlinks to point to specific lines in source files - and we can combine these hyperlinks with the code to set up breakpoints, in two ways. *;(find-lua51file "src/lvm.c" "case OP_CLOSE:" 1) * (find-lua51file "src/lvm.c" "case OP_CLOSE:" 1 '(ee-tbr)) The first line above contains an elisp hyperlink to a line in the source of Lua. Actually, it points to the code for an opcode in Lua's virtual machine that most people find rather mysterious. As the line starts with `*;', an F8 on it executes a Lisp comment - i.e., does nothing - and moves down; only a `M-e' (or a `C-e C-x C-e') on that line would follow the hyperlink. The second line, when executed with F8, would go to that line in the source, then run `(ee-tbr)' there; ee-tbr invokes gud-tbr to set a temporary breakpoint on that source line (i.e., one that is disabled when the execution stops there for the first time), and then buries the buffer - the one with "lmv.c" - like a `M-K' would do; the effect is that the buffer in that window - the top-left window in a situation like in Figure 6 - does not change, it will still show the e-script. A variation on this is to wrap the hyperlink in an ee-tbr: * ; (find-lua51file "src/lvm.c" "case OP_CLOSE:" 1) * (ee-tbr '(find-lua51file "src/lvm.c" "case OP_CLOSE:" 1)) When ee-tbr is called with an argument it evaluated the argument inside a save-excursion, and sets a breakpoint there; the effect is almost the same as the previous case, but this does not change the order of the buffers in the buffer list. Two little languages for debugging ---------------------------------- E-scripts for eepitch and GDB can be used to bring programs to a certain point (and to inspect their data structures there; we will have more to say about this in the next section). In a sense, as in [Bentley], these e-scripts are written in a language that describes states of running programs - and they can be executed step by step. These e-scripts, being executable, can be used in e-mails to communicate particular states of programs - say, where a certain bug occurs. Unfortunately, they are too fragile and may cease working after minimal changes in the program, and they are almost impossible to read... However, the screenshot in Figure 5 suggests another language for communicating controlling programs with GDB: the contents of the "*gud*" buffer. After removing some excess verbosity by hand we get something that is readable enough if included in e-mails - and to extract the original commands from that we just have to discard the lines that don't start with "(gdb)", then remove the "(gdb)" prompts. As for the hyperlinks with `(ee-tbr)', they may need to be copied to the GUD buffer, and not filtered out; we still need to experiment with different ways to do that to be able to choose one. Inspecting data in running programs ----------------------------------- Almost anyone who has learned a bit of Lisp should be familiar with this kind of box diagrams. After running (setq x '(5 "ab")) (setq y (list x x '(5 "ab"))) the value of y can be represented by: ___ ___ ___ ___ ___ ___ |___|___| --> |___|___| --------> |___|___| --> nil | ___________/ | |/ | _v_ ___ ___ ___ _v_ ___ ___ ___ |___|___| --> |___|___| --> nil |___|___| --> |___|___| --> nil | | | | v v v v 5 "ab" 5 "ab" This representation is verynice - it omits lots of details that are usually irrelevant, like the address in the memory of each cons, and the exact names of each struct in C and their fields. But sometimes we need to understand the implementation in C, and a more complete diagram would be convenient. At least, we would like to know how to get, in the C source of Emacs, from the address of the leftmost cons in the top line to the rightmost "ab" in the bottom line - but how do we express following the "cdr" arrows, the "car" arrows, and extracting the contents of a string object in elisp, One solution is to use GDB, and e-scripts for it: ... A "complete diagram" corresponding to the one above, whatever the format that we choose to draw it, should include some information explaining that "cdr" arrows correspond to "->cdr", "car" arrows correspond to ..., and each string object corresponds to another kind of box different from the cons boxes; to get to the C string stored in an elisp string object we should examine its "foo" field, i.e., do a "->foo". Obviously, this same idea applies also to other programs with complex data structures - and for some programs we may even have fancier ways to explore their data structures; for example, in a graphic toolkit it might be possible to change the background of a button to orange from GDB. ##### # # Testing intro.lua # 2007jul19 # ##### # «testing-intro.lua» (to ".testing-intro.lua") # (find-angg "DAVINCI/intro.lua") # (find-angg "DAVINCI/tcmd.tcl") # Install Tcl/Tk and Expect. # (Packages are available for most distributions). # Download and compile SciTe 1.74 (upstream). # Install the dependencies; get the list from: # http://ftp.debian.org/debian/pool/main/s/scite/scite_1.71-1.dsc # (find-es "davinci" "scite-upstream") mkdir ~/DAVINCI/ cd ~/DAVINCI/ wget http://angg.twu.net/DAVINCI/intro.lua wget http://angg.twu.net/DAVINCI/tcmd.tcl wget http://angg.twu.net/LUA/lua50init.lua * (eepitch-shell) # (find-angg "DAVINCI/intro.lua") cd ~/DAVINCI/ ~/usrc/scite174/scite/bin/SciTE intro.lua & * (eepitch-shell) kill $(cat /tmp/ee.tcmd.pid) * (eepitch-kill) * (eepitch-shell) cd ~/DAVINCI/ ./tcmd.tcl & ~/usrc/scite174/scite/bin/SciTE intro.lua & # (find-angg "DAVINCI/tcmd.tcl") kill $(cat /tmp/ee.tcmd.pid) cd ~/DAVINCI/ ./tcmd.tcl & * (eepitch-shell) cd ~/DAVINCI/ cp -v ~/usrc/lua-5.1.2/test/fib.lua . kill $(cat /tmp/ee.tcmd.pid) ~/DAVINCI/tcmd.tcl & * (eepitch-lua51) tcmd = function (tclcode) writefile("/tmp/ee.tcmd.tcl", tclcode) local output = getoutput("kill -USR2 $(cat /tmp/ee.tcmd.pid)") if output ~= "" then error(output) end end tcmd("setfile fib.lua") tcmd('setvars "n = 4\nN = 1"') tcmd("setline 5") tcmd("setline 6") # (find-scitegrep "grep -niH -e '\"editor\"' $(find *)") # (find-scitefile "scite/src/LuaExtension.cxx" "\"editor\"") ##### # # Scite ST and friends # 2007jul24 # ##### http://caladbolg.net/scite.php http://caladbolg.net/scite/images/pm.png http://caladbolg.net/scite_snippets.php http://caladbolg.net/scite_st.php http://scite-tools.googlecode.com/svn/trunk/scripts/doc/snippets_doc.txt http://scitetools.wordpress.com/ ##### # # LuaEclipse and RemDebug # 2007jul24 # ##### http://lists.luaforge.net/pipermail/luaeclipse-developers/ http://www.keplerproject.org/remdebug/ http://lua-users.org/lists/lua-l/2005-09/msg00602.html http://lua-users.org/lists/lua-l/2006-06/msg00426.html http://lists.luaforge.net/pipermail/kepler-project/2007-July/000997.html ##### # # Wish's event loop # 2007jul26 # ##### # «wish-event-loop» (to ".wish-event-loop") # (find-es "tcl" "wish-event-loop") # (find-es "iup" "iup-event-loop") ##### # # IUP's event loop # 2007jul30 # ##### # «iup-event-loop» (to ".iup-event-loop") # (find-fline "~/LOGS/2007jul30.scuri") # (find-iupgrep "grep -nH -e MainLoop $(find *)") # (find-iupfile "srclua5/iuplua_api.c" "static int MainLoop(lua_State *L)") # (find-iupfile "src/mot/motif.c" "int IupMainLoop (void)") ##### # # Scite/Scintilla's event loop # 2007aug08 # ##### # (find-scites "") ##### # # peek.lua: notes # 2007jul30 # ##### # «peek.lua» (to ".peek.lua") PrimitiveType("int", 4) PrimitiveType("unsignedint", 4) PrimitiveType("char", 1) PrimitiveType("unsignedchar", 1) PointerTo (nil, "void*") PointerTo ("char", "char*") PointerTo ("char*", "char**") ArrayOf ("char*", "char*[7]", 7) ArrayOf ("char*[7]", "char*[7][4]", 4) PointerTo ("char*[7][4]", "char*[7][4]*") StructOf ("int i char c", "struct:ic") TypedefTo ("struct:ic", "ic") ArrayOf("char", "char[12]", 12) -- (gdb) ptype month -- type = char *[4][7] -- (gdb) ptype &month -- type = char *(*)[4][7] -- (gdb) p month -- $1 = {{0x8048468 "Aa", 0x804846b "Bb", 0x804846e "Cc", 0x8048471 "Dd", -- 0x8048474 "Ee", 0x8048477 "Ff", 0x804847a "Gg"}, -- {0x804847d "Hh", 0x8048480 "Ii", 0x8048483 "Jj", 0x8048486 "Kk", -- 0x8048489 "Ll", 0x804848c "Mm", 0x804848f "Nn"}, -- {0x8048492 "Oo", 0x8048495 "Pp", 0x8048498 "Qq", 0x804849b "Rr", -- 0x804849e "Ss", 0x80484a1 "Tt", 0x80484a4 "Uu"}, -- {0x80484a7 "Vv", 0x80484aa "Ww", 0x80484ad "Xx", 0x80484b0 "Yy", -- 0x80484b3 "Zz", 0x80484b6 ";:", 0x80484b9 ",."}} -- (gdb) p &month -- $2 = (char *(*)[4][7]) 0x8049600 -- Methods: -- :star() -- :plus(k) -- :box(k) -- :amp() -- :field(fieldname) -- :arrow(fieldname) -- :value() -- :sizeof() -- int i; -- i === {addr=1000000, type="int", value="\00\00\00\42"} ctype_meta = { } CType = function (type, tbl) tbl[type] = type ctypes[type] = setmetatable(tbl, ctype_meta) end PrimitiveType = function (type, sizeof) CType(type, { kind = "prim", sizeof = sizeof }) end PointerTo = function (base, type) CType(type, { kind = "*", sizeof = 4, star = base }) end ArrayOf = function (base, type, n) local basesizeof = ctypes[base].sizeof CType(type, { kind = "[]", sizeof = n and n * basesizeof, star = base }) end PrimitiveType("unsignedint", 4) PrimitiveType("char", 1) PrimitiveType("unsignedchar", 1) PointerTo (nil, "void*") PointerTo ("char", "char*") PointerTo ("char*", "char**") ArrayOf ("char*", "char*[7]", 7) ArrayOf ("char*[7]", "char*[7][4]", 4) PointerTo ("char*[7][4]", "char*[7][4]*") -- StructOf ("int i char c", "struct:ic") -- TypedefTo ("struct:ic", "ic") ctype_meta.star = function( pointer_star = function (cobj) -- {addr=2000, type="int*"}:star() = {addr=peekptr(2000), type="int"} -- {addr=2000, type="int[5]"}:star() = {addr=2000, type="int"} -- {addr=2000, type="int[]"}:star() = {addr=2000, type="int"} pointer_meta = { sizeof = function (cobj) return 4 end star = function (cobj) return Cobj {addr = peekptr(cobj.addr), type = cobj:type().star} } c4tonumber = function (c4) local bt = string.byte local a, b, c, d = bt(c4, 1), bt(c4, 2), bt(c4, 3), bt(c4, 4) return a + 256 * (b + 256 * (c + 256 * (d))) end peekptr = function (addr) return c4tonumber(peek(addr, 4)) end * (eepitch-lua51) = string.byte(string.char(200, 233), 2) ##### # # peek.lua: diagrams (the oldest ones) # 2007aug01 # ##### # «peek.lua:diagrams» (to ".peek.lua:diagrams") #* cd /tmp/ cat > charptr.c <<'%%%' char c='@'; char *cp; char ca[]="@ABCD"; char ca5[5]; int main () { return 0; } %%% gcc -g -Wall -o charptr charptr.c #* ;; (find-efunction 'eepitch-gdb-lua-kill) (defun eepitch-gdb-charptr () (eepitch-gdb "*gud-charptr*" "gdb --annotate=3 /tmp/charptr")) (defun eepitch-gdb-charptr-kill () (eepitch-gdb-kill "*gud-charptr*")) * (eepitch-gdb-charptr-kill) * (eepitch-gdb-charptr) ptype ca5 ptype *ca5 ptype ca5+0 ptype c ptype &c ptype cp ptype *cp ptype ca ptype ca+0 +------------------+ | addr=1000 | | type="char[5]" | | value="@ABCD" | +-| | sizeof=5 | / | star="char" | / | amp= | |---+ * / +------------------+ \ weaken / | \ / | +0 \ v v v +----------------+ +-------------------+ +------------------+ | addr=1000 | | addr=nil | | addr=1000 | | type="char" | & | type="char*" | +0 | type="char[]" | | value="@" | |-------> | value=toc4(1000) | deref | value=nil | | sizeof=1 | <-------| | sizeof=4 | <------| | sizeof=nil | | star=nil | * | star="char" | | star="char" | | amp="char*" | | amp="char**" | | amp="char[]*"?| +----------------+ +-------------------+ +------------------+ ^ ^ \ | +0 \ - * \ +-------------------+ \ | addr=2000 | \ | type="char*" | +-| | value=toc4(1000) | | sizeof=4 | | star="char" | | amp="char**" | +-------------------+ ##### # # peek.lua - documentation # 2007aug02 # ##### # «peek.lua:doc» (to ".peek.lua:doc") Inspirations: PiL: (find-pilw3m "25.3.html" "A Generic Call Function") cdecl: (find-es "anatocc" "cdecl") cinvoke: (find-es "lua5" "cinvoke") evil.rb: (find-es "ruby" "evil.rb") gdb: (find-es "gdb" "C-types") swig: (find-es "swig" "C-types-as-strings") Primitive types =============== "char", "int", etc are primitive types, with sizeofs 1, 4, etc. Names of types and "TD" ("type data") ===================================== For each type name "t" the table TD has an entry describing its "type data" - its sizeof, its name, how it reacts to the ampersand and star operators, etc. The table TD lets us refer to types by their names. Array types =========== If "t" is a type and "n" is a non-negative integer, then "t[n]" is a type with sizeof = n * TD["t"].sizeof. When "t" doesn't have a sizeof we can't create a type "t[n]". If "t" is a type with a sizeof then "t[]" is a type without a sizeof. When "t" doesn't have a sizeof then we can't create a type "t[]". We can't create types like "char[5][][2]" or "char[5][][]". Pointer types ============= If "t" is a type then "t*" is a type with sizeof 4. A type like "char[5][]**[2]" is valid. "void" is a special primitive type with no sizeof. "void*" is a type with sizeof 4. Arrays and pointers in C and in peek.lua ======================================== A declaration in C like char *(*mptr)[4][7]; corresponds to: char *(((*mptr)[4])[7]); If we write the "[...]"s at the left this becomes: char *([7]([4](*mptr))); This is the order that we will use for type names in peek.lua; it lets us get rid of the parentheses. In peek.lua, after a declaration corresponding to the one above, the variable "mptr" would have type "char*[7][4]*"; "*mptr" would have type "char*[7][4]", "[3]*mptr" would have type "char*[7]", "[6][3]*mptr" would have type "char*", and "*[6][3]*mptr" would have type "char". Struct types ============ If "t", "u" and "v" are types with sizeofs, then a declaration like this in C, struct s { t a; u b; v c; }; corresponds to defining these types in TD: "struct:s" "struct{t:a;u:b;v:c;}" The TD entry for "struct:s" points to the entry for "struct{t:a;u:b;v:c;}". When we omit the name of the struct in C, as in struct { t a; u b; v c; }; then this corresponds to having just the entry "struct{t:a;u:b;v:c;}" in TD; the entry "struct:s" is not created. The sizeof of the resulting "struct" types is the sum of the sizeofs of the fields of the struct. We can only create a struct type when all the fields have sizeofs. We can create a struct with field of type "t*" (that has sizeof = 4) even if the type "t" has no sizeof, or if its sizeof is unknown at the moment of the creation of the struct type. Union types =========== "union" types are like "struct" types, with "union" replacing "struct" everywhere. The sizeof of a "union" type is the maximum of the sizeofs of its fields. peek ==== We will only need to define one Lua function in C: peek. "peek(addr, len)" returns the result of reading len bytes from the memory, starting from the address addr, as a Lua string len bytes long. The definition of peek is as simple as possible, and it will happily segfault when given a bad addr. C objects ========= If "t" is a type with a sizeof, the a "C object with type "t" in memory" can be seen as a triple: {addr=a, type="t", value=v}, where a is an integer - the address where the object starts in the memory - and v is its "value", as a sequence of bytes (a string). If "t" is a type without a sizeof - for example, "char[]" - then we can represent a C object of type "t" in memory as just a pair {addr=a, type="t"}. We can represent an "immediate object" of type "t" - for example, an integer that is the result of an expression - as a pair {type="t", value=v}, with v being a string sizeof "t" bytes long. We can't have an immediate object of type "t" when "t" doesn't have a sizeof: it wouldn't have an addr, and it couldn't have a value. A possible notation for C objects: (type) value at addr. Examples: (char[5]) {'@', 'A', 'B', 'C', 0} at 1000 (char[5]) $4041424300 at 1000 (char) '@' at 1000 (char) $40 at 1000 (char*) 1000 at 2000 (char*) 1000 (char[]) at 1000 Function types ============== Consider the following program in C: char a[] = {'@', 'A', 'B', 'C', 0}; char f(int i) { return a[i]; } char (*fp)(int i) = f; The linker sess "a" as being a certain (fixed) position in the initialized data segment - the beginning of the five bytes of the array - and "f" as being a certain (fixed) position in the code segment. Also, a[2] is a char, f(2) is a char, (*fp)[2] is a char - so arrays and functions are similar, and if we write the "(...)"s at the left as we did with the "[...]"s, we have that "[2]a" is of type "char", "a" is of type "char[]", "(2)f" is of type "char", "f" is of type "char(int:i)", "(2)*fp" is of type "char", "*fp" is of type "char(int:i)", "fp" is of type "char(int:i)*". The rule for constructing function types is this: if "t" is either a type with a sizeof or "void", and if "u", "w", and "w" are either types with sizeofs or types of the form "x[]", and if "a", "b", and "c" are names for variables, then "t(u:a,v:b,w:c)", "t(u:a,v:b,w:c,...)", "t(void)", "t()" are types with no sizeofs. Dereferencing ============= In C arrays are "dereferenced" into pointers when they are used as values, and if "t" is a type with a sizeof, then "t*" and "t[]" as almost equivalent when used as types in argument lists of functions. The code generated for the functions g1 and g2 below is the same: char a[] = {'@', 'A', 'B', 'C', 0}; char b[] = {'@', 'A', 'B', 'C', 0}; int g1(char *cp) { return cp[2]; } int g2(char cp[]) { return cp[2]; } int h() { g1(a); g2(a); } [Two differences: inside g1 we could add a line like "cp = b", but inside g2 that would be invalid; and inside g1 and g2 the "cp"s would react differently to "&" - give details using a notation like "(char*)1000" and "(char[]) at 1000"...] +--------+ | | | Code | | | +--------+ The "real" code has been moved to: (find-angg "DAVINCI/peek.lua") (find-angg "DAVINCI/peek-luadecls-1.txt") (find-angg "DAVINCI/peek-luadecls-2.txt") Old stuff: * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) TD = {} newctype = function (kind, typename, sizeof, td) td.kind = kind td.type = typename td.sizeof = sizeof TD[typename] = td PP(td) end BaseType = function (new, sizeof) newctype("base", new, sizeof, {}) end ArrayOf = function (old, new, n) newctype("array", new, n and (n * TD[old].sizeof), {star=old}) end PointerTo = function (old, new, n) newctype("pointer", new, 4, {star=old}) end eachfielddecl = function (str) return each2(split(str, "([^%s;]+)")) end StructOrUnion = function (kind, fielddecls, shortname) local totalsize = 0 local fields = {} local descriptions = {} for type,varname in eachfielddecl(fielddecls) do local fieldsize = TD[type].sizeof local offset = (kind=="union") and 0 or totalsize table.insert(descriptions, type..":"..varname) table.insert(fields, {type=type, name=varname, offset=offset}) fields[varname] = table.getn(fields) totalsize = (kind=="union") and math.max(totalsize, fieldsize) or totalsize + fieldsize end local longname = kind.."{"..table.concat(descriptions, ",").."}" newctype(kind, longname, totalsize, {fields=fields}) if shortname then newctype(kind, shortname, totalsize, {fields=fields}) end end StructOf = function (fielddecls, shortname) StructOrUnion("struct", fielddecls, shortname) end UnionOf = function (fielddecls, shortname) StructOrUnion("union", fielddecls, shortname) end BaseType ("int", 4) BaseType ("char", 1) BaseType ("void", nil) PointerTo("void", "void*") PointerTo("char", "char*") PointerTo("char*", "char**") ArrayOf ("char*", "char*[7]", 7) ArrayOf ("char*[7]", "char*[7][4]", 4) PointerTo("char*[7][4]", "char*[7][4]*") StructOf ("int i; char c;", "struct:ic") UnionOf ("int ii; char cc;", "union:iicc") -- TypedefTo("struct:ic", "ic") -- not yet --[[ {"kind"="base", "sizeof"=4, "type"="int"} {"kind"="base", "sizeof"=1, "type"="char"} {"kind"="base", "type"="void"} {"kind"="pointer", "sizeof"=4, "star"="void", "type"="void*"} {"kind"="pointer", "sizeof"=4, "star"="char", "type"="char*"} {"kind"="pointer", "sizeof"=4, "star"="char*", "type"="char**"} {"kind"="array", "sizeof"=28, "star"="char*", "type"="char*[7]"} {"kind"="array", "sizeof"=112, "star"="char*[7]", "type"="char*[7][4]"} {"kind"="pointer", "sizeof"=4, "star"="char*[7][4]", "type"="char*[7][4]*"} {"fields"={1={"name"="i", "offset"=0, "type"="int"}, 2={"name"="c", "offset"=4, "type"="char"}, "c"=2, "i"=1}, "kind"="struct", "sizeof"=5, "type"="struct{int:i,char:c}"} {"fields"={1={"name"="i", "offset"=0, "type"="int"}, 2={"name"="c", "offset"=4, "type"="char"}, "c"=2, "i"=1}, "kind"="struct", "sizeof"=5, "type"="struct:ic"} {"fields"={1={"name"="ii", "offset"=0, "type"="int"}, 2={"name"="cc", "offset"=0, "type"="char"}, "cc"=2, "ii"=1}, "kind"="union", "sizeof"=4, "type"="union{int:ii,char:cc}"} {"fields"={1={"name"="ii", "offset"=0, "type"="int"}, 2={"name"="cc", "offset"=0, "type"="char"}, "cc"=2, "ii"=1}, "kind"="union", "sizeof"=4, "type"="union:iicc"} --]] methods = {} methods.base = {} methods.typedef = {} methods.array = {} methods.pointer = {} methods.struct = {} methods.union = {} methods.generic = {} cobject_meta = { __index = function (cobj, key) local td = TD[cobj,type] local mt = methods[td.kind] return td[key] or mt[key] or methods.generic[key] end } methods.array.star = function (cobj) return CObject {type=cobj.star, addr=cobj:getvalue()} end methods.pointer.star = function (cobj) return CObject {type=cobj.star, addr=cobj.addr} end methods.array.plus = function (cobj) end methods.pointer.plus = function (cobj) end methods.generic.amp = function (cobj) return CObject {type=cobj.type.."*", value=assert(cobj.addr)} end +-------------------------+ | | | Stuff to write about: | | | +-------------------------+ (char[5]) ------| {'@','A','B','C',0} |-- / at 1000 \ * / - \ weaken / | +0 \ v & v +0 v (char) '@' |----> (char*) 1000 <-------| (char[]) at 1000 <----| ^ deref at 1000 ^ * | \ | +0 * \ - -------| (char*) 1000 at 2000 PrimitiveType("int", 4) PrimitiveType("char", 1) PrimitiveType("void", nil) PointerTo ("void", "void*") PointerTo ("char", "char*") PointerTo ("char*", "char**") ArrayOf ("char*", "char*[7]", 7) ArrayOf ("char*[7]", "char*[7][4]", 4) PointerTo ("char*[7][4]", "char*[7][4]*") StructOf ("int i; char c;", "struct:ic") TypedefTo ("struct:ic", "ic") -- Methods (not implemented yet!!!): -- :star() -- :amp() -- :plus(k) -- :field(fieldname) -- :peek() -- :box(k) -- :arrow(fieldname) -- :value() -- (gdb) ptype month -- type = char *[4][7] -- (gdb) ptype &month -- type = char *(*)[4][7] -- (gdb) p month -- $1 = {{0x8048468 "Aa", 0x804846b "Bb", 0x804846e "Cc", 0x8048471 "Dd", -- 0x8048474 "Ee", 0x8048477 "Ff", 0x804847a "Gg"}, -- {0x804847d "Hh", 0x8048480 "Ii", 0x8048483 "Jj", 0x8048486 "Kk", -- 0x8048489 "Ll", 0x804848c "Mm", 0x804848f "Nn"}, -- {0x8048492 "Oo", 0x8048495 "Pp", 0x8048498 "Qq", 0x804849b "Rr", -- 0x804849e "Ss", 0x80484a1 "Tt", 0x80484a4 "Uu"}, -- {0x80484a7 "Vv", 0x80484aa "Ww", 0x80484ad "Xx", 0x80484b0 "Yy", -- 0x80484b3 "Zz", 0x80484b6 ";:", 0x80484b9 ",."}} -- (gdb) p &month -- $2 = (char *(*)[4][7]) 0x8049600 -- int i; -- i === {addr=1000000, , type="int", value="\00\00\00\42"} ##### # # peek.lua - random notes # 2007jul26 # ##### # A tool for introspection # Inspired by: (find-es "ruby" "evil.rb") # (find-lua51file "src/") * (eepitch-gdb-lua-kill) * (eepitch-gdb-lua) # (find-node "(gdb)Print Settings") # (find-node "(gdb)Debugging C") # (find-node "(gdb)Assignment" "values into arbitrary places") show print union ptype UpVal # (find-lua51file "src/lua.h") ptype lua_State ptype lua_CFunction ptype lua_Reader ptype lua_Writer ptype lua_Alloc ptype lua_Number ptype lua_Integer ptype lua_Debug ptype lua_Hook # # (find-lua51file "src/llimits.h") ptype lu_int32 ptype lu_mem ptype l_mem ptype lu_byte ptype L_Umaxalign ptype l_uacNumber ptype Instruction # # (find-lua51file "src/lobject.h") ptype GCObject ptype GCheader ptype Value ptype TValue ptype StkId ptype TString ptype Udata ptype Proto ptype LocVar ptype UpVal ptype CClosure ptype LClosure ptype Closure ptype TKey ptype Node ptype Table (gdb) (gdb) # (find-lua51file "src/lua.h") (gdb) ptype lua_State type = struct lua_State { GCObject* next; lu_byte tt; lu_byte marked; lu_byte status; StkId top; StkId base; global_State* l_G; CallInfo* ci; Instruction* savedpc; StkId stack_last; StkId stack; CallInfo* end_ci; CallInfo* base_ci; int stacksize; int size_ci; shortunsignedint nCcalls; lu_byte hookmask; lu_byte allowhook; int basehookcount; int hookcount; lua_Hook hook; TValue l_gt; TValue env; GCObject* openupval; GCObject* gclist; struct:lua_longjmp* errorJmp; ptrdiff_t errfunc; } (gdb) ptype lua_CFunction type = int(*)(lua_State*) (gdb) ptype lua_Reader type = char*(*)(lua_State*,void*,size_t*) (gdb) ptype lua_Writer type = int(*)(lua_State*,void*,size_t,void*) (gdb) ptype lua_Alloc type = void*(*)(void*,void*,size_t,size_t) (gdb) ptype lua_Number type = double (gdb) ptype lua_Integer type = int (gdb) ptype lua_Debug type = struct lua_Debug { int event; char* name; char* namewhat; char* what; char* source; int currentline; int nups; int linedefined; int lastlinedefined; char[60] short_src; int i_ci; } (gdb) ptype lua_Hook type = void(*)(lua_State*,lua_Debug*) (gdb) # (gdb) # (find-lua51file "src/llimits.h") (gdb) ptype lu_int32 type = unsignedint (gdb) ptype lu_mem type = unsignedint (gdb) ptype l_mem type = int (gdb) ptype lu_byte type = unsignedchar (gdb) ptype L_Umaxalign type = union { double u; void* s; longint l; } (gdb) ptype l_uacNumber No symbol "l_uacNumber" in current context. (gdb) ptype Instruction type = unsigned int (gdb) # (gdb) # (find-lua51file "src/lobject.h") (gdb) ptype GCObject type = union GCObject { GCheader gch; union:TString ts; union:Udata u; union:Closure cl; struct:Table h; struct:Proto p; struct:UpVal uv; struct:lua_State th; } (gdb) ptype GCheader type = struct GCheader { GCObject* next; lu_byte tt; lu_byte marked; } (gdb) ptype Value type = union { GCObject* gc; void* p; lua_Number n; int b; } (gdb) ptype TValue type = struct lua_TValue { Value value; int tt; } (gdb) ptype StkId type = struct lua_TValue { Value value; int tt; } * (gdb) ptype TString type = union TString { L_Umaxalign dummy; struct { GCObject* next; lu_byte tt; lu_byte marked; lu_byte reserved; unsignedint hash; size_t len; } tsv; } (gdb) ptype Udata type = union Udata { L_Umaxalign dummy; struct { GCObject* next; lu_byte tt; lu_byte marked; struct:Table* metatable; struct:Table* env; size_t len; } uv; } (gdb) ptype Proto type = struct Proto { GCObject* next; lu_byte tt; lu_byte marked; TValue* k; Instruction* code; struct:Proto** p; int* lineinfo; struct:LocVar* locvars; TString** upvalues; TString* source; int sizeupvalues; int sizek; int sizecode; int sizelineinfo; int sizep; int sizelocvars; int linedefined; int lastlinedefined; GCObject* gclist; lu_byte nups; lu_byte numparams; lu_byte is_vararg; lu_byte maxstacksize; } (gdb) ptype LocVar No symbol "LocVar" in current context. (gdb) ptype UpVal type = struct UpVal { GCObject *next; lu_byte tt; lu_byte marked; TValue *v; union { TValue value; struct {...} l; } u; } (gdb) ptype CClosure type = struct CClosure { GCObject *next; lu_byte tt; lu_byte marked; lu_byte isC; lu_byte nupvalues; GCObject *gclist; struct Table *env; lua_CFunction f; TValue upvalue[1]; } (gdb) ptype LClosure type = struct LClosure { GCObject *next; lu_byte tt; lu_byte marked; lu_byte isC; lu_byte nupvalues; GCObject *gclist; struct Table *env; struct Proto *p; UpVal *upvals[1]; } (gdb) ptype Closure type = union Closure { CClosure c; LClosure l; } (gdb) ptype TKey type = union TKey { struct { Value value; int tt; struct Node *next; } nk; TValue tvk; } (gdb) ptype Node type = struct Node { TValue i_val; TKey i_key; } (gdb) ptype Table type = struct Table { GCObject *next; lu_byte tt; lu_byte marked; lu_byte flags; lu_byte lsizenode; struct Table *metatable; TValue *array; Node *node; Node *lastfree; GCObject *gclist; int sizearray; } (gdb) type = struct Table { GCObject *next; lu_byte tt; lu_byte marked; lu_byte flags; lu_byte lsizenode; struct Table *metatable; TValue *array; Node *node; Node *lastfree; GCObject *gclist; int sizearray; } (gdb) type = struct Table { GCObject *next; lu_byte tt; lu_byte marked; lu_byte flags; lu_byte lsizenode; struct Table *metatable; TValue *array; Node *node; Node *lastfree; GCObject *gclist; int sizearray; } (gdb) # (find-lua51file "src/lua.h") * (eepitch-gdb-lua-kill) * (eepitch-gdb-lua) ptype Proto ptype GCObject ptype GCheader ptype TString ptype L_Umaxalign p sizeof(L_Umaxalign) p sizeof(double) p sizeof(void *) p sizeof(long int) ptype lu_byte ptype size_t ctype["unsignedchar"] = { sizeof = 1 } ctype["lu_byte"] = { sizeof = 1 } ctype["GCObject*"] = { sizeof = 4 } ##### # # lcmd.lua # 2007jul27 # ##### # (find-es "lua5" "lua-ex") ##### # # debugging wish # 2007aug13 # ##### # «debugging-wish» (to ".debugging-wish") # (find-es "tcl" "luatclbridge") # (find-tk84file "") # (find-tk84file "odb") # (find-tk84file "odb" "-o wish") # (find-tk84file ".files" "unix/libtk8.4.so") # (find-tk84sh "cd unix; ldd ./wish") # (find-angg ".zshrc" "tcl-tk") # (find-angg ".emacs" "tcl-tk") * (setenv "LD_LIBRARY_PATH" (getenv "TCLTK_LD_LIBRARY_PATH")) * (eepitch-gdb-wish) * (eepitch-gdb-wish-kill) * (eepitch-gdb-wish) br Tcl_FindExecutable y run p argv0 # (find-sh "objdump -xasf $TKSRCDIR/wish") # (find-node "(stabs)Top") # (find-node "(stabs)C Example") # (find-node "(stabs)Assembly Code") # (find-angg "LUA/luatclbridge.c") lua-l, 2008nov03, Peter Cawley: If you want to do this, and make it feel natural to Lua, then it is a bit of a pig to do: Create a table (T), assign it a fresh metatable (MT), add an __index metamethod to MT which reads the value from the C structure and then add a __newindex metatable to MT which writes the value to the C structure. http://trac.clozure.com/openmcl/wiki/OpenMclFfi # Local Variables: # coding: utf-8-unix # End: