Holas, el día de hoy como último post del año 2020 quiero comentarles sobre rust-gdb y cómo utilizarlo para depurar nuestros programas escritos en Rust.

rust-gdb no es mas que un script que añade ciertos parámetros al poderoso depurador GDB, de esta manera la depuración en Rust se hace más amigable que utilizando unicamente GDB, si están interesados en lo que contiene el script de rust-gdb es lo siguiente:

#!/bin/sh
# Exit if anything fails
set -e

# Prefer rustc in the same directory as this script
DIR="$(dirname "$0")"
if [ -x "$DIR/rustc" ]; then
  RUSTC="$DIR/rustc"
else
  RUSTC="rustc"
fi

# Find out where the pretty printer Python module is
RUSTC_SYSROOT="$("$RUSTC" --print=sysroot)"
GDB_PYTHON_MODULE_DIRECTORY="$RUSTC_SYSROOT/lib/rustlib/etc"

# Run GDB with the additional arguments that load the pretty printers
# Set the environment variable RUST_GDB to overwrite the call to a
# different/specific command (defaults to gdb).
RUST_GDB="${RUST_GDB:-gdb}"
PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" exec ${RUST_GDB} \
  --directory="$GDB_PYTHON_MODULE_DIRECTORY" \
  -iex "add-auto-load-safe-path $GDB_PYTHON_MODULE_DIRECTORY" \
  "[email protected]"

Para nuestro ejemplo de depuración vamos a escribir un programa super sencillo que agregue valores a un Vector, luego imprima todo el vector y al final los valores que posee.

Nuestro ejemplo tiene como nombre vectors.rs

fn main() {
    // Instanciamos un nuevo Vector
    let mut vector = Vec::new();
    // Añadimos valores al vector
    vector.push(1);
    vector.push(2);
    vector.push(3);
    vector.push(4);
    vector.push(5);

    // Imprimimos todo el vector
    println!("Vector is: {:?}", vector);

    // Imprimimos cada valor del vector
    println!("\nVector Values:");
    for x in &vector {
        println!("{}", x);
    }
}

Para compilarlo y que pueda ser depurable, vamos a hacerlo de la siguiente manera:

rustc -g src/vectors.rs

Esto creará un archivo ejectuable llamado vectors en el directorio donde hemos ejecutado el comando rustc.

La variable -g nos permite crear el ejecutable en modo depuración para luego poder enlazarlo con el codigo fuente del mismo dentro de GDB

Si ejecutamos vectors la respuesta va a ser la siguiente:

Vector is: [1, 2, 3, 4, 5]

Vector Values:
1
2
3
4
5

Ahora vamos a lo que nos concierne, la depuración. Para ello hacemos lo siguiente:

rust-gdb vectors

Esto nos abre un prompt similar al siguiente:

notes with tab name

Debemos añadir un punto de depuración lo hacemos de la siguiente manera:

notes with tab name

Si queremos ver donde están nuestros puntos de depuración ejecutamos el comando i b en el prompt de gdb

Esto tambien se puede hacer como info break

La respuesta será algo como:

notes with tab name

Por último el ejecutamos el comando run, el cual iniciará el programa y se detendrá en el punto de depuración que añadimos previamente.

notes with tab name

En este punto de la ejecución ya tenemos la variable vector instanciada y con valores, por lo cual podemos ver que tiene dicha variable, esto se hace mediante el comando p {nombre_variable}.

notes with tab name

Si quieremos ver un backtrace es decir la pila de llamadas que se hicieron hasta llegar al punto de depuración que añadimos lo podemos realizar mediante el comando backtrace

notes with tab name

En este caso no tenemos más llamadas que main por que el ejemplo es muy pequeño

Para continuar hasta el siguiente punto de depuración o hasta que finalice la ejecución del programa presionamos la letra c

notes with tab name

Existe una manera un poco más dinámica de hacer la depuración con rust-gdb mediante el uso de su interfaz TUI, para esto ejecutamos en el prompt de gdb el comando tui enable

Al depurar con TUI habilitado podemos ver algo similar a lo siguiente:

notes with tab name

El código de este ejemplo se encuentra en:
https://github.com/nano-bytes/rust-samples

Eso es todo por hoy.
Happy Hacking!!!

Felices fiestas y un excelente año nuevo.

Última modificación: 16/02/2021

Autor