Red de conocimiento informático - Material del sitio web - Cómo desactivar la información de depuración del controlador mtd

Cómo desactivar la información de depuración del controlador mtd

Una de las dificultades en el desarrollo de controladores es el inconveniente de la depuración. Este artículo tiene como objetivo presentar varias herramientas de depuración directa e indirecta que se utilizan comúnmente en el desarrollo de controladores. Estas son:

1. Uso de printk

2. 3. Utilice strace

4. Utilice la opción de pirateo integrada del kernel

5. Utilice el método ioctl

6. /p>

7. Utilice kgdb

Los dos primeros métodos son los siguientes:

1. Utilice printk

Este es el más simple y sencillo. pero también es el método de desarrollo de controladores más utilizado y eficaz. La línea 338 del main.c del controlador Scull, que se muestra a continuación, es un ejemplo de depuración usando printk. La línea 338 del main.c del controlador Scull es un ejemplo de depuración usando printk, que se puede encontrar en todas partes al leer el código fuente del controlador.

338 // printk(KERN_ALERT "despertar por señal en proceso %d\n", actual->pid);

La función de printk es similar a la que usamos frecuentemente en aplicaciones printf tiene la misma función, puede ir precedido de una macro definida por el kernel, como KERN_ALERT en el ejemplo anterior (nota: no hay coma entre la macro y la cadena).

#define KERN_EMERG ""

#define KERN_ALERT ""

#define KERN_CRIT ""

#define KERN_ERR ""

#define KERN_WARNING ""<

#define KERN_NOTICE""

#define KERN_INFO ""

#define KERN_DEBUG ""

#define DEFAULT_CONSOLE_LOGLEVEL 7

Esta macro se utiliza para definir el nivel de la cadena a imprimir. Cuanto menor sea el valor, mayor será el nivel. Hay un parámetro en el kernel que puede controlar si la cadena impresa por printk se envía a la consola (pantalla o archivo de registro /sys/log/syslog)

# cat /proc/sys/kernel/printk

6 4 1 7

Los primeros 6 significan enviar mensajes con un nivel superior (inferior) a 6 a la consola, y los segundos 4 significan enviar mensajes con un nivel superior a 6 a la torre de control.

Entonces, si descubre que no puede ver la salida de algún printk en su programa en la consola, use echo 8 > /proc/sys/kernel/printk para resolverlo.

En el proceso de desarrollo de controladores complejos, se agregan cientos de declaraciones printk al código fuente con fines de depuración. Cuando se depure el producto final, estas declaraciones printk se eliminarán. Piense en los usuarios conductores, no en los desarrolladores. (Recuerde: haga con los demás lo que le gustaría que le hicieran a usted. Lo peor de todo es que si elimináramos la declaración printk con fines de depuración, los usuarios informarían errores en el controlador y tendríamos que volver a agregar manualmente miles de decenas de miles. de declaraciones printk, por lo tanto, necesitamos una forma de activar o desactivar fácilmente la información de depuración. ¿Dónde podemos encontrar este método?

¡Eche un vistazo al código fuente del controlador scull o del controlador LED!

#define LEDS_DEBUG

#undef PDEBUG

#ifdef LEDS_DEBUG

#ifdef __KERNEL__

#define PDEBUG (fmt, args...) printk( KERN_EMERG "leds: " fmt, ## args)

#else

#define PDEBUG(fmt, args...) fprintf( stderr, fmt, ## args)

#endif

#else

#define PDEBUG(fmt, args...)

#endif

#undef PDEBUGG

#define PDEBUGG(fmt, args... Una vez completada la depuración y formado el producto final, solo necesitamos comentar la línea 1.

p>

__KERNEL__ en el código anterior es una macro. Cuando compilamos el kernel (incluidos los módulos), esta macro se define en el kernel. Por supuesto, si no lo entiende... y #. ### en el código ¿Qué quieres decir? Verifica cuidadosamente la información en la parte de preprocesamiento de gcc. Si eres demasiado vago para verificar, actúa como ingeniero de VC y copia el código anterior en tu código. >

En segundo lugar, revisa el mensaje OOP

OOP significa sorpresa. El núcleo no se sorprende cuando algo sale mal con tu controlador: Oye, muchacho, ¿por qué estás jugando?

Compile falloy.ko basado en falloy.c (haga clic para descargar) y ejecute insmod falloy.ko Ejecute echo yang >/dev/faulty ¿Por qué el kernel se sorprende por la escritura del controlador defectuoso? *(int *)0 = 0, escribiendo en la dirección de memoria 0, lo que el kernel nunca permitirá.

52 ssize_t default_write (archivo de estructura *filp, const char __user *buf, size_t count,

53 loff_t *pos)

54 {

55

56 *(int *)0 = 0;

57 devuelve 0;

58 }

1 No se puede Manejar la desreferencia del puntero NULL del kernel en la dirección virtual 00000000

2 pgd = c3894000

3 [00000000] *pgd=33830031, *pte=00000000, *ppte=00000000

4 Error interno: Ups: 817 [#1] PREEMPT

5 Módulo vinculado: Scull problemático

6 CPU: 0 Sin teñir (2.6.22.6 #4)

7 PC está ubicada en default_write+0×10/0×18 [Fault]

8 LR está ubicada en vfs_write+0xc4/0×148

9 PC : [ ] SR: [] PSR: A0000013

10 SP: C3871F44 IP: C3871F54 FP: C3871F50

11 R10: 4021765c r9: c3870000 r8: 00000000

12 r7: 00000004 r6: c3871f78 r5: 40016000 r4: c38e5160

13 r3: c3871f78 r2: 00000004 r1: 40016000 r0: 00000000

14 Banderas: Cv IRQ s en FIQ en Modo SVC_32 Usuario de segmento

15 Control: c000717f Tabla: 33894000 DAC: 00000015

16 Proceso sh (pid: 745, límite de pila = 0xc3870258)

17 Pila : (0xc3871f44 a 0xc3872000)

18 1f40: c3871f74 c3871f54 c0088eb8 bf00608c 00000004 c38e5180 c38e5160

19 1f60: c3871f78 00000 00 c3871fa4 c3871f78 c0088ffc c0088e04 00000000 00000000

20 1f80 : 00000000 00000004 40016000 40215730 00000004 c002c0e4 00000000 c3871fa8

21 1fa0: c002bf40 c0088fc0 00000004 40016000 0000 0001 40016000 00000004 00000000

22 1fc0: 00000004 40016000 40215730 00000004 00000001 00000000 4021765c 00000000

23 1fe0: 00000000 bea60964 0000266c 401adb40 60000010 00000001 00000000 00000000

24 Backtrace:

25 [] (defectuoso

_write+0×0/0×18 [defectuoso]) de [] (vfs_write+0xc4/0×148)

26 [] (vfs_write+0×0/0×148) de [] ( sys_write+0x4c/0×74)

27 r7:00000000 r6:c3871f78 r5:c38e5160 r4:c38e5180

28 [] (sys_write+0×0/0×74) de [] (ret_fast_syscall+0×0/0x2c)

29 r8:c002c0e4 r7:00000004 r6:40215730 r5:40016000 r4:00000004

30 Código: E1A0C00D E92DD800 E24CB004 000 0 ( E5800000 )

La línea 1 es el motivo inesperado, es decir, el motivo por el que se informa el error;

80: e92dd800 stmdb sp!{fp, ip, lr, pc}

84: E24cb004 sub fp, ip, #4; 0×4

88: E3a00000 mov r0, #0; , [r0]

90: e89da800 ldmia sp, {fp, sp, pc}

El proceso de localizar la ubicación del error y obtener información relevante:

9 pc: [] lr: [] psr: A0000013

25 [] (faulty_write+0×0/0×18 [defectuoso]) de [] (vfs_write+0xc4/0×148)

26 [ ] (vfs_write+0×0/0×148) de [] (sys_write+0x4c/0×74)

El código de error es la quinta instrucción en la función faily_write ( (0xbf00608c-0xbf00607c)/4 +1=5), la primera dirección de esta función es 0xbf00607c, esta función tiene un total de ***6 instrucciones (0×18), y esta función es llamada por la instrucción anterior ubicada en 0xc0088eb8 (es decir: 0xbf00607c-0xbf00607c). e., La dirección de retorno de la función es 0xc0088eb8. El valor de lr en el momento del error es exactamente igual a 0xc0088eb8 en el momento del error, lo que ilustra el problema). La instrucción para llamar a esta función es la instrucción número 49 de vfs_write (0xc4/4=49).

El flujo de llamada a la función para llegar a la ubicación donde ocurre el error es: escribir (llamada al sistema de espacio de usuario)->sys_write->vfs_write->faulty_write

El mensaje OOP no solo me lo permitió para encontrar la ubicación del error y, lo que es aún más sorprendente, también me permite saber algunos secretos: 1. ¿Cuál es el papel de fp en gcc? 2. ¿Por qué gcc siempre coloca 3 instrucciones tontas al comienzo de toda la función al compilar cualquier función? 3. ¿Cómo conocen el kernel y gdb el orden de la pila de llamadas de función y utilizan nombres de funciones en lugar de direcciones? 4. ¿Cómo saber el contenido de la pila de cada función? Jaja, me gusta cada vez más dar sorpresas del kernel. Veamos las sorpresas del kernel nuevamente.

¡Ejecute cat /dev/faulty y el kernel quedará impactado nuevamente!

1 No se puede manejar la desreferencia del puntero NULL del kernel en la dirección virtual 0000000b

2 pgd = c3a88000

3 [0000000b] *pgd=33a79031, *pte = 00000000 , *ppte=00000000

4 Error interno: Vaya: 13 [#2] PREEMPT

5 Módulo vinculado: Problema

6 CPU: 0 Sin teñir (2.6 .22.6 #4)

7 PC está en vfs_read+0xe0/0×140

8 LR está en 0xffffffffffffff

9 PC: [ ] LR: [] PSR: 20000013

10 SP: c38d9f54 IP: 0000001C FP: fffffffffff

11 R10: 00000001 R9: c38d8000 R8: 00000000

12 R7: 00000004 r6: ffffffff r5: ffffffff r4: ffffffff

13 r3: ffffffff r2: 00000000 r1: c38d9f38 r0: 00000004

14 Banderas: nzCv IRQ en FIQ en modo SVC_32 Segmento usuario

15 Control: c000717f Tabla: 33a88000 DAC: 00000015

16 Proceso cat (pid: 767, límite de pila = 0xc38d8258)

17 Pila: (0xc38d9f54 a 0xc38da000)

18 9f40: 00002000 c3c105a0 c3c10580

19 9f60: c38d9f78 00000000 c38d9fa4 c38d9f78 c0088f88 c0088bb 4 00000000 000000

20 9f80: 00000000 00002000 bef07c80 00000003 00000003 c002c0e4 00000000 c38d9fa8

21 9fa0: C002BF40 C0088F4C 00002000 BEF07C80 00000003 BEF07C80 00002000 00000000

22 9FC0: 0 BEF07C80 00000003 00000000 00000000 00000001 00000001 00000003

23 9FE0 :00000000 bef07c6c 0000266c 401adab0 60000010 00000003 00000000 00000000

24 Seguimiento inverso: puntero de marco no válido 0xffffffffffff

25 Código: ebffff86 e3500000 e1a07 000 da000015 ( e594500c)

26 Fallo de segmentación

Pero la sorpresa fue grande: OOP dijo que el error ocurrió en vfs_read (esto es lo que los maestros han estado mejorando

(en el código del kernel), ¿cómo es esto posible? Jaja, el kernel universal no puede rastrear la pila de llamadas a funciones. ¿Por qué? De hecho, el problema radica en la línea 43 de faily_read, lo que hace que r4, r5, r6 y fp en la pila cambien a 0xffffffffff, mientras que los valores de ip y lr permanecen sin cambios, por lo que la función faily_read puede regresar con éxito. a su llamador: vfs_read. Pero el pobre vfs_read (un fiel seguidor de las reglas APTCS) no sabe que sus r4, r5, r6 han sido cambiados por el malvado faily_read, por lo que el destino de vfs_read se puede imaginar: ¡muerte segura! No importa cuán poderoso sea el kernel, es imposible rastrear la pila de llamadas a funciones sin la ayuda del fp apropiado.

36 ssize_t faily_read(archivo de estructura *filp, char __user *buf,

37 size_t count, loff_t *pos)

38 {

39 int ret;

40 char stack_buf[4];

41

42

43 memset(stack_buf, 0xff, 20);

44 if (count > 4)

45 count = 4;

46 ret = copy_to_ user(buf, stack_buf, count);

47 if (!ret)

48 recuento de retornos;

49 retornos ret;

50 }

00000000 :

0: e1a0c00d mov ip, sp

4: e92dd870 stmdb sp!{r4, r5, r6, fp, ip, lr, pc}

8: E24CB004 sub fp, ip, #4; 0×4

C: e24dd004 sub sp, sp, #4; en este caso, stack_buf[] se asigna en la pila 1 palabra de espacio, la variable local ret se almacena en un registro, por lo que no se asigna espacio en la pila

10: e24b501c sub r5, fp, #28

14: e1a04001 mov r4, r1

18: e1a06002 mov r6, r2

1c: e3a010ff mov r1, #255; 0xff

20: e3a02014 mov r2, # 20; 0×14

24: e1a00005 mov r0, r5

28: ebfffffe bl 28 //Aquí está la llamada a memset

78: e89da878 ldmia sp, {r3, r4, r5, r6, fp, sp, pc}

Esto es programación orientada a objetos, una comprensión profunda:

El kernel es superpoderoso, pero no lo es ni puede serlo. todo. . Por lo tanto, no importa lo capaz que seas, debes tener una buena relación con los miembros de tu equipo, de lo contrario tendrás mala suerte en los momentos críticos;

El defectuoso fue faily_read, pero vfs_read se convirtió en el chivo expiatorio. Por lo tanto, no debemos dejarnos engañar por el fenómeno superficial, sino profundizar en su esencia;

El kernel es súper robusto, pero el controlador que usted escribe es una parte integral del kernel porque falla. el resultado es que todo el kernel falla. Por eso, cuando te unes a un equipo debes advertirte que aunque tu papel pueda no ser importante, tu descuido es suficiente para derribar a todo el gran equipo.

Por otro lado, cuando eres el líder de un equipo, debes tener cuidado, cuidado, cuidado y cuidado a la hora de elegir a los miembros del equipo, aunque solo tenga un pequeño papel.

No los apiles al azar. Si algo sale mal, será difícil encontrar el error. Así que no te metas con tu líder o morirás miserablemente.

V