A todos los programadores novatos siempre se les informa sobre la importancia de informar correctamente los errores. Siempre dicen que si el programa no pudo hacer algo, entonces deberĂa decir de manera clara e inequĂvoca por quĂ© sucediĂł. Hablan de la importancia de controlar el valor de retorno de las funciones llamadas. Además, incluso los compiladores han aprendido a emitir advertencias si se ignora el valor devuelto por ciertas funciones. Debo decir que se acepta la importancia del manejo de errores por parte de los programadores modernos. A veces esto conduce a incidentes divertidos, como en el KDPV (tomado aquĂ). En la vida real, tuve que lidiar con mensajes de diagnĂłstico tan extraños varias veces. Quiero contarles sobre este Ăşltimo caso y los mĂ©todos para superar tal diagnĂłstico. Si estás interesado, eres bienvenido debajo del gato. Los programadores experimentados ciertamente no descubrirán nada nuevo por sĂ mismos, pero definitivamente podrán filosofar sobre el desarrollo de software.
En general, tengo malas noticias. No habrá más imágenes. Bajaremos al nivel de la consola del sistema Linux y viviremos allĂ. En este caso, nos regocijaremos. Para el proyecto con el que trabajar es un cargador U-Boot bastante conocido . Proyecto de cĂłdigo abierto apoyado por DENX Software Engineering... Por lo tanto, nos alegrará tener una consola, un entorno de sistema y, en general, la vida está en pleno apogeo. Porque cuando se trabaja con este proyecto, por regla general, no hay nada como esto: áreas de memoria continua, transferencia de bytes de un lugar a otro y esperando que la periferia estĂ© lista. Pero, por cierto, esta parte ya se ha completado y hay un gestor de arranque bastante funcional para la pieza de hardware. Es hora de comenzar con las decoraciones que permitan a los programadores de aplicaciones influir de alguna manera en el proceso de arranque del sistema. Nada es un buen augurio para los problemas. El problema se resolviĂł hace mucho tiempo y es utilizado activamente por proyectos tan populares como OpenWRT y muchos otros, un poco menos conocidos.
. U-Boot . . fw_printenv fw_setenv Linux. . . « ». ? . «fw_printenv», - .
localhost ~ # fw_printenv Cannot open /dev/mtd1: No such file or directory localhost ~ # fw_printenv --help Usage: fw_printenv [OPTIONS]... [VARIABLE]... Print variables from U-Boot environment -h, --help print this help. -v, --version display version -c, --config configuration file, default:/etc/fw_env.config -n, --noheader do not repeat variable name in output -l, --lock lock node, default:/var/lock
. . . « » , . /etc/fw_env.config. . , ( ) U-Boot , . uboot.env , vfat ( FAT-32). . U-Boot , . . Linux. c uboot.env, , , /boot. 11 12 (/dev/mtd1 /dev/mdt2 ) 30 (/boot/uboot.env) .
# VFAT example /boot/uboot.env 0x0000 0x4000
. . .
localhost ~ # fw_printenv Read error on /boot/uboot.env: Success
, . , Linux’ — . , « » — root’. . , ( ) ? ? U-Boot’ «saveenv»? …
localhost ~ # ls -l /boot/uboot.env -rwxr-xr-x 1 root root 8192 Dec 2 13:22 /boot/uboot.env
, . (, ). , ?
localhost ~ # mv /boot/uboot.env /boot/uboot.env.bak localhost ~ # fw_printenv Cannot open /boot/uboot.env: No such file or directory localhost ~ # mv /boot/uboot.env.bak /boot/uboot.env
. . , … , . . , . ? 950 tools/env/fw_env.c:
lseek(fd, blockstart + block_seek, SEEK_SET);
rc = read(fd, buf + processed, readlen);
if (rc == -1) {
fprintf(stderr, "Read error on %s: %s\n",
DEVNAME(dev), strerror(errno));
return -1;
}
if (rc != readlen) {
fprintf(stderr,
"Read error on %s: Attempted to read %zd bytes but got %d\n",
DEVNAME(dev), readlen, rc);
return -1;
}
. read(). . , , read() -1, errno . . ? , … …
, read? , … read- -. read() . . ? , — .
localhost ~ # strace fw_printenv execve("/usr/bin/fw_printenv", ["fw_printenv"], 0x7ebf2400 /* 28 vars */) = 0 brk(NULL) = 0x2118000 uname({sysname="Linux", nodename="localhost", ...}) = 0 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=42265, ...}) = 0 mmap2(NULL, 42265, PROT_READ, MAP_PRIVATE, 3, 0) = 0x76f14000 close(3) = 0 openat(AT_FDCWD, "/lib/libc.so.6", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3 read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\f~\1\0004\0\0\0"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=1286448, ...}) = 0 mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x76f12000 mmap2(NULL, 1356160, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x76da1000 mprotect(0x76ed7000, 65536, PROT_NONE) = 0 mmap2(0x76ee7000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x136000) = 0x76ee7000 mmap2(0x76eea000, 8576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x76eea000 close(3) = 0 set_tls(0x76f12ca0) = 0 mprotect(0x76ee7000, 8192, PROT_READ) = 0 mprotect(0x4a9000, 4096, PROT_READ) = 0 mprotect(0x76f1f000, 4096, PROT_READ) = 0 munmap(0x76f14000, 42265) = 0 openat(AT_FDCWD, "/var/lock/fw_printenv.lock", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 flock(3, LOCK_EX) = 0 brk(NULL) = 0x2118000 brk(0x2139000) = 0x2139000 openat(AT_FDCWD, "/etc/fw_env.config", O_RDONLY) = 4 fstat64(4, {st_mode=S_IFREG|0644, st_size=1342, ...}) = 0 read(4, "# Configuration file for fw_(pri"..., 4096) = 1342 read(4, "", 4096) = 0 close(4) = 0 openat(AT_FDCWD, "/boot/uboot.env", O_RDONLY) = 4 fstat64(4, {st_mode=S_IFREG|0755, st_size=8192, ...}) = 0 close(4) = 0 openat(AT_FDCWD, "/boot/uboot.env", O_RDONLY) = 4 _llseek(4, 0, [0], SEEK_SET) = 0 read(4, "n.'\202__INF0__=Ravion-V2 I.MX6 CPU"..., 16384) = 8192 write(2, "Read error on /boot/uboot.env: S"..., 39Read error on /boot/uboot.env: Success ) = 39 close(4) = 0 flock(3, LOCK_UN) = 0 close(3) = 0 exit_group(1) = ? +++ exited with 1 +++ localhost ~ #
Linux. . . , — . -. :
openat(AT_FDCWD, "/boot/uboot.env", O_RDONLY) = 4 _llseek(4, 0, [0], SEEK_SET) = 0 read(4, "n.'\202__INF0__=Ravion-V2 I.MX6 CPU"..., 16384) = 8192 write(2, "Read error on /boot/uboot.env: S"..., 39Read error on /boot/uboot.env: Success ) = 39
16384 (16K), 8192 (8K). . . . , 8192 . . 0, 0x4000 16384. 0x2000
# VFAT example /boot/uboot.env 0x0000 0x2000
, . U-Boot’ . . . . () . — - . , . , . . .
— U-Boot. . , — . ? ( )? — 16 8. — ? , — .
localhost ~ # fw_printenv __INF0__=Ravion-V2 I.MX6 CPU Module BSP package __INF1__=Created: Alex A. Mihaylov AKA MinimumLaw, MinimumLaw@Rambler.Ru […] boot_os=1 localhost ~ #
. fw_setenv .
localhost ~ # fw_setenv boot_os 0; fw_printenv boot_os boot_os=0
? . , . , ?
. , U-Boot, , . . , strace read 8192. ? 8192 -1.
. , — , Das U-Boot . . , . . , . . . .
localhost ~ # fw_printenv --version Compiled with U-Boot 2019.10 localhost ~ #
lseek(fd, blockstart + block_seek, SEEK_SET);
rc = read(fd, buf + processed, readlen);
if (rc != readlen) {
fprintf(stderr, "Read error on %s: %s\n",
DEVNAME(dev), strerror(errno));
return -1;
}
. . . . . , . .
. «uboot.env»
localhost ~ # hexdump -C /boot/uboot.env 00000000 0a 43 62 eb 5f 5f 49 4e 46 30 5f 5f 3d 52 61 76 |.Cb.__INF0__=Rav| 00000010 69 6f 6e 2d 56 32 20 49 2e 4d 58 36 20 43 50 55 |ion-V2 I.MX6 CPU| 00000020 20 4d 6f 64 75 6c 65 20 42 53 50 20 70 61 63 6b | Module BSP pack| 00000030 61 67 65 00 5f 5f 49 4e 46 31 5f 5f 3d 43 72 65 |age.__INF1__=Cre| [...] 00000720 3d 71 70 00 76 65 6e 64 6f 72 3d 72 61 76 69 6f |=qp.vendor=ravio| 00000730 6e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |n...............| 00000740 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00002000 localhost ~ #
— , , . 1837 (0x7031 – 4) . 4 CRC32, =. . . . ( !) . ?
. . U-Boot . vfat . . OpenWRT . SPI-flash. . . . . , dataflash raw-NAND . .. , . .
. … . . . . , . . , . .
. , … , . : « , . .» , .
P.S.
CodeRushGracias de nuevo por la invitaciĂłn a Habr. Y sĂ, siempre quiero escribir sobre algo serio, sobre compiladores, sobre programaciĂłn segura directamente en hardware. Y la fuerza es suficiente solo para la lectura ligera del viernes. Bien, supongamos que se ha comenzado. Un gran viaje siempre comienza con un pequeño paso.