![]() |
Модераторы: feodorv, GremlinProg, xvr, Fixin |
![]() ![]() ![]() |
|
MuForum |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 427 Регистрация: 13.6.2007 Где: Молдова, Кишинев Репутация: нет Всего: 4 |
Доброе время суток.
Мне необходимо программно получить размер максимального значения стека процесса и текущий размер стека процесса. Операционная система: Windows XP, 2003. -------------------- "Чтобы правильно задать вопрос, нужно знать большую часть ответа!" (Р. Шекли) |
|||
|
||||
Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 8 Всего: 154 |
у процесса нет стека, стек может быть только у потока
|
|||
|
||||
GremlinProg |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
это практически одно и то же, конечно, с учетом замены "процесс" на "поток" IMAGE_OPTIONAL_HEADER::SizeOfStackReserve - это максимальный размер стека IMAGE_OPTIONAL_HEADER::SizeOfStackCommit - это размер той небольшой части стека, из того, что зарезервировано, которая уже точно в памяти (т.е. стек этого размера выделяется сразу при загрузке образа) получить можно так (без проверок):
а чтобы получить реально распределенный размер стека (если он больше SizeOfStackCommit), нужно пройти по всем виртуальным страницам, вплоть до IMAGE_OPTIONAL_HEADER::SizeOfStackReserve, и определить, в каком они состоянии, COMMITED будет означать что регион физически распределен получить состояние виртуального региона можно с помощью VirtualQuery дополнительная информация: http://msdn.microsoft.com/en-us/library/ms686774(VS.85).aspx мне лично непонятно только одно: даже если первый адрес 64кб, и пусть, к примеру даже куча и стек забирают себе по странице, откуда первые адреса стека набирают себе еще 64кб, т.е.: 1. первый адрес: 0x00010000 2. добавляем 1мб: 0x00110000 3. добавляем 2стр: 0x00112000 4. округляем на границу 64кб: 0x00120000 все, по идее, должен быть 0x00120000, а он 0x00130000 хотя, можно предположить, что куча забирает сразу 64 кб, после чего начинает отбирать стек свой 1мб, тогда все сходится: 1. первый адрес: 0x00020000 2. добавляем 1мб: 0x00120000 3. добавляем 1стр: 0x00121000 4. округляем на границу 64кб: 0x00130000 -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||
|
|||||
GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: 2 Всего: 26 |
значения в PE заголовке показывают каким был стек при загрузке программы, до того как начал выполняться какой-то ее код, и это относится только к первому потоку программы. В процессе работы программы стек первого потока может быть изменен, а стеки других потоков могут иметь произвольный размер.
Правильные параметры стека надо смотреть в TEB(TIB), поля StackLimit и StackBase. Правильные потому что система берет информацию о стеке потока именно там. ЗЫ: GremlinProg, йа вернулсо |
|||
|
||||
GremlinProg |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
и о чем ты так хотел нам поведать? особенно интересует, с чем ты несогласен, т.к. это ![]() если интерпретировать в вопросе "процесс - как первичный поток", то MuForum именно об этом и спрашивает, причем "относится только к первому потоку программы" - ересь, т.к. любой наследуемый поток смотрит именно в PE, если ему не сообщили параметры стека, причем по ссылке это указано, и если бы ты ее читал, писать такое бы не стал
правильные параметры не первичного потока GoldFinch, ты можешь опять пойти отдыхать, если будешь продолжать в том же духе, т.к. к теме твой пост не относится -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||
|
|||||
Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 8 Всего: 154 |
[offtopic]Интересно, зачем знать размер стека главного потока программы? Судя по предыдущим постам, ТС пишет много-поточный сервер для какой-то игры. Какой должна быть логика работы приложения, что-бы потребовалось знание размера стека, я даже представить не могу. Прошу заранее простить мою ограниченность...
![]() |
|||
|
||||
GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: 2 Всего: 26 |
GremlinProg, действительно, при создании нового потока, если самому не указать параметры стека потока, то его размеры будут взяты из IMAGE_NT_HEADERS, в том числе и размеры первого потока при его создании берутся от туда же, но как этот факт относится к вопросу ТСа? При чем тут текущий размер стека и максимальный размер стека?
Поля IMAGE_OPTIONAL_HEADER могут быть в любой момент изменены, и в них могут быть в любой момент времени записаны новые значения которые будут использоваться как значения по умолчанию при создании новых потоков. (Кроме того, заголовок программы в памяти может быть вообще удален, или его может вообще не быть в памяти, если программа загружалась не системным загрузчиком.) Но допустим IMAGE_OPTIONAL_HEADER никто не трогал. Однако сам стек в процессе выполнения потока может быть заменен на другой, путем замены esp, и значений в TEB, это будет правильный стек, с точки зрения ОС Можно просто поменять esp, однако возможны проблемы при вызове АПИ и эксепшенах, когда ОС будет проверять стек (что будет точно - не помню).
по каким страницам? где их искать? |
|||
|
||||
GremlinProg |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
GoldFinch, у меня складывается впечатление, что ты к нам ненадолго и очень спешишь скоротать этот и так не большой срок,
тебя проще исключить из разговора, чем отвечать на каждый вопрос мимо темы при том же, при чем размер стека делится на commited и reserved, нагугли адресацию Win32 по обычным виртуальным страницам, покрывающих всесь стек, где искать, я показал, прекращай флудить, ждем MuForum за ответом на вопрос Lazin, мне это тоже интересно, никогда не пользовался -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: 2 Всего: 26 |
GremlinProg,
1) я написал что предложенный тобой метод не позволяет получить текущие размеры стека. Потому что значения в заголовке никак не связаны ни с текущими размерами стека, ни с темы размерами которые были использованы при создании стека первого потока. Это понятно? 2) я спросил, где брать адрес базы стека, чтобы определить состояние его страниц. В твоем посте сказано что надо проверять страницы, но не сказано с какой страницы надо начинать проверку. Где искать страницы принадлежащие стеку ты не сказал. Как найти базу (первую страницу) стека? Это сообщение отредактировал(а) GoldFinch - 25.8.2009, 16:29 |
|||
|
||||
GremlinProg |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
SizeOfStackReserve - общий размер стека, он нужен, чтобы определить адрес, начиная с которого он начнет расти вниз, регион стека, начиная с максимального адреса минус SizeOfStackCommit проверять не нужно, т.к. он точно выделен, для этого его и нужно посмотреть, можно и не смотреть, если не жалко времени на проверку этой страницы (обычно страницы, но тут может быть указано и больше) текущий размер стека можно получить вычитая esp из вершины стека (максимального его адреса), с которой он начался, это очевидно, поэтому я просто описал как найти вершину, за некоторыми дополненими, которые не вполне сходятся, и о которых я упомянул при расчетах а чтобы получить реальный объем памяти, используемый под стек, нужно пройти по страницам, т.е. под размерами стека можно понимать и то и другое, потому я и описывал оба варианта в расчетах все расписал, но ежели до сих пор непонятно, причем это даже в статье описано: GetSystemInfo SYSTEM_INFO::lpMinimumApplicationAddress, который обычно равен смещению первых 64байт (SYSTEM_INFO::dwAllocationGranularity) это и есть минимальный виртуальный адрес, но за поправками на кучу (см. расчеты), этот адрес нужно увеличить на dwAllocationGranularity -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: 2 Всего: 26 |
GremlinProg, то что ты предлагаешь, содержит столько допущений построенных на пустом месте, что я хз как такое вообще можно предлагать
SizeOfStackReserve и SizeOfStackCommit можно использовать только в том случае, если их никто не менял. Определение вершины стека, которое ты предлагаешь, сработает только в том случае, если начиная с 0x10000 в памяти сначала расположена куча, а потом стек, и если известен размер кучи, и если известен размер стека. Я не знаю что именно гарантирует что куча и стек будут выделены именно в таком порядке. Есть большое подозрение что это поведение загрузчика характерно только для ХР и ранних ОС, а в висте и семерке все может быть по другому. Кроме того, это все относится к системному загрузчику. Но допустим, поля в PE заголовке не изменены, и нам известна организация памяти при запуске программы. Где гарантия что за время выполнения программы стек не перенесли в другое место? Или что его размер не уменьшили? Есть куда как более надежные способы определения размеров стека. Как я уже говорил, базу и максимальный размер текущего стека можно посмотреть в TEB. Это то, что ОС считает текущим стеком потока (его можно изменить.) Другой способ основан на том, что около вершины стека лежит самый первый SEH фрейм. Пройдя по цепочке SEH фреймов его можно найти, и соответственно найти вершину того стека, который использовался при запуске .exe --------------------------------- Чтобы это все не казалось чем-то нереальным, надо напомнить, что программа может запакована каким-нибудь UPX, это полностью убивает все предположения о расположении стека в памяти. Упаковщик может запускаться со стеком небольшого размера, затем править IMAGE_NT_HEADERS, запускать распакованный код в новом потоке, и убивать первый поток. |
|||
|
||||
GremlinProg |
|
||||||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
GoldFinch, какие допущения-то?
и с каких щей это мой способ-то? не понимаю PE тоже я придумал? какой же кривой я придумал PE, чтобы хранить в нем параметры кучи и стека, какая мелочь, и зачем они там )) страничное выравние, минимальный диапазон страниц для распределения - это условие, читай MSDN и допущения - это простой расчет: если по верхним адресам точно стековый диапазон, а не хватает 64 байт, стало быть они внизу, а что может быть внизу? да куча, в которой этот стек и расположен, странно бы было, если бы курица появилось раньше яйца, так же странно было бы, если бы стек появился бы раньше кучи, которая его рождает, но это так - предположение, которое довольно просто проверить: проходим HeapWalk и ищем в ней стек, нет - значит нет, считаем, что так и росло
все может быть, лучше не гадать, а проверить проверяется элементарно: F11 под отладчиком на любом приложении -> CallStack -> первый исполняемый адрес -> Registers -> ESP если ESP меньше 0x00120000, значит порядок изменен
там же, где и гарантия на то, что порше, сброшенный со скалы ф пропасть поедет после этого своим ходом, несерьезно, конечно, но ты уже 3 поста потратил на это доказательство
вот с этого места ты начинаешь показывать чудеса техники:
а теперь назови хоть один критерий, который говорит, что обращение к TEB - это надежнее, чем обращение к PE, (формат PE, кстати в отношении стабильности обгоняет TEB, который может меняться от версии к версии операционки) с SEH - все аналогично, хотя и менее проблематично, но это вообще нонсенс: лезть в ран-тайм специфику за тем, что лежит в PE, причем получать приближенные значения с гаданием на молоке, а вдруг до SEH что-то есть и утверждать что это "куда как более надежные способы определения размеров стека", парадокс да, это на самом деле самый эффективный способ упасть со скалы, ты прав, особенно когда траекторию движения с нее тебе будет указывать не сила тяготения (Ось), а упрямый арёл (UPX), который побывал на разных планетах и знает, какое ЖЕ должно быть на нашей, и не важно, что полетать на других планетах тебе уже не придется )) -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||||||
|
|||||||||
GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: 2 Всего: 26 |
чтото пошел совсем какой-то оффтоп %)
Cтек не расположен в куче. Cтек выделяется через VirtualAlloc. Стек не может быть выделен в куче так как она не обеспечивает выравнивания. Стек создается отдельно от кучи. Куча создается при создании объекта процесса и его юзермодных структур, перед заполнением PEB. После этого создается поток при создании которого создается его стек.
Я уже говорил что размер стека в PE заголовке может не соответствовать реальному размеру стека. И документация на PE заголовок никак не позволяет определить вершину(или базу) стека. Хотя MS не рекомендует напрямую использовать TEB, де-факто она будет стабильна еще очень долго. Слишком много приложений ее используют (упаковщики, протекторы, антивирусы и т.п.). Добавлено через 2 минуты и 28 секунд GremlinProg, так ты согласен что предложенный тобой способ 1) не позволит запаковать или защитить программу; 2) не будет гарантированно работать в произвольный момент времени работы программы. |
|||
|
||||
GremlinProg |
|
||||||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
да, только кто ж его начал? напоминаю: свое первое предупреждение ты получил именно за это, видимо понравилось ну так я не спорю, может и вне кучи странное дело, чем же тогда пользуется куча ) хотя принципы ее действия я уже не раз описывал, можешь почитать
если в куче ни чего нет, чего бы ей и не обеспечивать выравнивания? нижний-то адрес для стека не важен, важен верхний ) кстати, если он в куче, то проще всего использовать HeapWalk для определения его размера хотя тут без разницы, где он расположен, я бы расположил в куче - удобно как на первичный, так и на последующие потоки, все в одном месте
а кто же мешает несоответствовать аналогичным параметрам в TEB'е?
меня терзают сомнения, GoldFinch, почему-то когда я обращаю внимание на ограничения, ты вдруг соглашаешься, я же мог соврать, смотри, подловлю )
вообще-то такое используют очень редко, когда это действительно надо, и нет возможности поступить иначе, как не залезти в недокументированные структуры т.е. приложений таких как раз слишком немного я бы с удовольствием сказал "да, согласен", только тут есть небольшая проблемка: я не пытался даже это доказывать, а ты, в свою очередь, даже не пытался это опровергнуть, т.е. подозреваю, что это твое высказывание упало откуда-то свыше на тебя и ты решил его сразу записать, очевидно, чтобы не забыть вообще-то у нас такие обороты не приняты, спор был в контексте что использовать: документированное - PE или недокументированное - TEB, причем ты настаиваешь на том, что читать TEB гораздо надежнее, чем читать PE, и, учитывая, что ты перешел на висту и семерку, - кроссплатформеннее, о как, так что не перегибай -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||||||
|
|||||||||
MuForum |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 427 Регистрация: 13.6.2007 Где: Молдова, Кишинев Репутация: нет Всего: 4 |
Извиняюсь за задержку.
В общем так, мне нужно узнать максимальный размер стека всех потоков и текущий размер стеков всех потоков. Всё это должно быть под операционную систему семейства Windows, а именно XP, 2003, 2008, Vista. Стек во время работы программы изменяться не будет. Он будет задаваться при создание потоков. Всё это мне необходимо для того, чтобы сделать визуальную статистику использования стека. -------------------- "Чтобы правильно задать вопрос, нужно знать большую часть ответа!" (Р. Шекли) |
|||
|
||||
GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: 2 Всего: 26 |
MuForum, максимальный размер стека, не меняется если его не менять
![]() а чтобы определить размеры стеков каждого потока, надо очевидно их перечислить (Thread32First/Thread32Next) можно получить esp из контекста каждого потока: OpenThread/GetThreadContext но где брать границы их стеков я не знаю. Разве что выполнять свой код с контексте каждого потока чтобы получить TEB, но наверное список TEB можно получить както еще. |
|||
|
||||
GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: 2 Всего: 26 |
на самом деле все просто:
NtQueryInformationThread с классом ThreadBasicInformation позволяет получить структуру THREAD_BASIC_INFORMATION в которой есть указатель на TEB, TebBaseAddress, откуда можно получить границы стека (база и максимальный размер). Тогда надо посчитать разницу между вершиной стека (база+макс_размер) и esp (который можно получить из контекста потока), это будет текущий размер всех данных в стеке. Однако для определения размера памяти которая выделена под стек, надо перебрать страницы стека, начиная с его базы, до первой страницы с флагом COMMITED. |
|||
|
||||
GremlinProg |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
тогда уж лучше всего использовать CRT и получить базу стека так, как это делает crtexe.c:
это вершина стека код более-менее переносим, и есть некоторая гарантия, что поддержка CRT будет периодически делать апгрейд для NtCurrentTeb -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
DrHex |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 171 Регистрация: 2.5.2009 Репутация: нет Всего: нет |
Максимальный размер стека узнать наверника не возможно(можно только предпологать). Так происходят случае когда стек не вылитает(переполнения стека) а происходит выход за границу стека, то и есть стек это виртуальная память, так как она не прерывна, то есть возможноть что после конца стека(конец памяти, которую выделал системный загрузчик) будет следующий буфер(то и есть валидная память).
Так что есть вариант, очень простой, а именно ставим хук(лучше не виндовский) на создание потока, получаем максимальный размер стека. Ну а вот что на счет статистики, то сдесь вопрос сложнее все зависит от конкретики. 1) Если требуется только текущее состояние потока то читай GoldFinch 2) Если требуется полное состояние(то и есть история) я имею ввиду пик стека, средние значения и так далее, то это сложнея - CreateProcess(с параметром DEBUG) - Цикл дебагера - Дизассемблер длин() - Ставим бряки на calls(так как раскрутка стека почти всегда в начали функции) - И бряку на создания потоков(хоть и приходит сообщения(в цикле дебагинга), но там кажется нельзя получить стек потока ) Вообщем все довольно просто...... --------------------
google.com и это все. |
|||
|
||||
GremlinProg |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
DrHex, перечитай тему, т.к. мы уже давно выяснили, что сделать это можно
смотря что понимать под "концом стека", верхний или нижний? вверху стоит сторож в виде одной страницы, а внизу - стек потому и распределется сразу, чтобы внизу были неиспользуемые приложением страницы, хотя, учитывая, что куча идет первой, внизу таки есть критическая зона, только при чем тут определение размеров стека? а в остальном, я так и не понял, что ты хотел сказать, т.к. язык которым ты пользуешься к программному не относится, а по-человечески у тебя сформулировать ни мысль ни план не получилось, и при чем тут дебагер, или ты предлагаешь писать отладчик чтобы собирать статистику по стеку? -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||
|
|||||
GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: 2 Всего: 26 |
Модератор: Сообщение скрыто. |
|||
|
||||
GremlinProg |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
скорее всего сторож стоит таки внизу (не дотягивает он вверху на страницу) -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
Lycifer |
|
||||||
Шустрый ![]() Профиль Группа: Участник Сообщений: 144 Регистрация: 4.11.2007 Репутация: нет Всего: нет |
GremlinProg что не понятного???
Можно взять готовый отладчик....
GremlinProg - и это отладчик????? - Без пользовательского интерфейса(точнее вообще без управлением отладчиком) - Без возможности трасировки(пошаговой и так далее). - Без загрузки символом - Без полного дизассембилирования - и еще пунктов 100-200. И так это часть отладчика. А какой другой вариант собирать полную статистику?????? Отладочное апи требуется для того что бы была возможность собирать инфу. (специально для GremlinProg такая информация как раскрутка стека, то и есть вычисление пика, среднее значения, какие потоки были запущенны и с каким размером стека) <...скрыто...>
Это сообщение отредактировал(а) GremlinProg - 28.8.2009, 18:15 |
||||||
|
|||||||
![]() ![]() ![]() |
Правила форума "C/C++: Системное программирование и WinAPI" | |
|
На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы . Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |