Hello, lav03!
You wrote on Fri, 28 Nov 2003 12:46:10 GMT:
l> Понятно. А что это за ф-ция GetLogicalAddress(..)? Это не апишная, ее в l> МСДМН нет.
Оно в старом MSDN было, за 2000 год вроде, в статьях из MSJ.
l> Ты не мог бы мне ее код дать?
//==============================================================================
// Given a linear address, locates the module, section, and offset containing
// that address.
//
// Note: the szModule paramater buffer is an output buffer of length specified
// by the len parameter (in characters!)
//==============================================================================
BOOL CCrashHandler::GetLogicalAddress(PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD& offset)
{
MEMORY_BASIC_INFORMATION mbi;
if (!VirtualQuery(addr, &mbi, sizeof(mbi)))
return FALSE;
DWORD hMod = (DWORD) mbi.AllocationBase;
if (!GetModuleFileName((HMODULE) hMod, szModule, len))
return FALSE;
// Point to the DOS header in memory
PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER) hMod;
// From the DOS header, find the NT (PE) header
PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS) (hMod + pDosHdr->e_lfanew);
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION (pNtHdr);
DWORD rva = (DWORD) addr - hMod; // RVA is offset from module load address
// Iterate through the section table, looking for the one that encompasses
// the linear address.for (unsigned i = 0; i < pNtHdr->FileHeader.NumberOfSections; i++, pSection++)
{
DWORD sectionStart = pSection->VirtualAddress;
DWORD sectionEnd = sectionStart + max(pSection->SizeOfRawData, pSection->Misc.VirtualSize);
// Is the address in this section???if ((rva >= sectionStart) && (rva <= sectionEnd))
{
// Yes, address is in the section. Calculate section and offset,
// and store in the "section" & "offset" params, which were
// passed by reference.
section = i + 1;
offset = rva - sectionStart;
return TRUE;
}
}
return FALSE; // Should never get here!
}
Best regards,
Sergey.
Posted via RSDN NNTP Server 1.8 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
В моем обработчике SE вызывается IntelStackWalk(pExceptionInfo->ContextRecord),
где pExceptionInfo — это e.m_ExceptionRecord (не буду писать подробно). В общем, e.m_ExceptionRecord инициализируется в конструкторе CStructuredException. Все, как у Рихтера.
IntelStackWalk выдает прекрасный дамп, где самая первая строчка — адрес (естест-но со смещением) ф-ции
CSimpleString.SetAt(..);
Затемм идет адрес foo(), а потом OnBnClickedButton1().
Я об этом и мечтал!!!
Но если я изменю код:
void CErrHndlTestDlg::OnBnClickedButton1()
{
try{
int res = foo();
}
catch(CMemoryException e) {...}
catch(CStructuredException e) {...}
}
int foo()
{
try{
throw new CMemoryException; // С++ исключение
}
catch(CMemoryException e) {...}
catch(CStructuredException e) {...}
return 0;
}
и в обработчике для CMemoryException получу контекст-рекорд
Hello, lav03!
You wrote on Fri, 28 Nov 2003 18:00:36 GMT:
l> и в обработчике для CMemoryException получу контекст-рекорд
l> CONTEXT Context; l> Context.ContextFlags = CONTEXT_FULL; l> GetThreadContext(m_hThread, &Context); l> IntelStackWalk(&Context);
l> первый адрес в дампе получаю какой — то бещеный:
l> Address Frame Logical addr Module l> 7FFE0304 0012FA14 0000:00000000
Это адрес в NTDLL.DLL — функция ZwGetContextThread. А что ты там ожидал увидеть?
l> а следующий адрес указывает даже не на мою foo(), а на l> OnBnClickedButton1().
А что отладчик показывает в стеке?
l> Такое ощущение, что фрейм не формируется.
Функция GetThreadContext действительно без фрейма, поэтому ее в дампе и не будет. А вообще отладчиком глянь.
l> Делел в VC++7. Опцию /Oy отключил.
l> Не пойму разницы. По крайней мере адрес возврата из foo() должен быть в l> стеке
У тебя исключение где поймалось — в OnBnClickedButton1 или в foo? Судя по приведенному коду, оно вообще ловиться не должно, поскольку кидаешь ты CMemoryException*, а ловишь CMemoryException.
Best regards,
Sergey.
Posted via RSDN NNTP Server 1.8 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, Sergey, Вы писали:
l>> Не пойму разницы. По крайней мере адрес возврата из foo() должен быть в l>> стеке
S>У тебя исключение где поймалось — в OnBnClickedButton1 или в foo? Судя по приведенному коду, оно вообще ловиться не должно, поскольку кидаешь ты CMemoryException*, а ловишь CMemoryException.
S>Best regards, S> Sergey.
Нет, на самом деле я ловлю CMemoryException*, это описка. И оно ловится именно в foo(), только вот foo(), почему-то, в стеке не присутствует во время снятия списка вызовов. Усли убрать try...catch из foo(), то оно поймается в OnBnClickedButton1() и адрес этой OnBnClickedButton1() будет отсутствовать в дампе, а следующим после
7FFE0304 0012FA14 0000:00000000 будет адрес _AfxDispatchCmdMsg.
Не понимаю, почему ф-ция, из которой выброшено C++ исключение отсутствует в списке вызовов, ведь на момент снятия дампа мы из ее тела еще не вышли.
А как вообще люди решают проблему, когда нужно локализовать ошибку при возникновении исключения в распространяемом коммерческом продукте. Что, PDB — файл распространяют?
Hello, lav03!
You wrote on Mon, 01 Dec 2003 08:57:34 GMT:
l> Нет, на самом деле я ловлю CMemoryException*, это описка. И оно ловится l> именно в foo(), только вот foo(), почему-то, в стеке не присутствует во l> время снятия списка вызовов. Усли убрать try...catch из foo(), то оно l> поймается в OnBnClickedButton1() и адрес этой OnBnClickedButton1() будет l> отсутствовать в дампе, а следующим после 7FFE0304 0012FA14 0000:00000000 l> будет адрес _AfxDispatchCmdMsg. Не понимаю, почему ф-ция, из которой l> выброшено C++ исключение отсутствует в списке вызовов, ведь на момент l> снятия дампа мы из ее тела еще не вышли.
Эта фигня происходит из-за того, что функция ZwGetContextThread скомпилена без кадра стека. Поэтому IntelStackWalk хватает кадр предыдущей функции (foo), из которого вытаскивает адрес возврата на OnBnClickedButton1(). В результате foo в дамп не попадает.
Best regards,
Sergey.
Posted via RSDN NNTP Server 1.8 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Hello, lav03!
You wrote on Mon, 01 Dec 2003 11:46:06 GMT:
l> А как вообще люди решают проблему, когда нужно локализовать ошибку при l> возникновении исключения в распространяемом коммерческом продукте.
А так и решают С дизассемблером в руках
l> Что, PDB — файл распространяют?
Не поможет. Еще pdb'шки для системных dll'ек нужны, а фиг ты энд-юзера заставишь их установить.
Best regards,
Sergey.
Posted via RSDN NNTP Server 1.8 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, lav03, Вы писали:
L>А как вообще люди решают проблему, когда нужно локализовать ошибку при возникновении исключения в распространяемом коммерческом продукте. Что, PDB — файл распространяют?
Вы читаете или нет, что вам люди отвечают???
Писали же -- на клиентской машине нужно только
получить список адресов, в виде
, затем список загруженных DLL вместе с их версиями,
все это отсылается разработчику и на месте переводится
в удобочитаемый код.
Как следствие, приходится не только хранить все
версии своей программы с PDB-шниками, но еще и все
версии всех windows, тоже с PDB-шниками (слава WMWare!)
Hello, Блудов!
You wrote on Tue, 02 Dec 2003 02:57:35 GMT:
L>> А как вообще люди решают проблему, когда нужно локализовать ошибку при L>> возникновении исключения в распространяемом коммерческом продукте. Что, L>> PDB — файл распространяют?
БП> Вы читаете или нет, что вам люди отвечают???
БП> Писали же -- на клиентской машине нужно только БП> получить список адресов, в виде
БП> SomeDLL 0xFFF89898 БП> SomeDLL 0xFFF89A98 БП> SomeDLL 0xFFF89B98
Вообще-то речь о том и шла, что без pdb (хотя бы stripped) получить полный call stack иногда невозможно.
Best regards,
Sergey.
Posted via RSDN NNTP Server 1.8 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, Sergey, Вы писали:
S>Вообще-то речь о том и шла, что без pdb (хотя бы stripped) получить полный call stack иногда невозможно.
Согласен. Мне пришлось запретить компилятору выкидывать стековые фреймы.
С inline-ми не помогает, но более-менее приличную информацию все же
можно собрать.
Здравствуйте, Sergey, Вы писали:
S>Hello, lav03! S>You wrote on Mon, 01 Dec 2003 08:57:34 GMT:
l>> Нет, на самом деле я ловлю CMemoryException*, это описка. И оно ловится l>> именно в foo(), только вот foo(), почему-то, в стеке не присутствует во l>> время снятия списка вызовов. Усли убрать try...catch из foo(), то оно l>> поймается в OnBnClickedButton1() и адрес этой OnBnClickedButton1() будет l>> отсутствовать в дампе, а следующим после 7FFE0304 0012FA14 0000:00000000 l>> будет адрес _AfxDispatchCmdMsg. Не понимаю, почему ф-ция, из которой l>> выброшено C++ исключение отсутствует в списке вызовов, ведь на момент l>> снятия дампа мы из ее тела еще не вышли.
S>Эта фигня происходит из-за того, что функция ZwGetContextThread скомпилена без кадра стека. Поэтому IntelStackWalk хватает кадр предыдущей функции (foo), из которого вытаскивает адрес возврата на OnBnClickedButton1(). В результате foo в дамп не попадает.
S>Best regards, S> Sergey.
А ведь если отключить оптимизацию, то foo() попадает в дамп. Значит в этом случае кадр стека все же формируется?
Можно ли как нибудь заставить функцию кадр стека формироваться, обхитрить?
Hello, lav03!
You wrote on Tue, 02 Dec 2003 08:41:11 GMT:
S>> Эта фигня происходит из-за того, что функция ZwGetContextThread S>> скомпилена без кадра стека. Поэтому IntelStackWalk хватает кадр S>> предыдущей функции (foo), из которого вытаскивает адрес возврата на S>> OnBnClickedButton1(). В результате foo в дамп не попадает.
l> А ведь если отключить оптимизацию, то foo() попадает в дамп.
Не верю. Ты наверное что-то перепутал.
l> Значит в этом случае кадр стека все же формируется?
Как это он сформируется для функции из ntdll? Я дизассемблером смотрел — нет там никакой установки ebp, почти сразу int 2E идет.
l> Можно ли как нибудь заставить функцию кадр стека формироваться, обхитрить?
Ну так я говорил уже — опция компилятора /Oy- после опций оптимизации, и все будет почти как надо.
Best regards,
Sergey.
Posted via RSDN NNTP Server 1.8 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[22]: Дамп стека при возникновении исключения
От:
Аноним
Дата:
03.12.03 09:04
Оценка:
Здравствуйте, Sergey, Вы писали:
S>Hello, lav03! S>You wrote on Tue, 02 Dec 2003 08:41:11 GMT:
S>>> Эта фигня происходит из-за того, что функция ZwGetContextThread S>>> скомпилена без кадра стека. Поэтому IntelStackWalk хватает кадр S>>> предыдущей функции (foo), из которого вытаскивает адрес возврата на S>>> OnBnClickedButton1(). В результате foo в дамп не попадает.
l>> А ведь если отключить оптимизацию, то foo() попадает в дамп. S>Не верю. Ты наверное что-то перепутал.
l>> Значит в этом случае кадр стека все же формируется? S>Как это он сформируется для функции из ntdll? Я дизассемблером смотрел — нет там никакой установки ebp, почти сразу int 2E идет.
l>> Можно ли как нибудь заставить функцию кадр стека формироваться, обхитрить? S>Ну так я говорил уже — опция компилятора /Oy- после опций оптимизации, и все будет почти как надо.
S>Best regards, S> Sergey.
Понятно, спасибо.
На счет отключения оптимизации я , кажется, действительно перепутал.
Но я пробовал и с /Oy и без нее, результат почему-то одинаков. Не работает. Я даже создал новцй проект для чистоты эксперимента.
Бог с ней с ZwGetContextThread. Мне не понятно, почему в моих OnBnClickedButton1() b foo() кадр стека формируется, а в IntelStackWalk() — нет, ведь все же они в одном проекте с одинаковыми опциями компилчтора скомпилированы.
Hello, !
You wrote on Wed, 03 Dec 2003 09:04:47 GMT:
> Понятно, спасибо.
Что-то непохоже
> На счет отключения оптимизации я , кажется, действительно перепутал.
> Но я пробовал и с /Oy и без нее, результат почему-то одинаков.
Значит, FPO-оптимизация и так не используется.
> Не работает. Я даже создал новцй проект для чистоты эксперимента.
Что конкретно не работает? foo в трэйс не попадает? Так ведь и не должно.
> Бог с ней с ZwGetContextThread. Мне не понятно, почему в моих > OnBnClickedButton1() b foo() кадр стека формируется, а в IntelStackWalk() > — нет, ведь все же они в одном проекте с одинаковыми опциями компилчтора > скомпилированы.
Код покажи. И дизассемблированный (начало функции IntelStackWalk) в том числе, а то опять не поверю, потому что в функции IntelStackWalk, IMHO, достаточно локальных переменных для того, чтобы FPO-оптимизация была невыгодной.
Best regards,
Sergey.
Posted via RSDN NNTP Server 1.8 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.