+ All Categories

Debug

Date post: 12-Dec-2014
Category:
Upload: fausto-maza
View: 21 times
Download: 1 times
Share this document with a friend
6

Click here to load reader

Transcript
Page 1: Debug

Debug

Fausto Maza

Carrera de Ingeniería en Sistemas,

Universidad Nacional de Loja,

Loja, Ecuador

[email protected]

ABSTRACT

This article makes a written presentation of a brief analysis on

the Debug all its features and functionality, and its vital

components useful in the management of assembly language.

RESUMEN

Este artículo hace una presentación escrita de un breve análisis

sobre el Debug todas sus características y funcionalidades,

componentes y su vital utilidad en el manejo del lenguaje

ensamblador.

PALABRAS CLAVES

Debug, componentes, lenguaje ensamblador.

I. INTRODUCCIÓN

En este breve análisis presentaremos el uso funcional de DEBUG.EXE, que es una utilidad del MS-DOS. El Debug es sin duda un programa antiguo pero que posee un enorme potencial didáctico para el principiante. El DEBUG.EXE es un ejecutable que, hasta 2001, acompañó a todas las versiones de MS-DOS, a partir de la 2.0, y de Windows. Se trata de una utilidad interactiva de exploración de bajo nivel, pero que también puede utilizarse para ciertas funciones. Proporcionaremos algunos conceptos de la palabra DEBUG y su principal funcionalidad. Además se detallara una breve definición, opciones, algunos de los principales errores que se da al utilizar el debug, el uso de algunos de sus componentes, y la entrada y salida de datos, ejecutables en DOS y algunos ejemplos de su utilización.

II. DEBUG

Para poder comprender más sobre este programa hay que tener

bien claro el significado de la palabra debug.

Definición.-

Bug.- significa fallo, defecto de programa. Un concepto muy

usado en juegos de video juegos.

Debug.- Entonces el debug Significa depurar (es decir escrutar

y eliminar fallos). La palabra ha quedado como verbo

(depurar), de la que han derivado otras.

El debug es una utilidad de MS-DOS que además de permitir

visualizar la memoria, permite introducir programas en ella y

rastrear su ejecución. Una de las importantes características

del debug es que permite desplegar todo el código del

programa en formato hexadecimal.

Importancia.- Es de vital importancia saber que las utilidades

de bajo nivel, requieren un funcionamiento stand-alone, es

decir, fuera de un Sistema Operativo multi-usuario, ya que

éstos encapsulan y ocultan muchos aspectos del hardware.

La utilidad del Debug es para:

Ensamblar pocas líneas de código

Des-ensamblar código en RAM, ROM y ejecutables

Correr paso-a-paso programas

Desplegar datos en memoria

Verificar estado de los registros del CPU

Comandos del Debug.

Para empezar a usar el Debug basta con teclear Debug desde

el MS-DOS o desde una ventana DOS de Windows. Aunque

en este último caso algunas de sus funcionalidades no estarán

disponibles. Es importante saber que muchos usos de estas

utilidades de bajo nivel, requieren un funcionamiento stand-

alone, es decir, fuera de un Sistema Operativo multi-usuario,

ya que éstos encapsulan y ocultan (virtualizan) muchos

aspectos del hardware. Una vez que el programa está en

ejecución, el indicador ("prompt") es un guión "-", indicando

que el "Shell" espera recibir órdenes. Para salir basta pulsar

una Q. Como muchos programas de su género, sus comandos

empiezan por una letra o combinación de ellas (pueden usarse

indistintamente mayúsculas o minúsculas) y ciertos

parámetros opcionales (no es imprescindible separar la letra

de opción de los parámetros opcionales).

Page 2: Debug

El comando más sencillo de utilizar en el de interrogación ?,

que al momento que lo ingresamos da como resultado una

lista resumida de todas las opciones disponibles.

Fig.1 Representación al utilizar la interrogación

Todos los comandos de DEBUG se invocan usando una sola

letra y son los siguientes:

ASSEMBLE (A)

El comando A se usa para introducir mnemotécnicos de

ensamblador y que éstos se traduzcan directamente a lenguaje

de máquina en memoria.

La sintaxis es la siguiente:

A <dirección>

Prácticamente cualquier mnemotécnico es soportado por

DEBUG, incluyendo los especificadores de "override" de

segmento (CS:, DS:, ES:, SS:).

Una excepción es que DEBUG no puede diferenciar entre

NEAR y FAR returns; asume que RET es "near" y RETF es

"far". 02) C (compare)

COMPARE (C).

Este comando compara y reporta diferencias entre los

contenidos de dos bloques de memoria.

La sintaxis es la siguiente:

C <bloque> <dirección>

<bloque> es la dirección de inicio y fin de un bloque o, si se

preceden con "L", la dirección de inicio y la longitud del

bloque; <dirección> es el inicio de otro bloque. Se presupone

que la longitud de ambos bloques es la misma.

DUMP (D).

Este comando despliega el contenido de una serie de

localidades de memoria.

La sintaxis es:

D <dirección1> <dirección2>

Ambas direcciones son opcionales. La 1ra es la dirección de

inicio de despliegue; la 2da es la dirección de fin.

ENTER (E).

Este comando permite cambiar los contenidos de localidades

específicas de memoria.

La sintaxis es:

E <dirección> <cambios>

<dirección> es el inicio de los cambios y <cambios> es una

lista opcional de los cambios deseados. Los cambios pueden

ser especificados en la línea de comandos en cualquier

combinación de números hexadecimales o caracteres ASCII;

los caracteres ASCII deben estar entre comillas simples o

dobles.

FILL (F).

Este comando llena un bloque de memoria con un valor

específico o una serie de valores.

La sintaxis es:

F <bloque> <valor de relleno>

<bloque> es la dirección de inicio y final o , si se preceden

con "L", la dirección de inicio y la longitud del bloque; <valor

de relleno> es(son) el(los) valor(es) con los que debe de

llenarse el bloque. Si <valor de relleno> representa menor

bytes que los que se necesitan para llenar el bloque, la serie se

repite hasta llenar el bloque.

GO (G).

Este comando ejecuta el código en memoria. Si se está

depurando un programa, permite ejecutar el código cargado

en memoria. También permite establecer puntos de quiebre

(breakpoints) que son direcciones en las que se detiene la

ejecución del programa.

La sintaxis es:

G =<inicio> <quiebre1> <quiebre2> ... <quiebre10>

<inicio> es la dirección de inicio de ejecución; <quiebre1>

hasta <quiebre10> son direcciones opcionales de paro del

programa. Si no se especifica <inicio>, Go inicia con la

dirección contenida en CS:IP. Para lograr los quiebres,

DEBUG reemplaza el código en las direcciones de quiebre

por el valor hexadecimal CC, que es el código de

interrupción. Si DEBUG llega a CC todos los puntos de

quiebre son restituidos, los registros se despliegan (como con

el comando R ) y se para la ejecución.

Aritmética Hexadecimal (H).

Este comando ejecuta restas y suma hexadecimales.

La sintaxis es:

H <valor1> <valor2>

Page 3: Debug

Como resultado de lo anterior, DEBUG regresa dos valores: la

suma y la resta de los argumentos en hexa.

INPUT (I).

Este comando "jala" un byte de un puerto.

La sintaxis es:

I <puerto>

<puerto> es la dirección del puerto a leer. Se lee el dato y se

despliega en pantalla.

LOAD (L).

Este comando se usa para cargar un archivo o sectores de

disco a memoria.

La sintaxis es:

L <buffer> <numdisco> <sectorini> <numsector>

<buffer> es la dirección en donde se carga la información;

<numdisco> es el número (opcional) del disco de donde se

leerá la información (0=A, 1=B, 2=C, etc.); <sectorini> es el

sector de disco absoluto (en hexadecimal) a leer; <numsector>

es la cantidad de sectores a leer. No se pueden leer más de

80H (128) sectores. Si no se suministra la combinación

<numdisco> <sectorini>

<numsector> DEBUG presume que se desea leer un archivo.

En este caso <buffer> es opcional.

Debe usarse el comando N (ver más adelante) para especificar

el archivo a leer. Éste se carga en CS:0100.

MOVE (M).

Este comando mueve un bloque de memoria de una localidad

a otra.

La sintaxis es:

M <bloque> <dirección>

<bloque> es como arriba (ver 2.1.5.); <dirección> es la

dirección destino. El bloque de origen y la dirección destino

pueden traslaparse.

NAME (N).

Este comando se usa para especificar el nombre del archivo

usado por los comandos LOAD y WRITE.

La sintaxis es:

N <nomarch1< <nomarch2>

<nomarch1> es la especificación de archivo completa que será

"parseada" y colocada en el bloque de control en CS:005C.

<nomarch2> es la especificación de archivo que será colocada

en CS:006C.

La expresión tal cual se tecleó se almacena en CS:0081,

precedida por el número de bytes tecleados.

OUTPUT (O).

Este comando pone un byte en el puerto especificado.

La sintaxis es:

O <puerto< <valor>

<valor> es el byte hexadecimal a escribir en <puerto>.

QUIT (Q).

Este comando se usa para salir de DEBUG.

REGISTER (R).

Este comando despliega los registros del CPU y los valores

de las banderas.

La sintaxis es:

R <registro>

<registro> es el nombre opcional y puede ser alguno de los

siguientes: AX, BX, CX, DX, SP, BP, SI, DI, DS, ES, SS, CS,

IP, PC o F. IP y PC son sinónimos.

SEARCH (S).

Este comando permite buscar en un bloque de memoria una

secuencia específica de valores.

La sintaxis es:

S <bloque> <valor_a_buscar>

<bloque> se define como antes (ver la sección 2_1_1).

<valor_a_buscar> es(son) el(los) valor(es) que deseamos

buscar en el bloque.

TRACE (T).

Este comando permite ejecución paso-a-paso de las

instrucciones de máquina. Después de cada instrucción se

muestra el estado de los registros.

La sintaxis es:

T =<inicio> <cuenta>

<inicio> es la dirección de inicio de la traza.

<cuenta> es el número de instrucciones a trazar.

UNASSEMBLE (U).

Este comando decodifica los valores de un grupo de

localidades de memoria a mnemotécnicos de 8086.

La sintaxis es la siguiente:

U <alcance>

Page 4: Debug

<alcance>, que es opcional, es ya sea un par de direcciones de

inicio y fin o, si se precede con "L", la dirección de inicio y la

longitud del área a desensamblar.

WRITE (W).

Este comando se usa para escribir un archivo a sectores

individuales de disco a disco.

La sintaxis es:

W <buffer> <numdisco> <sectorini> <numsector>

<buffer> es la dirección de donde se carga la información.

<numdisco> es el número (opcional) del disco en donde se

escribirá la información (0=A, 1=B, 2=C, etc.).

<sectorini> es el sector de disco absoluto (en hexadecimal) en

donde empieza la escritura.

<numsector> es la cantidad de sectores a leer. No se pueden

escribir más de 80H (128) sectores. Si no se suministra la

combinación <numdisco> <sectorini> <numsector> DEBUG

presume que el inicio de archivo es CS:100.

En este caso <buffer> es opcional. Debe usarse el comando N

(ver arriba) para especificar el archivo a escribir.

Antes de escribir BX:CX debe ajustarse al número de bytes

que desean grabarse.

W no puede escribir a archivos con la extensión EXE o HEX.

Por lo general la mayoría de los comandos de debug ejecutan

una acción y vuelven al indicador del shell, pero si es un

comando largo, como puede ser mostrar un trozo grande de

código, puede detenerse pulsando CTRL-Pausa o

interrumpirse con CTRL-C para volver al shell.

Fichero Script.

Una característica poco conocida, es que debug puede aceptar

entradas desde un fichero "Script", que puede ser un simple

fichero de texto ASCII en el que cada comando esté separado

del anterior por un INTRO. Después del último, que debe ser

una "Q" para salir de debug, es conveniente dejar una línea en

blanco pulsando INTRO dos veces. Las líneas pueden

contener comentarios. Cualquier cosa a partir del carácter

punto y coma (;) hasta el final de la línea, será ignorado.

Suponiendo que tengamos un fichero "Script" de nombre

Ordenes.txt, puede ser utilizado como entrada para debug

mediante un comando de

redirección en la siguiente

forma:

También puede conseguirse que el programa redireccione la

salida hacia un fichero que puede ser inspeccionado más

tarde. Aunque tiene la dificultad de tener que trabajar "a

ciegas", puede ser de utilidad en determinadas circunstancias.

Por ejemplo, cuando se desea un volcado de determinadas

zonas de la memoria. En el caso anterior podría obtenerse un

fichero Result.txt con el siguiente comando:

ERRORES.

Cuando debug no sabe interpretar un comando, muestra un

mensaje de error y un indicador "^" debajo del comando

donde está el error.

Fig.2 Representación cuando se produce un error.

ENTRADA Y SALIDA.

Debug asume que los datos numéricos proporcionados son

hexadecimales, y cuando se trate de direcciones de memoria,

deben introducirse en forma segmentada. A su vez, los

resultados son mostrados también en formato hexadecimal

cuando se refieren a direcciones de memoria. Cuando se trata

simplemente del contenido de ciertas posiciones de memoria,

el resultado es mostrado en formato hexadecimal y en ASCII.

Por ejemplo, una salida puede presentar el siguiente aspecto:

177C:0180 01 21 10 03 41 10 05 61-10 07 81 10 09 A1 10

0B !..A..a........

177C:0190 C1 10 0D E1 10 0F 01 11-11 21 11 13 41 11 15

61 .........!..A..a

177C:01A0 11 17 81 11 19 A1 11 1B-C1 11 1D E1 11 1F 01

12 ................

177C:01B0 21 21 12 23 41 12 25 61-12 27 81 12 29 A1 12

2B !!.#A.%a.'..)..+

177C:01C0 C1 12 2D E1 12 2F 01 13-31 21 13 33 41 13 35

61 ..-../..1!.3A.5a

177C:01D0 13 37 81 13 39 A1 13 3B-C1 13 3D E1 13 3F 01

14 .7..9..;..=..?..

177C:01E0 41 21 14 43 41 14 45 61-14 47 81 14 49 A1 14

4B A!.CA.Ea.G..I..K

177C:01F0 C1 14 4D E1 14 4F 01 15-51 21 15 53 41 15 55

61 ..M..O..Q!.SA.Ua

Cada fila muestra 16 posiciones de memoria a partir de la

posición señalada por las columnas de la izquierda, que las

; esto es un comentario

D ; aquí se mostrará algo...

DEBUG < Ordenes.txt

DEBUG < Ordenes.txt > Result.txt

Page 5: Debug

muestran como desplazamiento: segmento. El bloque central

muestra el contenido hexadecimal de cada byte, mientras que

el bloque derecho contiene la representación ASCII. Por

ejemplo, la 5ª fila muestra el contenido de las posiciones

177C:01C0 a 177C:01CF (ambas inclusive). Sus dos últimos

bytes contienen respectivamente los caracteres 5 y a, que

corresponden a las cantidades 35hy 61h del bloque central.

Que como sabemos, equivalen a los decimales 53 y 97, que

son precisamente los valores ASCII de los caracteres

mencionados.

Por razón de que éste tipo de salida pueda ser listado a

impresora, el bloque derecho no contiene en realidad la

representación ASCII de todos los caracteres (algunos ni si

quiera tienen una representación imprimible). En realidad solo

se muestran los caracteres imprimibles del primer bloque (US-

ASCII). El resto está representado por un punto. No perder de

vista que, a pesar de que algunas posiciones de memoria

puedan contener valores cuya equivalencia ASCII sea un

carácter imprimible. Esto no significa que dichas posiciones

representen efectivamente tales valores para la aplicación

quelas utiliza. Por ejemplo, puede que en realidad, las dos

posiciones de memoria mencionadas (dos octetos), en vez de

los caracteres 5 y a, representen una palabra de16 bits en

formato Little Endian, que a su vez representan una cantidad

entera (un número).

EJECUTABLES EN DOS.

Existen dos formatos: .COM y .EXE.

•El primero, .COM, es el formato original. En este formato,

todo, código y datos, es puesto en un único segmento cuyo

tamaño no debe exceder los 64KB.

•En el segundo, .EXE, se reserva un segmento para datos, uno

para código y uno para la pila.

Con el debug se pueden escribir programas en formato .COM,

que son bastan temas pequeños.

El programa debe comenzar a ejecutarse en la dirección 256

[100h], ya que los ejecutables de DOS reservan los primeros

256 bytes para colocar ahí una estructura de datos conocida

como PSP, cuando es cargado en la memoria. El PSP

(ProgramSegment Prefije: Prefijo de Segmento del Programa)

contiene información que será utilizada por el cargador de

DOS.

III. EJEMPLO DEL DEBUG.

1. Uso del comando “R”

Observe el contenido de los registros del microprocesador y

cambie a los valores que se indican el contenido de los

siguientes registros, en cada caso luego de realizar el cambio,

verifíquelo en la pantalla y anote lo que va apreciando:

C:\>debug

- r

AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE

BP=0000 SI=0000 DI=0000

DS=1A9E ES=1A9E SS=1A9E CS=1A9E IP=0100 NV UP

EI PL NZ NA PO NC

1.- El acumulador que se cargue con 5A7

-rax

:5A7

-r

AX=05A7 BX=0000 CX=0000 DX=0000

2.- El contador con 1DE4

-rcx

:1DE4

-r

AX=05A7 BX=0000 CX=1DE4 DX=0000

3.- El de instrucciones con 0200

-rip

:200

-r

(...) DS=1A9E ES=1A9E SS=1A9E CS=1A9E

IP=0200

4.- El base con C23

-rbx

:C23

-r

AX=05A7 BX=0C23 CX=1DE4 DX=0000

5.- El DX con FFFF1

-rdx

:FFFF1

Error ^

-r

AX=05A7 BX=0C23 CX=1DE4 DX=0000

No se puede cambiar el registro DX con FFFF1 porque

tiene 2 ½ bytes (5 nibles) y el registro sólo acepta 2 bytes (4

nibles o 1 palabra).

6.- Regrese el IP a su valor original

-rip

:100

-r

AX=05A7 BX=0C23 CX=1DE4 DX=0000

SP=FFEE BP=0000 SI=0000

DS=1A9E ES=1A9E SS=1A9E CS=1A9E IP=0100

NV UP EI PL NZ

Page 6: Debug

2. Genere un archivo COM y ejecútelo desde el

sistema operativo

-A100

1A9E:0100 MOV AH,09

1A9E:0102 MOV DX,200

1A9E:0105 INT 21

1A9E:0107 INT 20

1A9E:0109

-E200

1A9E:0200 80.2A 3E.2A 83.2A CF.2A 00.2A 75.2A

0F.2A BA.2A

1A9E:0208 96.2A 80.2A E8.2A C3.2A 1F.2A E8.2A

D7.2A E2.2A

….

1A9E:0270 E8.2A 5D.2A 1F.2A E8.2A 71.2A E2.2A

E8.2A B2.2A

1A9E:0278 00.2A 80.2A 3E.2A 83.2A CF.2A 00.2A

75.2A 0A.2A

1A9E:0280 E8.2A D2.2A 01.2A 72.24

-G

El programa ha finalizado con normalidad

-N LOGO.COM

-RBX

BX 0000

:0000

-RCX

CX 0000

:0184

-W

Escribiendo 00184 bytes

-Q

C:\>LOGO.COM

3. Despliegue en pantalla la siguiente cadena de

caracteres y guardar el programa con el nombre

EJER16.COM

-A100

1A9E:0100 MOV AH,09

1A9E:0102 MOV DX,200

1A9E:0105 INT 21

1A9E:0107 INT 20

1A9E:0109

-E200

1A9E:0200 4F.42 53.49 43.45 41.4E 52.56 24.45

0F.4E BA.49

1A9E:0208 96.44 80.4F E8.53 C3.20 1F.43 E8.41

D7.43 E2.48

1A9E:0210 BA.49 B8.4D 7E.42 E9.4F CF.53 06.21

80.21 3E.24

-G

BIENVENIDOS CACHIMBOS!!

El programa ha finalizado con normalidad

-N EJER16.COM

-RBX

BX 0000

:0000

-RCX

CX 0000

:0124

-W

Escribiendo 00124 bytes

-Q

IV. CONCLUSIONES

He concluido que el conocimiento sobre el debug es de

vital importancia para su utilización y mejoramiento en el

desarrollo del sistema que se desea manipular o crear.

Como todos sabemos programar en sistemas es un poco

complicado, por ese motivo importante saber las funciones

de los comando que brinda debug.

Para programar en este lenguaje tenemos que tener

conocimientos de este lenguaje, antes de utilizar porque

después los resultados podrían ser relativamente malos.

RECONOCIMIENTOS

Agradezco a la persona que es nombrada en la web como

ingzepe, quien me ayudo profundizando en los saberes de un

Debug.

De la misma manera a los autores de la página web Zator

Systems, con el mismo tema de Debug.

De igual forma a la persona que creo el pdf de los

Componentes de Debug.

Y de la misma manera al Ing. MSc. Henry I. Condori A.

“FUNCIONES BASICAS DE DEBUG Y EJEMPLOS”, que

fueron de gran utilidad para la práctica de los componentes

de debug.

REFERENCIAS

[1] Publicado por ingzepe, “DEBUG.EXE”. Desde

http://es.scribd.com/doc/7462877/Debug

[2] Zator Systems. “DEBUG”. Desde

http://www.zator.com/Hardware/H1_7_1.htm

[3] Desconocido. “COMPONENTES DE DEBUG”. Desde

http://halcon.webcindario.com/USO%20DEBUG.pdf

[4] Ing. MSc. Henry I. Condori A. “FUNCIONES BASICAS

DE DEBUG Y EJEMPLOS”. Desde

http://www.unap.edu.pe/~hcondori/assembler/laboratoriod.

pdf


Recommended