Почему некоторые библиотеки и другие части повторяются в виртуальной памяти Linux с GDB?

На самом деле это четыре вопроса:

  1. Как мне узнать их кодовые точки?
  2. Какое-то регулярное выражение?
  3. Как подсчитать, сколько ячеек символов занимает строка?
  4. Как стереть все, что было выведено?

OP упоминает xterm, но только последние два, возможно, относятся к xterm.

Для (1) и (2) команда echo не очень помогает. Лучше использовать printf , который распознает экранирование обратной косой черты. В некоторых реализациях (например, GNU coreutils ), который включает константы Unicode, например,

printf '\u94f6\btest'

, хотя для регулярных выражений вам снова лучше использовать язык сценариев, такой как Perl (который может обрабатывать UTF-8).

Дополнительная литература:

Вопросы (3) и (4) более интересны. Во-первых, сценарий не может точно сказать, сколько символьных ячеек занимает строка, а может измерить это только постфактум. Это потому, что ширина основана на сочетании поведения терминала и ядра.

  • xterm использует wcwidth , чтобы решить, насколько широким должен быть символ, с некоторыми проблемами, касающимися «широких» (двойных) шрифтов, и реализацией wcwidth, отражающей предвзятость разработчика относительно значений Unicode неоднозначной ширины.xterm можно настроить (во время выполнения) для использования его копии реализации Маркуса Куна wcwidth ; вас предупреждают, что он может быть неполным и не соответствовать фактической информации о языковом стандарте системы.
  • когда xterm получает указание стереть часть символа двойной ширины (как в данном примере), он заменяет другую часть пробелом. Большинство других терминалов, имитирующих xterm, делают это (хотя при быстрой проверке я заметил, что один просто перемещает курсор, что приводит к перекрытию широкого символа и текста ASCII). Если бы вы знали , что значение имеет двойную ширину, вы могли бы просто изменить свое представление о том, где находится курсор.
  • ядро ​​Linux ничего не знает о wcwidth . Системы на базе Linux, начиная с 2004 , имеют функцию в stty под названием iutf8 :

, которая сообщает ядру , что входные данные кодируются в UTF -8, для правильной поддержки редактирования в каноническом режиме ввода

  • функция ядра Linux полезна для редактирования ввода , потому что она помогает драйверу терминала делать что-то разумное, когда возврат удаляет предыдущий персонаж. Однако сопоставимой функции для вывода нет.

Вы можете , как предлагается, использовать отчет о позиции курсора (escape-последовательность), чтобы найти положение курсора в разных точках. Но если вы собираетесь использовать это, чтобы решить, как очистить строку, может показаться более прямым просто переместить в позицию перед печатью значения Unicode и начать очистку с этой точки.

В качестве альтернативы вы можете указать терминалу сохранить позицию курсора перед печатью широкого символа и восстановить ее (вернуться). Это может показаться более понятным и предсказуемым. После восстановления позиции курсора вы можете очистить строку. Все три могут быть выполнены с помощью управляющих последовательностей - или tput :

tput sc
printf '\u94f6'
tput rc
tput el
printf 'test'

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

4
14.10.2018, 16:08
1 ответ

В выводе gdbотсутствует важная часть информации :о правах доступа к страницам. (Они показаны в Solaris и FreeBSD , но не в Linux. )Вы можете увидеть их, взглянув на /proc/<pid>/maps; карты для вашего примера Protostar показывают

$ cat /proc/.../maps
08048000-08049000 r-xp 00000000 00:0f 2925       /opt/protostar/bin/stack6
08049000-0804a000 rwxp 00000000 00:0f 2925       /opt/protostar/bin/stack6
b7e96000-b7e97000 rwxp 00000000 00:00 0
b7e97000-b7fd5000 r-xp 00000000 00:0f 759        /lib/libc-2.11.2.so
b7fd5000-b7fd6000 ---p 0013e000 00:0f 759        /lib/libc-2.11.2.so
b7fd6000-b7fd8000 r-xp 0013e000 00:0f 759        /lib/libc-2.11.2.so
b7fd8000-b7fd9000 rwxp 00140000 00:0f 759        /lib/libc-2.11.2.so
b7fd9000-b7fdc000 rwxp 00000000 00:00 0
b7fe0000-b7fe2000 rwxp 00000000 00:00 0
b7fe2000-b7fe3000 r-xp 00000000 00:00 0          [vdso]
b7fe3000-b7ffe000 r-xp 00000000 00:0f 741        /lib/ld-2.11.2.so
b7ffe000-b7fff000 r-xp 0001a000 00:0f 741        /lib/ld-2.11.2.so
b7fff000-b8000000 rwxp 0001b000 00:0f 741        /lib/ld-2.11.2.so
bffeb000-c0000000 rwxp 00000000 00:0f 0          [stack]

(Пример Protostar работает на виртуальной машине, которую легко взломать, предположительно, чтобы сделать упражнения более понятными :здесь нет защиты NX и ASLR.)

Выше вы увидите, что то, что кажется повторяющимся сопоставлением в gdb, на самом деле соответствует разным сопоставлениям с разными разрешениями. Текстовый сегмент отображается -только для чтения и исполняемый; сегмент данных отображается только для чтения -; BSS и куча отображаются на чтение -на запись. В идеале сегмент данных, BSS и куча не являются исполняемыми, но в этом примере отсутствует поддержка NX, поэтому они исполняемые. Каждая разделяемая библиотека получает собственное сопоставление для своего текстового сегмента, сегмента данных и BSS. Четвертое сопоставление — это не -доступный для чтения, не -доступный для записи, не -исполняемый сегмент, обычно используемый для защиты от переполнения буфера (, хотя, учитывая возраст используемого здесь ядра и библиотеки C, это может быть что-то другое. ).

Смещение, если оно задано, указывает смещение данных в файле, которое не обязательно имеет много общего с его позицией в адресном пространстве. При загрузке на это распространяются ограничения выравнивания; например, заголовки программы libc-2.11.2.soопределяют два заголовка «LOAD»:

Type           Offset   VirtAddr   PhysAddr   FileSiz  MemSiz   Flg Align
LOAD           0x000000 0x00000000 0x00000000 0x13d2f4 0x13d2f4 R E 0x1000
LOAD           0x13e1cc 0x0013f1cc 0x0013f1cc 0x027b0  0x0577c  RW  0x1000

(Используйте readelf -l, чтобы увидеть это.)

Это может привести к множественным отображениям по одному и тому же смещению с разными виртуальными адресами, если секции, сопоставленные с сегментами, имеют разные флаги защиты. В случае stack6:

Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
LOAD           0x000000 0x08048000 0x08048000 0x00604 0x00604 R E 0x1000
LOAD           0x000604 0x08049604 0x08049604 0x00114 0x00128 RW  0x1000

(Это также объясняет небольшой размер, показанный proc info mappingsдля stack6:: каждый заголовок запрашивает менее 4 КБ с выравниванием 4 КБ, поэтому он получает два сопоставления 4 КБ с одинаковым смещением по разным адресам.)

Пустые отображения соответствуют анонимным отображениям; подробности см. в man 5 proc. Вам нужно разбить mmapв gdb, чтобы определить, чему они соответствуют.

Вы не можете видеть сопоставления ядра (, кроме устаревших vsyscallна некоторых архитектурах ), потому что они не имеют значения с точки зрения процесса (они недоступны ).

Я не знаю лучшего gdbварианта, я всегда использую /proc/$$/maps.

См. Как запускаются программы :Исполняемые файлы ELF для получения подробной информации о формате ELF, читаемом ядром, и о том, как он отображается в распределении памяти; он содержит указатели на множество других справочных материалов.

6
27.01.2020, 20:53

Теги

Похожие вопросы