Core dump flash config is corrupted как исправить

Board esp32s3 Device Description esp32s3 devkitc n8r8 Hardware Configuration Native USB port plugged into computer, serial convert USB port not plugged in. Version v2.0.3 IDE Name Arduino IDE, Plat...

My understanding [EDITED based on subsequent investigations]

Background

There are multiple ways to connect from a a host (Mac/PC) USB port to an ESP32-S3 for bootloading (download) and serial terminal purposes:

  1. Use a physical USB-to-serial converter chip/module, connected to the ESP32-S3’s serial TX and RX lines
  2. Use the ESP32S3’s onboard USB controller, wire the USB port directly to the ESP32-S3.

If using option (1) there is no problem. (For example this is the UART USB jack on the ESP32-S3 DevKit board.) However, that requires an extra part and it’s otherwise nice to use the integrated USB controller. So, let’s assume option (2). This requires configuring the ESP32-S3 to act as a serial port device. There are again multiple ways to do that:

  1. Use the ESP32-S3’s internal USB-OTG (On The Go) peripheral, which supports acting as a general purpose USB host or device (the bidirectionality is what makes it «On The Go»); in software, set the peripheral up to act as a USB device, and implement the USB CDC («Communications Device Class», aka serial port) protocol, and thus the device shows up as a serial port to the host.
  2. Use the ESP32-S3’s internal USB Serial/JTAG peripheral, which is a separate special purpose USB controller that only supports USB CDC (serial port) and JTAG (debugging port, not important here) protocols.

Using the dedicated USB Serial/JTAG controller is simpler for software, since the hardware takes care of most of the details of USB. However, the USB-OTG controller is more general, allowing other device classes (such as mass storage) in addition to being a serial port.

Importantly, the bootloader (used to upload code) and the application (which wants to Serial.print to a console) might make different choices about which controller to use. The Arduino platform, for example, tends to use TinyUSB, a software USB stack that expects a fully general USB controller, which would imply the USB-OTG controller.

Issues

So far this is all lovely but now there are some wrinkles.

As @me-no-dev noted above, the bootloader cannot use the USB-OTG controller. This is related to a spot of confusion over one-time-programmable EFUSE bits as described in security advisory AR2022. Basically, for many ESP32-S3 parts, bootloader USB-OTG access is permanently disabled.

So, the bootloader uses the USB Serial/JTAG controller instead (if allowed). This works just fine and allows the flash to be programmed in the normal way. HOWEVER, it is observed that sometimes the bootloader is unable to exit into the application, and a manual reset is required to start the app.

This appears to happen if the bootloader (download mode) is entered (by reboot-to-bootloader typically triggered by DTR/RTS wiggles) FROM an application using the USB-OTG controller (not hardware USB Serial/JTAG), which is the Arduino runtime’s default.

Per @me-no-dev’s comment above, the reasons for this are not entirely understood, but it’s thought to be something about switching between the two controllers?

Workarounds

There are two known ways to work around this:

  1. After loading code, use a full hardware reset (probably a button) to launch the app. This fully resets the board and skips the USB Serial/JTAG controller, avoiding issues with switching. However it’s inconvenient, impossible without physical access, and disruptive to port connectivity.
  2. In the application, use the USB Serial/JTAG controller instead of the USB-OTG controller. This limits flexibility (can’t be a mass storage device at the same time) and makes the port show up as a generic «Espressif USB JTAG/serial debug unit».

To switch the Arduino runtime to the USB Serial/JTAG controller (workaround (ii)):

image

  • In the Arduino IDE, select Tools > USB Mode > Hardware CDC and JTAG (pictured above).
  • With arduino-cli, use --build-property=build.usb_mode=1 on the command line (untested).
  • With platformio, use build_flags = -DARDUINO_USB_MODE=1 in platformio.ini.
  • If using ESP-IDF and not Arduino, select ESP_CONSOLE_USB_SERIAL_JTAG in menuconfig.

Both workarounds are somewhat unfortunate, which is why this bug exists and people are grumpy.

Investigation notes

As noted above, success/failure seems to be triggered not by what app we’re loading but by what app was running before resetting to the bootloader:

  • run OTG-using app, reset to run, flash JTAG/Serial-using app => loads but does NOT run
  • reset to start JTAG/Serial-using app, flash the same app again => loads and DOES run
  • flash OTG-using app => loads and DOES run right away!
  • flash OTG-using app again => loads and does NOT run
  • reset to run OTG-using app, flash OTG-using app again => loads and does NOT run
  • reset to run OTG-using app, flash JTAG/Serial-using app => loads but does NOT run
  • reset to start JTAG/Serial-using app, flash OTG-using app => loads and DOES run

So somehow, when resetting back to the bootloader, a running OTG-using app leaves state in the system that prevents the bootloader from jumping to start ANY program it loads. Maybe the reboot-to-bootloader code in the OTG-based driver is somehow doing things slightly wrong?

For reference, the USB Serial/JTAG controller can be distinguished from the USB-OTG controller externally; it shows up as «Espressif USB JTAG/serial debug unit» with VID:PID 303A:1001.

Rebooting from app to bootloader and bootloader to app (the path that fails) is generally managed by wiggling DTR and RTS serial control lines — this is the «Hard resetting via RTS pin…» message from in esptool.py (with the default --after=hard_reset). Of course these «pins» are purely virtual in this case, contained within the emulated serial port.

The USB Serial/JTAG controller manages DTR/RTS wiggle detection directly. This is described in section 30.3.2 in the technical reference:

image

Here is the further discussion in section 30.4.2:

image

The reset-to-app code in esptool.py does this, assuming DTR=0 and RTS=0 on entry:

    def hard_reset(self):
        if self.uses_usb():
            self._check_if_can_reset()

        print("Hard resetting via RTS pin...")
        self._setRTS(True)  # EN->LOW
        if self.uses_usb():
            # Give the chip some time to come out of reset,
            # to be able to handle further DTR/RTS transitions
            time.sleep(0.2)
            self._setRTS(False)
            time.sleep(0.2)
        else:
            self._setRTS(False)

(Tangent: self.uses_usb() is currently broken; see bug espressif/esptool#756 and PR espressif/esptool#757. Fixing it doesn’t help this issue, though.)

DTR and RTS can be wiggled manually for testing with miniterm, with ^T^D and ^T^R respectively. After reproducing this problem (successfully flashing an app, but failing to reboot-to-app), we can see this:

% python -m serial.tools.miniterm /dev/ttyACM0 115200
--- Miniterm on /dev/ttyACM0  115200,8,N,1 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
--- RTS inactive ---  [[ note: ^T^R was pressed here ]]
--- DTR inactive ---  [[ ^T^D was pressed here ]]
--- RTS active ---  [[ ^T^R ]]
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x15 (USB_UART_CHIP_RESET),boot:0x0 (DOWNLOAD(USB/UART0))
Saved PC:0x40041a76
waiting for download

So it does reboot on wiggle, but the waiting for download indicates it ended up back in the bootloader. It’s as if the «download flag» was not successfully reset during the RTS=0 DTR=0 point. If I go through the other sequence to explicitly set the «download flag», I get identical output:

--- RTS inactive ---
--- DTR active ---
--- RTS active ---
--- DTR inactive ---
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x15 (USB_UART_CHIP_RESET),boot:0x0 (DOWNLOAD(USB/UART0))
Saved PC:0x40041a76
waiting for download

When reboot-to-app does work (after running the esp-idf/examples/system/console/basic sample app built with ESP_CONSOLE_USB_SERIAL_JTAG), we can see both of the USB/Serial controller’s DTR/RTS wiggle sequences work correctly. Going from bootloader to app:

waiting for download
--- DTR inactive ---
--- RTS inactive ---
--- RTS active ---
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x15 (USB_UART_CHIP_RESET),boot:0x8 (SPI_FAST_FLASH_BOOT)
Saved PC:0x400428a0
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3810,len:0x113c
load:0x403c9700,len:0xa4c
load:0x403cc700,len:0x2af0
entry 0x403c9898
 ... blah blah blah ...
Type 'help' to get the list of commands.
Use UP/DOWN arrows to navigate through command history.
Press TAB when typing command name to auto-complete.
Your terminal application does not support escape sequences.

Line editing and history features are disabled.
On Windows, try using Putty instead.
esp32s3>

Going from app back to bootloader:

esp32s3> --- RTS inactive ---
--- DTR active ---
--- RTS active ---
--- DTR inactive ---
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x15 (USB_UART_CHIP_RESET),boot:0x0 (DOWNLOAD(USB/UART0))
Saved PC:0x4037c14a
waiting for download

Note the boot:0x8 (SPI_FAST_FLASH_BOOT) instead of boot:0x0 (DOWNLOAD(USB/UART0)).

As a final note, fixing uses_usb() detection creates a problem with false errors:

WARNING: ESP32-S3 chip was placed into download mode using GPIO0.
esptool.py can not exit the download mode over USB. To run the app, reset the chip manually.
To suppress this note, set --after option to 'no_reset'.
*** [upload] Error 1

Apparently GPIO_STRAPPING gets zeroed out by internal resets, including resets triggered by DTR/RTS wiggles detected by the USB Serial/JTAG peripheral. That triggers the false locked-into-bootloader alert from esptool. (In actual fact if the error is bypassed, esptool can reboot into app just fine in that scenario.)

Esptool detects another method of software reboot-into-bootloader (RTC_CNTL_FORCE_DOWNLOAD_BOOT) to avoid some false alarms, but the USB Serial/JTAG peripheral doesn’t use that mechanism. USB Serial/JTAG triggered reboot does have a reason code in RTC_CNTL_RTC_RESET_STATE_REG, but esptool.py’s initial reset always leaves that reason code in place, even when the system is locked into the bootloader. So that’s not a useful discriminator. With uses_usb() broken (as it currently is at head), at least that check is disabled and doesn’t get in the way…

The main relevance of the above is that there seems to be a bunch of subtle/hidden chip state controlling whether or not the system starts in the bootloader or jumps to the app. The logic is hard to observe, hidden in the obscurities of the closed-source ROM, and thus hard to debug from outside.

В этой статье я расскажу, как можно настроить сохранение дампов в Linux при падении процессов, такие дампы называют core dumps.

Введение

При работе в Linux у вас запускается множество процессов, но иногда какой-нибудь процесс может начать падать. Или какая-нибудь программа может не запускаться. Иногда разработчики для анализа таких ситуаций просят выслать им дамп ядра (core dumps) относящийся к падению их программы.

Вообще core dumps никак не связан с ядром Linux. Термин “Ядро” в этом случае относится к старой памяти на магнитных сердечниках из старых систем (magnetic core memory). Хотя такая память уже не используется, но термин core dumps всё еще употребляется.

В core dumps сохраняется память сбойного процесса при его падении, а также некоторая служебная информация.

Ограничение на размер дампа

Самое главное ограничение, которое говорит системе, делать дамп упавшего процесса или не делать – это ограничение максимального размера дампа. Если это ограничение равняется 0 – то дамп не будет делаться совсем. Также вы можете ограничить максимальный размер дампа произвольным числом в байтах, или отключить лимит вовсе.

Посмотреть текущее ограничение для своего пользователя и своей оболочки можно выполнив команду:

$ ulimit -S -c
0

В выводе у меня 0 – это означает что создание дампов под моим пользователем и в моём окружении невозможно.

Командой выше мы смотрели мягкое (soft) ограничение. Это фактическое ограничение, которое влияет на процессы.

Есть ещё жесткое ограничение (hard), его может поменять только root пользователь. Давайте посмотрим как сейчас нас ограничивает жёсткое ограничение:

$ ulimit -H -c
unlimited

Из этого следует, что сейчас жёсткое ограничение нас вообще не ограничивает. Поэтому мы можем изменить для себя мягкое ограничение и разрешить создание дампов. Это делается командой:

$ ulimit -c unlimited

Проверим:

$ ulimit -S -c
unlimited

Куда сохранять дампы ядра

Чтобы узнать, куда сейчас сохраняются дампы ядра, нужно прочитать файл /proc/sys/kernel/core_pattern:

*** Debian 11 ***
$ cat /proc/sys/kernel/core_pattern
core

*** Ubuntu 22.04 ***
$ cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport -p%p -s%s -c%c -d%d -P%P -u%u -g%g -- %E

Debian называет файлы дампов именем core и куда-то их сохраняет (если честно, я не выяснял куда).

Ubuntu через пайп передаёт дамп на обработку программе apport.

Вы можете временно (до перезагрузки) изменить путь и имя дампов задав свой шаблон, например таким способом:

$ sudo sysctl -w kernel.core_pattern=/var/crash/core.%u.%e.%p

Выше мы меняем параметр sysctl – kernel.core_pattern. И задаём ему значение состоящее из пути и имени файла, а также используем переменные:

  • %u – имя пользователя (под каким пользователем работала упавшая программа);
  • %e – имя программы;
  • %p – номер процесса (pid).

Проверим что путь изменился. Затем нужно создать этот каталог, если его ещё не существует и убедиться что наш пользователь сможет в него писать.

*** Ubuntu 22.04 ***
$ cat /proc/sys/kernel/core_pattern
/var/crash/core.%u.%e.%p
$ ls -ld /var/crash/
drwxrwxrwx 2 root root 4096 апр 21 01:01 /var/crash/

*** Debian ***
$ cat /proc/sys/kernel/core_pattern
/var/crash/core.%u.%e.%p
$ ls -ld /var/crash/
ls: невозможно получить доступ к '/var/crash/': Нет такого файла или каталога
$ sudo mkdir /var/crash/; sudo chmod 777 /var/crash/
$ ls -ld /var/crash/
drwxrwxrwx 2 root root 4096 мая 31 15:50 /var/crash/

Хорошо, путь мы поменяли и каталог по этому пути сделали доступным. Ограничение на размер дампов для своей оболочки тоже сняли.

Создаём сбойную программу

Для того чтобы проверить что дампы для нас уже выполняются нужно запустить программу, которая точно упадёт. Напишем эту программу сами:

$ nano crash.c
int main()
{
    return 1/0;
}

Наша программа выполняет деление на 0 и это приводит к сбою.

Теперь нужно откомпилировать эту программу (возможно вам придется установить gcc):

$ gcc -o crash crash.c
crash.c: In function ‘main’:
crash.c:3:13: warning: division by zero [-Wdiv-by-zero]
    3 |     return 1/0;
      |             ^

Даже компилятор показывает, что наша программа содержит ошибку деления на ноль.

Теперь запустим программу:

$ ./crash
Floating point exception (core dumped)

Программа падает с ошибкой и видно что был сформирован core dumped. Если бы дампы ядра были отключены, этой надписи в скобках не появилось бы.

Посмотрим на наш файл дампа:

$ ls -l /var/crash/
total 120
-rw------- 1 alex alex 299008 мая 31 12:58 core.1000.crash.1397

Настройка создания дампов на постоянной основе

Проделанное выше вернётся к значениям по умолчанию после перезагрузки. Также остальные процессы, которые были запущены от имени других пользователей и в других оболочках не будут создавать дампы при падениях. Исправим это внеся изменения в конфигурационные файлы.

Ограничение на размер дампа

Настройка лимитов производится в конфиге /etc/security/limits.conf или лучше создать отдельный конфиг в каталоге /etc/security/limits.d/.

$ sudo nano /etc/security/limits.d/core.conf
root    hard        core        unlimited
root    soft        core        unlimited
*       hard        core        unlimited
*       soft        core        unlimited

Звездочка означает что это правило применимо ко всем пользователям в системе, кроме root. Для root пользователя нужно создавать отдельные правила.

Дальше идет тип ограничения. Soft – это мягкое ограничение, которое фактически ограничивает процессы. А hard – это верхняя граница для soft. Соответственно soft должно быть всегда меньше hard.

Core – это специальное ограничение для дампов ядра. Ограничивать лимитами можно многие параметры, но это выходит за рамки этой статьи.

Unlimited – означает, что мы не ограничиваем размер дампов. Здесь вы можете указать число в байтах, или 0 чтобы совсем выключить создание дампов.

Чтобы внесённые изменения применились к какому-нибудь процессу, этот процесс нужно перезагрузить.

Путь сохранения дампов

Отредактируйте конфиг /etc/sysctl.conf:

$ sudo nano /etc/sysctl.conf
kernel.core_pattern=/var/crash/core.%u.%e.%p
fs.suid_dumpable=2

Вторым параметром мы разрешаем программам имеющим бит Setuid тоже сохранять дампы при падениях.

Setuid – это бит разрешения, который позволяет пользователю запускать исполняемый файл с правами владельца этого файла. Другими словами, использование этого бита позволяет нам поднять привилегии пользователя в случае, если это необходимо.

Параметр fs.suid_dumpable для sysctl может принимать следующие значения:

  • 0 – отключено;
  • 1 – включено;
  • 2 – включено с ограничениями. Делает дампы ядра доступными для чтения только пользователю root.

Чтобы применить изменения, выполните sysctl с ключом -p.

$ sudo sysctl -p
kernel.core_pattern = /var/crash/core.%u.%e.%p
fs.suid_dumpable = 2

Разрешаем сохранять дампы службам systemd

Хорошо, путь к созданию дампов мы указали и лимиты для всех пользователей убрали.

Но для сохранения дампов служб работающих в systemd, нам нужно настроить ещё один конфиг.

$ sudo nano /etc/systemd/system.conf
DefaultLimitCORE=infinity

Чтобы применить изменения выполните следующие команды:

$ sudo systemctl daemon-reexec
$ sudo systemctl restart nginx.service

И чтобы проверить применились ли наши изменения посмотрите информацию о лимитах для процесса nginx:

$ systemctl status nginx.service | grep 'Main PID'
   Main PID: 2099 (nginx)
$ cat /proc/2099/limits | grep 'core'
Max core file size        unlimited            unlimited            bytes

В командах выше я вначале получаю PID основного процесса nginx, а затем использую его, чтобы посмотреть лимиты этого процесса.

Вот теперь nginx сможет сохранить дамп при падении.

Сохранения дампа при падении nginx

Чтобы имитировать падение nginx, убьём его главный процесс отправив сигнал SIGSEGV:

$ sudo kill -s SIGSEGV 2099

Проверим что дамп появился:

$ ls -l /var/crash/
total 1940
-rw------- 1 root root 2347008 мая 31 13:41 core.0.nginx.2099
-rw------- 1 alex alex  299008 мая 31 12:58 core.1000.crash.1397

Чтение дампов ядра

Чтобы понять что произошло нужно прочитать дамп ядра. Для этого используется утилита gdb (её нужно установить). Вначале указывается путь к программе, затем путь к дампу:

*** Дамп нашей сбойной программы ***
$ gdb ./crash /var/crash/core.1000.crash.1397
Program terminated with signal SIGFPE, Arithmetic exception.
Программа завершилась с сигналом SIGFPE, арифметическое исключение.

*** Дамп процесса nginx ***
$ sudo gdb /usr/sbin/nginx /var/crash/core.0.nginx.2099
Program terminated with signal SIGSEGV, Segmentation fault.
Программа завершена с сигналом SIGSEGV, ошибка сегментации.

Вывод

Дампы ядра могут быть полезны для устранения неполадок, но могут стать причиной утечки конфиденциальных данных. По возможности отключайте дампы ядра и включайте их только тогда, когда это действительно необходимо. И проверяйте, надежно ли хранятся файлы, чтобы обычные пользователи не могли видеть их. И независимо от того, какой выбор вы сделали, всегда проверяйте, работает ли ваша конфигурация именно так, как вы ожидаете.

Сводка

Настройка дампов ядра (core dumps) в Linux

Имя статьи

Настройка дампов ядра (core dumps) в Linux

Описание

В этой статье я расскажу, как можно настроить сохранение дампов в Linux при падении процессов, такие дампы называют core dumps

Оценка: 84.65%14 Голосов

Общая

Потребовалось перенести старый ESXi Sever 5.5 на новый хост с новым, отличающимся от старого, RAID-контроллером. В результате изменения устройства в конфигурации ESXi появились неправильные пути до системных папок.

После переноса жёстких дисков в новый сервер и его запуска система выдала ошибки No Datastores Have Been Configured on the Host и No coredump target has been configured. host core dumps cannot be saved. И если с отсутствием датасторов проблема лечится добавлением дисков в конфигурации ESXi, после чего все виртуальные машины доступны, то с второй ошибкой все чуть сложнее.

Данная ошибка может возникнуть как в ESXi 5.x так и 6.х. На сайте VMware Knowledge Base есть описание ошибки и возможные методы ее устранения, но в моем случае описанные действия отличаются.

Для устранения ошибки потребуется SSH доступ к серверу.

После успешной авторизации есть проверяем наличие разделов для coredump


esxcli system coredump partition get

И получаем ответ Not a known device: mpx.vmhba1:C0:T0:L0 где mpx.vmhba1:C0:T0:L0 это название устройства.

Так как RAID-контроллер сменился на совсем другой то следует узнать новое имя устройства:


esxcli storage core path list

pathlist

В поле Device указано новое имя, что нам и необходимо. В моем случае это имя выглядит как naa.600508b100104c395657453248550006

Далее необходимо узнать какие разделы присутствуют на устройстве


fdisk -l

partlist

Раздел должен быть не менее 100Мб

Выбираем раздел 7, так как по умолчанию используется он. Но вы можете выбрать и другой раздел или создать новый. После чего указываем новый раздел для system coredump.

Что указать нужный раздел используйте сочетание Device:Partition. В моем случае это naa.600508b100104c395657453248550006:7


esxcli system coredump partition set --partition="naa.600508b100104c395657453248550006:7"
esxcli system coredump partition set --enable true

После этого вводим


esxcli system coredump partition list

И видим

coredumplist

  • Просмотров: 15437

Понравилась статья? Поделить с друзьями:
  • Corba transient error
  • Copy error 0xffffffff ps3
  • Copied error please send this in trx discord server что делать
  • Copied error please send this helpers on our discord server как исправить
  • Copied error please send this helpers on our discord server trx