какой тип кода может динамически запускать ловушку sigbus для доступа к данным без выравнивания? - PullRequest
1 голос
/ 29 апреля 2019

Я ищу SIGBUS на доступ к данным без выравнивания. Я отслеживаю одну из этих ошибок, и я хотел бы знать, как это происходит на sitara am335x. Может кто-нибудь дать мне пример кода, чтобы описать это или обеспечить его запуск.

Добавление фрагмента кода:

int Read( void *value, uint32_t *size, const uint32_t baseAddress )
{
    uint8_t *userDataAddress = (uint8_t *)( baseAddress + sizeof( DBANode ));
    memcpy( value, userDataAddress, ourDataSize );
    *size = ourDataSize;
    return 0;
}

Узел DBA - это объект класса из 20 байтов. baseAddress - это mmap в файл с общей памятью, опять-таки с типом объекта класса DBANode, приведенным к uint32_t, чтобы можно было выполнить арифметику.

Это разборка раздела:

    91a8:   e51b3010    ldr r3, [fp, #-16]
    91ac:   e5933000    ldr r3, [r3]
    91b0:   e51b0014    ldr r0, [fp, #-20]  ; 0xffffffec
    91b4:   e51b1008    ldr r1, [fp, #-8]
    91b8:   e1a02003    mov r2, r3
    91bc:   ebffe72b    bl  2e70 <memcpy@plt>
    91c0:   e51b3010    ldr r3, [fp, #-16]
    91c4:   e5932000    ldr r2, [r3]
    91c8:   e51b3018    ldr r3, [fp, #-24]  ; 0xffffffe8
    91cc:   e5832000    str r2, [r3]

00002e70 <memcpy@plt>:
    2e70:   e28fc600    add ip, pc, #0, 12
    2e74:   e28cca08    add ip, ip, #8, 20  ; 0x8000
    2e78:   e5bcf868    ldr pc, [ip, #2152]!    ; 0x868

Когда точно такая же база кода была восстановлена, проблема просто исчезла. Может ли gcc создать 2 разные версии инструкций с одинаковой оптимизацией -O0, указанной для gcc?

Я также изучил библиотеку, чтобы файлы obj дампировали в обеих компиляциях. Они точно такие же. API используется довольно часто. Однако сбой происходит только после длительного использования в течение нескольких дней. Я читаю один и тот же узел каждые 500 мс. Так что это не соответствует. Должен ли я смотреть на повреждение указателя?

Ответы [ 2 ]

1 голос
/ 02 мая 2019

Оказывается, baseAddress является проблемой. Как я уже упоминал, это mmap для общей памяти, где mmap может выйти из строя. Сбой mmap возвращает -1, и код проверял NULL и продолжал запись в -1, т.е. 0xFFFFFFFF, вызывая сигбус. Код 1 виден, когда мы используем memcpy. Попытка любого другого доступа, например, прямой байтовой адресации, дает код 3 с sigbus.

Я до сих пор не уверен, почему он вызывает SIGBUS вместо SIGSEGV. Разве это не должно быть нарушением памяти? Вот пример:

int main(int argc, char **argv)
{
    // Shared memory example                                                    
     const char *NAME = "SharedMemory";                                          
     const int SIZE = 10 * sizeof(uint8_t);                                      
     uint8_t src[]={0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00};          
     int shm_fd = -1;                                                            

     shm_fd = shm_open(NAME, O_CREAT | O_RDONLY, 0666);                          
     ftruncate(shm_fd, SIZE);                                                    

    // Map shared memory segment to address space                               
     uint8_t *ptr = (uint8_t *) mmap(0, SIZE, PROT_READ | PROT_WRITE | _NOCACHE, MAP_SHARED, shm_fd, 0);
     if(ptr == MAP_FAILED)                                                       
     {                                                                           
          std::cerr << "ERROR in mmap()" << std::endl;                            
      //  return -1;                                                              
      }                                                                           
      printf("ptr = 0x%08x\n",ptr);                                               
      std::cout << "Now storing data to mmap() memory" << std::endl;              
      #if 0                                                                           
      ptr[0] = 0x11;                                                              
      ptr[1] = 0x22;                                                              
      ptr[2] = 0x33;                                                              
      ptr[3] = 0x44;                                                              
      ptr[4] = 0x55;                                                              
      ptr[5] = 0x66;                                                              
      ptr[6] = 0x77;                                                              
      ptr[7] = 0x88;                                                              
      ptr[8] = 0x99;                                                              
      ptr[9] = 0x00;                                                              
      #endif                                                                          

      memcpy(ptr,src,SIZE);   //causes sigbus code 1                              
      shm_unlink(NAME);
}

Я до сих пор не знаю, почему mmap дает сбой на shm, хотя у меня доступно 100 МБ ОЗУ, и все мои ограничения по ресурсам установлены на неограниченное количество с более чем 400 fds (файловыми дескрипторами), которые все еще доступны из предела 1000 fds. !!!

1 голос
/ 30 апреля 2019

Из Технического справочного руководства Cortex-A8:

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

Примечание Доступ к данным, пересекающий границу слова, может увеличить время доступа.

Установка бита A в регистр управления CP15 c1 позволяет выполнить выравнивание проверка. Когда бит A установлен в 1, доступ к памяти двух типов генерировать сигнал сброса данных и код состояния ошибки выравнивания:

  • 16-битный доступ без выравнивания по полуслову

  • 32-разрядная загрузка или хранилище, не выровненное по словам

Обнаружение ошибки выравнивания является обязательной функцией генерации адреса. а не опционально поддерживаемая функция внешней памяти аппаратное обеспечение управления. См. Справочное руководство по архитектуре для дополнительная информация о поддержке доступа к выравниваемым данным.

Из ARM ARM, инструкции, которые всегда генерируют ошибку выравнивания, если не выровнены по размеру передачи: LDREX, STREX, LDREXD, STREXD, LDM, STM, LDRD, RFE, SRS, STRD, SWP, LDC, LDC2, STC, STC2, VLDM, VLDR, VPOP, VPUSH, VSTM, VSTR.

Кроме того, большинство PUSH, POP и VLDx, где: align: указано.

Далее

В реализации, включающей расширения виртуализации, Нераспределенный доступ к устройству или строго упорядоченной памяти всегда вызывает Ошибка выравнивания Исключение сброса данных

Как и в связанном вопросе, структуры являются наиболее очевидным способом вызвать «намеченные» не выровненные обращения, но любое повреждение указателя стека или другого указателя переменной также даст тот же результат. В зависимости от того, как настроено ядро, это повлияет, если обычный доступ к одному слову / полуслову просто медленный, или вызовет ошибку.

Если у вас есть доступ к трассировке ETM, вы сможете определить точный доступ. Похоже, что у детали есть ETM / ETB (поэтому не требуется никакого необычного устройства захвата трассировки), но я не представляю, как легко будет заставить инструменты работать с ним.

Что касается кода, который может вызвать это, да, даже memcpy() может быть проблемой . Поскольку набор инструкций ARM имеет оптимизацию для передачи нескольких регистров (или пар регистров в AA64), оптимизированные библиотечные функции предпочтут «поток» данных, а не выполнять побайтовую загрузку и сохранение. В зависимости от структуры данных и цели компиляции, вполне возможно, что в результате будет получен недопустимый LDM по невыровненным адресам.

...