Обновлено
Хотя это и не Cortex-M1, приведенный ниже пример работает как с micro: bit (Cortex-M0, среда выполнения ZFP), так и с STM32F407 (среда выполнения SFP,тот же результат, не показан).
main.adb
with System;
with System.Storage_Elements;
with Interfaces;
with Ada.Text_IO;
procedure Main is
type Byte_Array is array (Natural range 0 .. 3) of Interfaces.Unsigned_8;
Bytes : Byte_Array with
Address => System.Storage_Elements.To_Address (16#0#);
Other_Bytes : Byte_Array;
begin
Other_Bytes := Bytes; -- Line 17
-- Output via semihosting.
for I in Other_Bytes'Range loop
Ada.Text_IO.Put (Other_Bytes (I)'Image);
end loop;
Ada.Text_IO.New_Line; -- Required to flush semihosting output buffer.
loop
null; -- Line 26
end loop;
end Main;
сеанс отладки (Cortex-M0, используя pyocd
в качестве сервера)
$ arm-eabi-gdb main
GNU gdb (GDB) 8.3 for GNAT Community 2019 [rev=gdb-8.3-ref-194-g3fc1095]
Copyright (C) 2019 Free Software Foundation, Inc.
[...]
Reading symbols from main...
(gdb) target remote :3333
Remote debugging using :3333
0x0000020a in _start ()
(gdb) load
Loading section .text, size 0x4fc lma 0x0
Loading section .rodata, size 0x20 lma 0x4e8
Loading section .data, size 0x4 lma 0x4fc
Start address 0x20a, load size 1312
Transfer rate: 3 KB/sec, 437 bytes/write.
(gdb) b 26
Breakpoint 1 at 0x14a: file [...]/src/main.adb, line 26.
(gdb) c
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.
Breakpoint 1, main () at [...]/src/main.adb:26
26 null; -- Line 26
(gdb) p/x Other_Bytes
$1 = (0 => 0x88, 0x8, 0x0, 0x20)
(gdb) x/4xb 0
0x0 <__vectors>: 0x88 0x08 0x00 0x20
(gdb) p/x Bytes (0)'Address
$2 = 0x0
(gdb) p/x Other_Bytes (0)'Address
$3 = 0x20000848
(gdb)
выход (полухостинг, запуск в отдельном терминале)
$ nc localhost 4444
136 8 0 32
Примечание по использованию System.Null_Address
.
Обратите внимание, что ранее я использовал System.Null_Address
для ссылки на адрес 0
. В этом случае (и большую часть времени) это будет работать. Однако System.Null_Address
не представляет ячейку памяти 0
по определению. Следовательно, To_Address (16#0#)
действительно может быть более безопасным (см. Также ARM 34/2 и ARM 37.c ).
Подсказки, которыеможет идентифицировать причину.
На основании предоставленной информации (неожиданный вызов обработчика исключений SVCall
и другое поведение в зависимости от уровня оптимизации) я подозреваю некоторое повреждение памяти (например, из-за записи в неправильную памятьместоположения; в C это часто вызвано висячими указателями; в Ada это может быть связано с использованием «небезопасных» языковых функций, таких как Unchecked_Access
, Unrestricted_Access
и атрибут Address
).
Отслеживание повреждения памяти может быть очень сложным, поскольку место (исходный код), где причинен ущерб, может даже не быть близко к тому месту, где вы действительно наблюдаете проблему.
Первое, что я бы начал исследовать, - это вызов обработчика исключений SVCall
. Я не ожидал бы, что инструкция ARM svc
будет выполнена в вашем случае. Некоторые шаги, которые я бы попробовал (нет гарантии, что это приблизит вас к решению):
- Разберите части соответствующего кода вокруг проблемы (в вашем случае
memcpy
), используя arm-eabi-objdump -d -S
иоставьте его в качестве ссылки. - Подключите отладчик
gdb
, загрузите программу и проверьте, сопоставима ли разборка рядом с Other_Bytes := Bytes;
и memcpy
с тем, что вернул objdump
. Используя мой собственный пример:
(gdb) info line main.adb:17
Line 17 of "[...]/src/main.adb" starts at address 0xca <_ada_main+10> and ends at 0xe6 <_ada_main+38>.
(gdb) x/14i 0xca
[...]
и
(gdb) info address memcpy
Symbol "memcpy" is at 0x300 in a file compiled without debugging.
(gdb) x/100i 0x300
[...]
- Установите опцию, чтобы показать разборку для каждой строки и установить точку останова непосредственно перед чтением памяти (то есть
Other_bytes := Bytes;
). Опять же, используя мой собственный пример:
(gdb) set disassemble-next-line on
(gdb) b 17
- Запустите программу (используя
c
) и, как только остановитесь в точке останова, снова проверьте разобранные инструкции. Продолжайте шаг за шагом (используя stepi
и затем последовательно нажимая <return>
, чтобы повторить последнюю команду) и внимательно следите за инструкциями процессора, показанными внимательно. Проверьте, соответствуют ли они ожиданиям (вывод objdump
). Я ожидаю, что в какой-то момент фактический и ожидаемый поток программ начнет отклоняться. Попробуйте посмотреть, если / где это происходит на уровне инструкций процессора.