С того, где запускает пространство памяти процесса и где оно заканчивается?

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


void MyDump(const void *m, unsigned int n)
{
        const unsigned char *p = reinterpret_cast<const unsigned char *>(m);
        char buffer[16];
        unsigned int mod = 0;

        for (unsigned int i = 0; i < n; ++i, ++mod) {
                if (mod % 16 == 0) {
                        mod = 0;

                        std::cout << " | ";

                        for (unsigned short j = 0; j < 16; ++j) {
                                switch (buffer[j]) {
                                        case 0xa:
                                        case 0xb:
                                        case 0xd:
                                        case 0xe:
                                        case 0xf:
                                                std::cout << " ";

                                                break;

                                        default: std::cout << buffer[j];
                                }
                        }

                        std::cout << "\n0x" << std::setfill('0') << std::setw(8) << std::hex << (long)i << " | ";
                 }

                buffer[i % 16] = p[i];

                std::cout << std::setw(2) << std::hex << static_cast<unsigned int>(p[i]) << " ";

                if (i % 4 == 0 && i != 1)
                        std::cout << " ";
        }
}

Теперь, как я могу знать, с которого адрес запускает мое пространство памяти процесса, где все переменные хранятся? И как делают меня теперь, какой длины область?

Например:


MyDump(0x0000 /* <-- Starts from here? */, 0x1000 /* <-- This much? */);

С уважением,
nhaa123

5
задан nhaa123 9 April 2010 в 16:21
поделиться

6 ответов

Обзор

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

В вашем случае вас особенно интересует, «где лежат переменные». API системной кучи в Windows очень вам поможет. Ссылка действительно неплохая, и хотя это не будет единая непрерывная область, API сообщит вам, где находятся ваши переменные.

В общем, однако, ничего не зная о том, где размещена ваша память, вам придется провести сканирование всего адресного пространства процесса. Если вам нужны только данные, вам также придется выполнить некоторую фильтрацию и для них, потому что бессмыслица с кодом и стеком тоже присутствует. Наконец, чтобы избежать ошибки сегментирования при сбросе адресного пространства, вам может потребоваться добавить обработчик сигнала segfault, который позволяет пропускать несопоставленную память во время сброса.

Схема памяти процесса

В ходе выполнения процесса у вас будет несколько непересекающихся участков памяти для печати. Они будут включать:

  1. Скомпилированный код (только для чтения),
  2. данные стека (локальные переменные),
  3. статические глобальные объекты (например, из общих библиотек или в вашей программе) и
  4. динамические данные кучи (все из malloc или нового ).

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

Для этого у нас есть ...

Полезные инструменты

Вместо того, чтобы слепо искать адресное пространство от 0 до 2 ^ 64 (которое, как мы все знаем, очень велико), вы захотите использовать Инструменты разработчика ОС и компилятора, чтобы сузить область поиска. Кому-то нужны эти инструменты, может быть, даже больше, чем вам; просто нужно их найти. Вот некоторые из которых я знаю.

Отказ от ответственности: я не знаю многих эквивалентов Windows для многих из этих вещей, хотя я уверен, что они где-то существуют.

Я уже упоминал API системной кучи Windows . Это лучший сценарий для вас. Чем больше вы найдете в этом ключе, тем точнее и проще будет ваш дамп. На самом деле ОС и среда выполнения C довольно много знают о вашей программе. Это вопрос извлечения информации.

В Linux типы памяти 1 и 3 доступны с помощью таких утилит, как / proc / pid / maps. В / proc / pid / maps вы можете увидеть диапазоны адресного пространства, зарезервированные для библиотек и программного кода. Вы также можете увидеть биты защиты; Например, диапазоны только для чтения, вероятно, являются кодом, а не данными.

Что касается Windows, то Марк Руссинович написал несколько статей о том, как узнать об адресном пространстве Windows-процесса и о том, где хранятся различные вещи. Я полагаю, у него там могут быть хорошие указатели.

2
ответ дан 18 December 2019 в 14:44
поделиться

Ну, вы не можете, не совсем ... по крайней мере, не переносным способом. Для стека вы можете сделать что-то вроде:

void* ptr_to_start_of_stack = 0;
int main(int argc, char* argv[])
{
    int item_at_approximately_start_of_stack;
    ptr_to_start_of_stack = &item_at_approximately_start_of_stack;
    // ... 
    // ... do lots of computation
    // ... a  function called here can do something similar, and
    // ... attempt to print out from ptr_to_start_of_stack to its own
    // ... approximate start of stack
    // ... 
    return 0;
}

Что касается попытки взглянуть на диапазон кучи, во многих системах вы можете использовать функцию sbrk () (в частности, sbrk (0) ), чтобы получить указатель на начало кучи (обычно он растет вверх, начиная с конца адресного пространства, тогда как стек обычно растет вниз с начала адресного пространства).

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

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

2
ответ дан 18 December 2019 в 14:44
поделиться

AFAIK, это зависит от ОС, вы должны посмотреть, например, на сегментация памяти.

1
ответ дан 18 December 2019 в 14:44
поделиться

Краткий ответ на этот вопрос: нельзя подходить к этой проблеме таким образом. Способ размещения процессов в памяти во многом зависит от компилятора и операционной системы, и нелегко определить, где находится весь код и переменные. Чтобы точно и полностью найти все переменные, вам нужно написать большие части отладчика самостоятельно (или позаимствовать их из кода реального отладчика).

Но, возможно, вы могли бы немного сузить круг вопросов. Если вам действительно нужна просто трассировка стека, ее несложно сгенерировать: Как можно получить трассировку стека в C?

Или, если вы хотите изучить сам стек, легко получить указатель на текущую вершину стека (просто объявите локальную переменную, а затем возьмите ее адрес). Самый простой способ получить нижнюю часть стека - объявить переменную в main, сохранить ее адрес в глобальной переменной и использовать этот адрес позже как «нижний» (это просто, но не совсем «чисто»).

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

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

7
ответ дан 18 December 2019 в 14:44
поделиться

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

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

1
ответ дан 18 December 2019 в 14:44
поделиться

Вы не можете, по крайней мере, не переносно. И нельзя делать много предположений.

Если вы не используете это на CP / M или MS-DOS.

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

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

Нет никаких гарантий что любой из вашего кода, например, находится даже в непрерывном пространстве. Виртуальная память и загрузчик могут разместить код практически там, где захотят. Также нет никакой гарантии, что ваши данные находятся где-то рядом с вашим кодом. Фактически, нет никакой гарантии, что вы даже сможете ПРОЧИТАТЬ пространство памяти, в котором находится ваш код. (Выполнить, да. Прочитать, может быть, нет.)

На высоком уровне ваша программа разбита на 3 раздела: код, данные и стек. ОС размещает их там, где считает нужным, а менеджер памяти контролирует, что и где вы можете видеть.

Есть множество вещей, которые могут замутить эти воды.

Однако.

Если хочешь.

Вы можете попробовать включить в свой код «маркеры». Например, поместите в начало файла функцию с именем «startHere ()», а затем в конец - функцию с именем «endHere ()». Если вам повезет, для программы с одним файлом у вас будет непрерывный блок кода между указателями функций для «startHere» и «endHere».

То же самое и со статическими данными. Вы можете попробовать ту же концепцию, если она вам вообще интересна.

0
ответ дан 18 December 2019 в 14:44
поделиться
Другие вопросы по тегам:

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