Click here to load reader
Date post: | 12-Dec-2014 |
Category: |
Documents |
Upload: | fausto-maza |
View: | 21 times |
Download: | 1 times |
Click here to load reader
Debug
Fausto Maza
Carrera de Ingeniería en Sistemas,
Universidad Nacional de Loja,
Loja, Ecuador
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).
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>
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>
<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
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
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.