crash handling

Estaba yo preguntándome esta tarde si sería posible lanzar de forma automática gdb cuando un programa cascara, sin necesidad de ponerse a depurar después, reproducir el bug, etc, al estilo del manejador de errores que instala Visual Studio en Windows que pregunta si se desea depurar la aplicación.

Me ha salido algo como esto (HTML horrible para el coloreado de sintaxis patrocinado por Vim):

#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

void attach_gdb(int signum)
{
    pid_t gdbpid;
    pid_t debuggee_pid = getpid();
    int gdb_exit_status;
    char pidbuf[100];
    char exebuf[100]; // should be safe unless PIDs reach ~90 digits ;P
    sprintf(pidbuf, "%d", debuggee_pid);
    sprintf(exebuf, "/proc/%d/exe", debuggee_pid);
    printf("Signal %d received. Attaching GDB to process. PID=%d\n", signum, debuggee_pid);

    if ((gdbpid = fork()) == 0)
    {
        execlp("gdb", "gdb", exebuf, pidbuf, NULL);
        perror("execlp");
        exit(1);
    }

    waitpid(gdbpid, &gdb_exit_status, 0); // hold on, we want to be debugged
    exit(1);
}

void __attribute__((constructor)) setup_handler()
{
    struct sigaction sa, old_sa;
    sa.sa_handler = attach_gdb;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags=0;
    // Register the handler for all actions which dump core by default
    sigaction(SIGSEGV, &sa, &old_sa);
    sigaction(SIGFPE, &sa, &old_sa);
    sigaction(SIGABRT, &sa, &old_sa);
    sigaction(SIGILL, &sa, &old_sa);
    sigaction(SIGQUIT, &sa, &old_sa);
}

Si se compila como librería dinámica y se enlaza a cualquiera de nuestros programas (o se precarga con LD_PRELOAD) lanza un gdb asociado al proceso al recibir cualquiera de las señales que causarían un core dump y terminación del programa :D.

¿Alguna idea para mejorarlo y que sea práctico? ¿Existe ya algo asi en un paquete Debian que hace mil cosas molonas más? (seguro que sí XD).

Jugando con Qt

El otro día me encontré con edb (una especie de OllyDbg para linux) y al ver la buena pinta que tenía me acordé de lo bonito que sería tener una interfaz gráfica para depurar en mi emulador de GameBoy. Me he puesto a juguetear con Qt y me está gustando. Está muy bien documentada y es bastante agradable de usar, una vez se pasa el susto de ver esas cosas raras como “public slots:” en mitad de la declaración de una clase en C++.

De momento he conseguido integrar el emu en una ventana de Qt, el redibujado va bastante más rápido de lo que me esperaba, y tengo el emulador en un hilo y la parte gráfica en otro. Ahora me falta empezar de verdad con el debugger. Ahi va un shot :)

qtboi screenshot

wenboi

Llevo algún tiempo escribiendo a ratos un emulador de Game Boy. Me picaba el tema de la emulación y shash me había comentado que la Game Boy era facililla de emular y me pasó algo de documentación. Pues bien, ha llegado el momento de que vea la luz. Con todos ustedes… wenboi!

wenboi screenshot

Todavía está en pañales pero ya se puede empezar una partida de Tetris y colocar piezas, y es éste el hito que me ha llevado a poner la etiqueta de “version 0.1″ y hablar un poquito del emulador aqui ;)

Por si alguien quiere cotillear, he creado una pequeña homepage de wenboi con información sobre el acceso al repositorio de Git y tambien he dado de alta a wenboi en Ohloh para que me analicen el repositorio, me saquen graficos de actividad y me digan que pongo pocos comentarios en el código. También hay un pequeño devlog que no sé si actualizaré demasiado.

Happy hacking!

ctypes

El otro día me encontré con un módulo interesante de python que no conocía: ctypes. Sirve para comunicarse con librerías en C: permite cargar librerías dinámicas y llamar a sus funciones, definir tipos equivalentes a los de C para pasarlos de un lado a otro e incluso especificar funciones python como callbacks de C. Vamos, que se pueden crear bindings a librerías externas escribiendo únicamente código python.

Ahi va un ejemplillo tonto usando la libavformat:

#!/usr/bin/python
import sys
from ctypes import *
import ctypes.util

av = CDLL(ctypes.util.find_library("avformat"))
filename = sys.argv[1]
# pFormatCtx deberia ser un puntero a AVFormatContext,
# pero esto es solo un ejemplo simple :)
pFormatCtx = c_void_p() 

av.av_register_all()
av.av_open_input_file(byref(pFormatCtx), filename, None, 0, None)
av.dump_format(pFormatCtx, 0, filename, 0)

Por supuesto para hacer algo más serio habría que declarar en python las estructuras como AVFormatContext que se definen en las cabeceras correspondientes y cosas así, pero entonces el programa de ejemplo sería demasiado engorroso como para leerlo en un blog ;). El ejemplo muestra una salida como esta:

$ ./av.py test.avi
Input #0, avi, from 'test.avi':
  Duration: N/A, bitrate: N/A
  Stream #0.0: Video: mpeg4, 512x420,   inf fps(c)
  Stream #0.1: Audio: vorbis, 22050 Hz, stereo, 24 kb/s

Referencias:

Trazas con gdb

Todo programador ha pasado alguna vez por la experiencia de depurar un programa a golpe de printf(), con los inconvenientes que ello supone, sobre todo recompilar cada vez que se quiere cambiar la información que se imprime en la traza.

Pues resulta que es posible hacer las cosas “bien” :)

Con gdb podemos imprimir los valores de variables de nuestro programa, eso es algo que todos sabemos PERO tambien podemos darle una serie de órdenes a ejecutar al pasar por un breakpoint.

Veamos un ejemplo. Sea el siguiente programa en C:

#include <stdio.h>

int main()
{
        int i;
        double x=2.0f;
        for (i=0; i<64; i++)
                x*=2;
        return 0;
}

Si compilamos con -g (para debug) y lo lanzamos en gdb podemos visualizar los valores de x así:


(gdb) break 8
Breakpoint 1 at 0x400463: file a.c, line 8.
(gdb) commands 1
Type commands for when breakpoint 1 is hit, one per line.
End with a line saying just "end".
>silent
>printf "x=%g\n",x
>cont
>end
(gdb) r
Starting program: /home/slack/a.out
x=2
x=4
x=8
x=16
x=32
x=64
[...]

El “silent” del principio es para que gdb no imprima la información que suele mostrar al pararse en un breakpoint (fichero, número de línea, contador de programa, etc) y la traza salga más limpia.

Por supuesto se pueden hacer mas cosas. gdb permite definir variables externas al programa y ejecución condicional, así que podemos contar las veces que pasamos por algun sitio y lanzar órdenes en momentos concretos y tonterías similares :D

Happy coding!

Querido diario…

Querido diario:

(advertencia: casi todo es improvisado, y hay muchos fallos).

Review: Hiromi Uehara – Valencia – 29/6/2007

El viernes pasado estuve en el concierto de Hiromi en los jardines del Palau de la Música de Valencia. Ya había leido algunas cosas sobre ella, pero ha superado mis expectativas más optimistas.

Me lo pasé en grande. La música genial, estuve todo el concierto sonriendo embobado escuchándoles tocar (y aún me dura). Aparte de eso, siempre me ha gustado ver a músicos pasándoselo bien y verla sobre el escenario con esa sonrisa juguetona mientras toca el piano no tiene precio. Ains, creo que me he enamorado…

Al final del concierto me quedé con ganas de gastarme el dinero y busqué el clásico tenderete con discos, pero solo había unos pocos de Martin Valihora, el batería, y no lo conozco lo suficiente. Pero bueno, hoy he salido de compras y me he vuelto con un Time Control bajo el brazo :)

Esperemos que vuelva a tocar pronto por aquí cerca.

Vámonos de congreso

Esta semana he pasado unos dias en Gerona, asistiendo al IbPRIA 2007. La primera vez que iba a un congreso con un paper bajo el brazo (antes habia estado de party en el Games2006).

Cosas buenas:

  • Pasarse 3 dias fuera y que (esperemos) el hotel y la inscripcion al congreso corran a cargo de la beca.
  • Asistir a la cena del congreso, no incluida en la inscripción de estudiante. Muchas gracias a las dos personas que nos cedieron amablemente los tickets que no iban a usar :D
  • Encontrarse con yero^Sector Omega nada más llegar al Auditorio. Siempre es bonito encontrarse con sceners in the wild :)
  • Al igual que en las parties, ver lo que han hecho los demás da ganas de ponerse a hacer cosas a la vuelta.

Cosas no tan buenas:

  • No haber hecho ni una sola foto: me olvidé la cámara en el hotel los 3 días.
  • El catering: comer de pie con el plato en la mano no mola.
  • No encontrar nada abierto el miércoles por la noche para tomarnos algo después de cenar.

En líneas generales una grata experiencia. Viajar mola :)

Síntesis musical para mí (o para torpes en general :) III

3) Más ondas básicas

No solo de senos vive el hombre (salvo que nos pongamos a hacer síntesis aditiva), así que vamos a ver unas cuantas ondas más que podemos utilizar como base para construir sonidos.

  • Onda cuadrada:

    Get the Flash Player to see this player.

    Se obtiene alternando dos valores (en nuestro caso +1 y -1) con la frecuencia deseada. Expresado en código, podría ser algo como esto:

    // Generacion del i-esimo sample de una onda cuadrada
    // de frecuencia f
    float t = i/sampling_rate; // instante i en segundos
    float periodo = 1.0f / f; // periodo de la onda en segundos
    if (fmodf(t,periodo) < periodo/2.0f)
        y[i] = 1.0f;
    else
        y[i] = -1.0f;
    

    Onda cuadrada.

    Otra posibilidad es hacer que las zonas a +1 y -1 no tengan la misma longitud (pulse width modulation)

  • Onda de diente de sierra:

    Get the Flash Player to see this player.

    En cada periodo, aumenta linealmente desde -1 a 1, cayendo bruscamente a -1 en el comienzo del siguiente periodo. Dicho en C viene a ser:

    // Sample i-esimo, frecuencia f
    float t = i/sampling_rate;
    float periodo = 1.0f / f;
    y[i] = 2.0f*(fmodf(t, periodo)/periodo)-1.0f;
    

    Onda de diente de sierra.

  • Onda triangular:

    Get the Flash Player to see this player.

    Es parecida a la anterior, pero durante la mitad del periodo crece linealmente de -1 a 1, y durante la otra mitad decrece linealmente volviendo a -1, sin discontinuidad.

    // Sample i-esimo, frecuencia f
    float t = i/sampling_rate;
    float periodo = 1.0 / f;
    float semiperiodo = periodo/2.0f;
    if (fmodf(t,periodo) < periodo/2.0f)
        y[i] = 2.0f*(fmodf(t,semiperiodo)/semiperiodo)-1.0f;
    else
        y[i] = 1.0f-2.0f*fmod(t,semiperiodo)/semiperiodo;
    

    Onda triangular.

En el programa de ejemplo de este capítulo (ahora con un 100% más de Makefile) está todo esto en forma compilable para poder probarlo fácilmente. Por cierto, ninguno de los ejemplos está optimizado porque pretenden ser lo más claros posible, si alguien tiene sugerencias sobre como implementar mejor cualquier cosa nos lo podemos pasar muy bien comentándolas :)

En fin, esto es todo por hoy. En el próximo post, cosillas sobre espectros de frecuencias y aliasing (supongo que la pereza me obligará a dejarme los filtros para dentro de dos posts :)

EDIT: A peticion de pplux, ahi van los enlaces a los posts anteriores:

Síntesis musical para mí (o para torpes en general :) II

2) Senos!!!

Después del ruido del capitulo anterior, vamos a pasar a algo ligeramente más interesante: la onda senoidal. Como podéis ver si seguís el enlace a la pagina sobre la onda senoidal en la wikipedia, junto con dibujitos y explicaciones interesantes, la formula es:

y = A·sin(w·t + fase)

donde A es la amplitud de la onda (la distancia entre una cresta y un valle), w es la frecuencia en radianes/segundo y t es el tiempo. Vamos a ignorar la fase porque no nos hace falta :)

Como nos gusta trabajar con frecuencias en hercios, multiplicamos por 2·pi. Además, tenemos que t = samples generados / frecuencia de muestreo. Por lo tanto en el código tendremos algo como:

y[i] = A*sin(2*pi*frecuencia*(i/sampling_rate))

para el sample i-ésimo desde el inicio del sonido. Vamos a ver el trozo de código correspondiente (lo que falta es, básicamente, la inicialización del capítulo anterior):

void play(void *userdata, Uint8 *stream, int len)
{
    int num_samples = len / 2;
    Sint16 *dst_buf = (Sint16*) stream;
    for (int i=0; i<num_samples ; ++i)
        buffer[i] = sin(2.0*M_PI*440.0f*(i+pos)/(float)SAMPLING_RATE);

    // Clipping y conversion a Sint16
    for (int i=0; i<num_samples; ++i)
    {
        float v = buffer[i];
        if (v > 1.0f)
            v = 1.0f;
        else if (v< -1.0f)
            v = -1.0f;

        dst_buf[i] = (Sint16)(32767.0f*v);
    }
    pos += num_samples;

}

Detalles destacables de esta función:

  • se trabaja con un buffer de floats y se convierte a entero al final. No mola ir perdiendo precisión por el camino, sobre todo cuando hagamos cosas mas complejas
  • hay clipping a [-1.0, 1.0]. Ahora mismo es completamente innecesario porque sin() devuelve valores en ese intervalo, pero cuando empecemos a mezclar varios sonidos vendrá bien :)
  • en la llamada a sin(), el 440.0f es la frecuencia de la nota que suena (un La4), y pos es una variable global que guarda el índice del ultimo sample generado entre llamadas a play(). Es feo, pero para un ejemplo pequeño va bien.

En el próximo episodio (ahora es tarde y tengo sueño), veremos otros osciladores típicos y cosas interesantes que se pueden hacer con ellos.

EDIT: herotyc me ha enviado una versión stand-alone del ejemplo de este capítulo. ¡Muchas gracias! :)