• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 319, comments - 22, trackbacks - 0, articles - 11
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

            http://www.greenxf.com/soft/24170.html

            ExEinfo PE(可執(zhí)行程序檢查工具)V0.0.3.0 綠色版

            exeinfo pe 是一款免費的win32可執(zhí)行程序檢查器,它可以檢查程序的打包方式,exe保護等,可以幫助開發(fā)人員對程序進行破解

            posted @ 2012-02-01 20:24 RTY 閱讀(307) | 評論 (0)編輯 收藏

            http://www.greenxf.com/soft/25434.html

            將鼠標移動到您要探測的窗體或控件上,即可獲取該窗體的句柄、類名、文本(包括密碼文本)、窗口位置、窗口尺寸、程式路徑、編程語言等信息。

            posted @ 2012-02-01 20:22 RTY 閱讀(365) | 評論 (0)編輯 收藏

            http://www.greenxf.com/soft/27822.html

            文件數字簽名克隆工具[單文件版]V1.00 綠色版

            可復制其他文件數字簽名。

            posted @ 2012-02-01 20:18 RTY 閱讀(342) | 評論 (0)編輯 收藏

            Building PySide on Microsoft Windows

            Prerequisites

            NOTE: Be sure that git.exe and cmake.exe are all in your PATH.

            Build

            • Open “Visual Studio Command Prompt”: [Start Menu]->Programs->Microsoft Visual C++ 2008 Express Edition->Visual Studio Tools
            • Get build scripts from repository http://qt.gitorious.org/pyside/packaging and go to folder “c:\repositories\packaging\setuptools”. The script can automatically download the sources, compile them, and create the installer, all in one step.
            • Run the build.py script (it must be run from “Visual Studio Command Prompt”):
            To build the latest stable binaries for Python 2.7 and Qt 4.7.3, run the script with parameters:
            1.   c:\repositories\packaging\setuptools>c:\Python27\python.exe build.py --q c:\Qt\4.7.3\bin\qmake.exe
            2.  
            To build the latest development binaries:
            1.   c:\repositories\packaging\setuptools>c:\Python27\python.exe build.py --m dev -q c:\Qt\4.7.3\bin\qmake.exe
            2.  
            All build.py parameters:
            1.    -<package_version> Specify package version. Default is latest stable version (1.0.4)
            2.    -d                   Download latest sources from git repository
            3.    -<pyside_version>  Specify what version of modules to download from git repository:
            4.                          'dev' (master tag) or 'stable' (1.0.4 tag)Default is 'stable'.
            5.    -<qmake_path>      Locate qmake
            6.    -e                   Check the environment
            7.    -b                   Specify what module to build
            8.    -o                   Create a distribution package only using existing binaries
            9.    
            • After the successful build, the final binary distribution can be found in sub-folder “dist”:
              1.   c:\repositories\packaging\setuptools\dist\PySide-1.0.4qt473.win32-py2.7.exe
              2.  

            Categories:

            posted @ 2012-01-14 21:08 RTY 閱讀(453) | 評論 (0)編輯 收藏

            Ubuntu Mobile Phone Concepts

            By , Published December 4, 2011
            Share:

            Ubuntu’s plan for a multi-device presence, to potentially include smartphones, has fired up the imagination of users.

            And the community have been quick to stoke their creative talents in mocking up a variety of possible implementations.

            Below are three of those community designs that have landed in our inbox over the last week…

            Community Designs

            Nick Rutledge mailed in with a link to his initial designs which are more traditional in approach than some mobile mock-ups that have been bandied around.

            ubuntu mobile designs

            nrutledge.blogspot.com/p/ubuntu-mobile-project.html

            Sam Horne’s mock-ups are ‘Unity-esque’ in appearance, with a strong emphasis given to familiar Unity elements such as the launcher and a ‘Dash’ style search – both of which are played to great use on his home-screen design in particular.

            “I would like to share with you my own Ubuntu for mobile phones mock-up, just as a way of giving my two cents.” Sam told us when mailing in his designs.

            “I gave the design some real thought (even if it’s not a perfect mock-up) to truly show how I’d make the mobile OS. Getting the design right is a big deal in my head, so I used my own HTC Desire to look at  them every time I made a change, just to make sure it felt natural or doable on an actual smartphone.”

            ginjaninja405.deviantart.com/art/Ubuntu-with-mobile-Unity-268863703

            Serial designer Musl1m took to his DeviantArt with a well thought out, and very Faenza styled, design.

            I love the approach to app navigation, particularly in his ‘Ubuntu Software Centre’ design.

            musl1m.deviantart.com/art/Ubuntu-Phone-Explained-271229476

             

            posted @ 2011-12-06 19:47 RTY 閱讀(337) | 評論 (0)編輯 收藏

            DeVeDe 是一個用來創(chuàng)建可在家庭DVD播放器中放映的DVD視頻光盤,支持幾乎所有的視頻格式,采用 Python 開發(fā)。

            新版本增加對 ffmpeg 的支持,修復了菜單顯示的問題,支持任務完成后自動關機的功能。

            posted @ 2011-11-22 20:28 RTY 閱讀(233) | 評論 (0)編輯 收藏

            The reference to the wiki syntax for Google Code projects
            Restrict-AddWikiComment-Commit
            Updated Aug 17, 2011 by dbentley@google.com

            Wiki Syntax

            Introduction

            Each wiki page is stored in a .wiki file under the /wiki directory in a project's repository. Each file's name is the same as the wiki page name. And, each wiki file consists of optional pragma lines followed by the content of the page.

            Pragmas

            Optional pragma lines provide metadata about the page and how it should be displayed. These lines are only processed if they appear at the top of the file. Each pragma line begins with a pound-sign (#) and the pragma name, followed by a value.

            Pragma Value
            #summary One-line summary of the page
            #labels Comma-separated list of labels (filled in automatically via the web UI)
            #sidebar See Side navigation

            Wiki-style markup

            Paragraphs

            Use one or more blank lines to separate paragraphs.

            Typeface

            Name/Sample Markup
            italic _italic_
            bold *bold*
            code `code`
            code {{{code}}}
            superscript ^super^script
            subscript ,,sub,,script
            strikeout ~~strikeout~~

            You can mix these typefaces in some ways:

            Markup Result
            _*bold* in italics_ bold in italics
            *_italics_ in bold* italics in bold
            *~~strike~~ works too* strike works too
            ~~as well as _this_ way round~~ as well as this way round

            Code

            If you have a multiline code block that you want to display verbatim, use the multiline code delimiter:

            {{{
            def fib(n):
              if n == 0 or n == 1:
                return n
              else:
                # This recursion is not good for large numbers.
                return fib(n-1) + fib(n-2)
            }}}

            Which results in:

            def fib(n):
              if n == 0 or n == 1:
                return n
              else:
                # This recursion is not good for large numbers.
                return fib(n-1) + fib(n-2)

            For more control over the syntax higlighting, the <code> tag allows you to specify a file extension:

            <code language="xml">
            <hello target="world"/>
            </code>

            To disable highlighting entirely, use the <pre> tag.

            Headings

            = Heading =
            == Subheading ==
            === Level 3 ===
            ==== Level 4 ====
            ===== Level 5 =====
            ====== Level 6 ======

            Dividers

            Four or more dashes on a line by themselves results in a horizontal rule.

            Lists

            Google Code wikis support both bulleted and numbered lists. A list must be indented at least one space to be recognized as such. You can also nest lists one within the other by appropriate use of indenting:

            The following is:
              * A list
              * Of bulleted items
                # This is a numbered sublist
                # Which is done by indenting further
              * And back to the main bulleted list

             * This is also a list
             * With a single leading space
             * Notice that it is rendered
              # At the same levels
              # As the above lists.
             * Despite the different indentation levels.

            The following is:

            • A list
            • Of bulleted items
              1. This is a numbered sublist
              2. Which is done by indenting further
            • And back to the main bulleted list
            • This is also a list
            • With a single leading space
            • Notice that it is rendered
              1. At the same levels
              2. As the above lists.
            • Despite the different indentation levels.

            Quoting

            Block quotes place emphasis on a particular extract of text in your page. Block quotes are created by indenting a paragraph by at least one space:

            Someone once said:

              This sentence will be quoted in the future as the canonical example
              of a quote that is so important that it should be visually separate
              from the rest of the text in which it appears.

            Someone once said:

            This sentence will be quoted in the future as the canonical example of a quote that is so important that it should be visually separate from the rest of the text in which it appears.

            Links

            Links are central to the wiki principle, as they create the web of content. Google Code wiki permits both internal (within the wiki) and external links, and in some cases automatically creates a link when it recognizes either a WikiWord or an URL.

            Internal wiki links

            Internal links within a wiki are created using the syntax below. If you add a wiki link to a page that does not exist, the link will appear with a LittleLink? to project committers and owners. Clicking that link will take you to the page creation form where you can enter content for that page.

            If you are not logged in, wiki links that point to non-existent pages will appear as plain text, without the link to the page creation form. When you create the target page, the link will become a normal hyperlink for all viewers of the page.

            WikiSyntax is identified and linked automatically

            Wikipage is not identified, so if you have a page named [Wikipage] you
            need to link it explicitly.

            If the WikiSyntax page is actually about reindeers, you can provide a
            description, so that people know you are actually linking to a page on
            [WikiSyntax reindeer flotillas].

            If you want to mention !WikiSyntax without it being autolinked, use an
            exclamation mark to prevent linking.

            WikiSyntax is identified and linked automatically

            Wikipage is not identified, so if you have a page named Wikipage you need to link it explicitly.

            If the WikiSyntax page is actually about reindeers, you can provide a description, so that people know you are actually linking to a page on reindeer flotillas.

            If you want to mention WikiSyntax without it being autolinked, use an exclamation mark to prevent linking.

            Links to anchors within a page

            Each heading defines a HTML anchor with the same name as the heading, but with spaces replaced by underscores. You can create a link to a specific heading on a page like this:

            [WikiSyntax#Wiki-style_markup]

            And it will render as: WikiSyntax#Wiki-style_markup.

            Links to issues and revisions

            You can easily link to issues and revisions using the following syntax.

            • issue 123 will be autolinked to issue number 123 in the current project. You can include a # or not. If the issue has been closed, the link will appear as a cross-out rather than an underline. Hovering your mouse over such a link shows the issue summary.
            • issue PROJECTNAME:122 will be autolinked to that issue number in the specified project. This is useful when your project depends on work being done in related projects.
            • r123 will be autolinked to the revision detail page for that revision in the current project.

            There is currently no way to disable this type of autolinking. See issue 996.

            For example: Please add a comment on issue 123 rather than adding more review comments to r456. 

            Renders as: Please add a comment on  issue 123  rather than adding more review comments to r456.

            Links to external pages

            You can of course link to external pages from your own wiki pages, using a syntax similar to that for internal links:

            Plain URLs such as http://www.google.com/ or ftp://ftp.kernel.org/ are
            automatically made into links.

            You can also provide some descriptive text. For example, the following
            link points to the [http://www.google.com Google home page].

            If your link points to an image, it will get inserted as an image tag
            into the page:

            http://code.google.com/images/code_sm.png

            You can also make the image into a link, by setting the image URL as
            the description of the URL you want to link:

            [http://code.google.com/ http://code.google.com/images/code_sm.png]

            Plain URLs such as http://www.google.com/ or ftp://ftp.kernel.org/ are automatically made into links.

            You can also provide some descriptive text. For example, the following link points to the Google home page.

            You can also make the image into a link, by setting the image URL as the description of the URL you want to link:

            [http://code.google.com/ http://code.google.com/images/code_sm.png]

            Links to images

            If your link points to an image (that is, if it ends in .png, .gif, .jpg or .jpeg), it will get inserted as an image into the page:

            http://code.google.com/images/code_sm.png

            If the image is produced by a server-side script, you may need to add a nonsense query string parameter to the end so that the URL ends with a supported image filename extension.

            http://chart.apis.google.com/chart?chs=200x125&chd=t:48.14,33.79,19.77|83.18,18.73,12.04&cht=bvg&nonsense=something_that_ends_with.png

            Tables

            Tables are created by entering the content of each cell separated by || delimiters. You can insert other inline wiki syntax in table cells, including typeface formatting and links.

            || *Year* || *Temperature (low)* || *Temperature (high)* ||
            || 1900 || -10 || 25 ||
            || 1910 || -15 || 30 ||
            || 1920 || -10 || 32 ||
            || 1930 || _N/A_ || _N/A_ ||
            || 1940 || -2 || 40 ||
            Year Temperature (low) Temperature (high)
            1900 -10 25
            1910 -15 30
            1920 -10 32
            1930 N/A N/A
            1940 -2 40

            HTML support

            To aid in the presentation of a wiki page there is some support for HTML. HTML tags are only supported in wiki pages, not in page comments.

            HTML syntax can be used in conjunction with wiki syntax, but it is recommended against doing so where possible.

            The following HTML tags and attributes are currently supported:

            HTML TagSupported Attributes
            atitle dir lang href
            btitle dir lang
            brtitle dir lang
            blockquotetitle dir lang
            codetitle dir lang language [1]
            ddtitle dir lang
            divtitle dir lang
            dltitle dir lang
            dttitle dir lang
            emtitle dir lang
            fonttitle dir lang face size color
            h1title dir lang
            h2title dir lang
            h3title dir lang
            h4title dir lang
            h5title dir lang
            ititle dir lang
            imgtitle dir lang src alt border height width align
            lititle dir lang
            oltitle dir lang type start
            ptitle dir lang align
            pretitle dir lang
            qtitle dir lang
            stitle dir lang
            spantitle dir lang
            striketitle dir lang
            strongtitle dir lang
            subtitle dir lang
            suptitle dir lang
            tabletitle dir lang align valign cellspacing cellpadding border width height
            tbodytitle dir lang align valign cellspacing cellpadding border width height
            tdtitle dir lang align valign cellspacing cellpadding border width height
            tfoottitle dir lang align valign cellspacing cellpadding border width height
            thtitle dir lang align valign cellspacing cellpadding border width height
            theadtitle dir lang align valign cellspacing cellpadding border width height colspan rowspan
            trtitle dir lang align valign cellspacing cellpadding border width height colspan rowspan
            tttitle dir lang
            utitle dir lang
            ultitle dir lang type
            vartitle dir lang

            [1] The language attribute of the code tag is the file extension of the language used in the code block. It is used as a hint for the syntax highlighter.

            Escaping HTML Tags

            When you want to display html tags directly on your wiki page (as opposed to rendered), you will need to escape each HTML tag.

            HTML tags can be escaped as shown in the table below:

            MarkupResult
            `<hr>`<hr>
            {{{<hr>}}}<hr>



            Comments

            The wiki supports embedded comments to help explain the contents of a wiki page. Anything inside the comment block is removed from the rendered page, but is visible when editing or viewing the source for that page.

            <wiki:comment>
            This text will be removed from the rendered page.
            </wiki:comment>

            +1 Button

            Use <g:plusone></g:plusone> to add a +1 button to the page. Example:

            <g:plusone size="medium"></g:plusone>

            The count, size, and href parameters are supported; see http://code.google.com/apis/+1button/ for documentation.

            Gadgets

            You can embed Gadgets on your wiki pages with the following syntax:

            <wiki:gadget url="http://example.com/gadget.xml" height="200" border="0" /> 

            Valid attributes are:

            • url: the URL of the gadget
            • width: the width of the gadget
            • height: the height of the gadget
            • title: a title to display above the gadget
            • border: "0" or "1", whether to draw a border around the gadget
            • up_*: Gadget user preference parameters
            • caja: "0" or "1", whether to use Caja to render the gadget. Caja helps protect users from malicious or accidental errors in third party gadgets.

            WorkingWithGoogleGadgets describes how to create gadgets for Google Code. It also provides a few helpful suggestions that can make it easier to publish gadgets and to integrate with other Google products such as iGoogle.

            InterestingDeveloperGadgets shows some sample gadgets you may want to include on your project pages.

            Videos

            You can embed videos with the following syntax:

            <wiki:video url="http://www.youtube.com/watch?v=3LkNlTNHZzE"/>

            Valid attributes are:

            • url: the URL of the video
            • width: the width of the embedded video
            • height: the height of the embedded video

            Right now we support videos from Youtube and Google Video, but other containers can be added to our open source gadgets project.

            Navigation

            Table of Contents

            An inline table of contents can be generated from page headers on a wiki page. Add the following syntax to a page in the location the table of contents should be displayed:

            <wiki:toc max_depth="1" />

            Valid attributes are:

            • max_depth: the maximum header depth to display in the table of contents

            Side navigation

            You can specify the sidebar for a wiki page by selecting another wiki page that defines your side navigation. The doctype project uses the sidebar extensively across its wiki.

            One way of adding a sidebar is by setting the #sidebar pragma, as shown below. Alternatively, the sidebar pragma can be left blank if no side navigation is desired.

            #sidebar TableOfContents

            The side navigation that is defined should be in the format of a simple list, as shown below.

             * [Articles HOWTO articles]
                * [ArticlesXSS Web security]
                * [ArticlesDom DOM manipulation]
                * [ArticlesStyle CSS and style]
                * [ArticlesTips Tips and tricks]
              * [DOMReference DOM reference]
              * [HTMLElements HTML reference]
              * [CSSReference CSS reference]

            A default sidebar page can also be specified for all wiki pages by project owners through the Wiki settings in the Administer tab. If a #sidebar pragma is also specified, it will take precedence on the page.

            Localizing Wiki Content

            Along with the default language for the wiki, which can be set through the Wiki settings in the Administer tab, additional languages are also supported. If more than one language is available, based on a user's language preference (e.g. browser language), the wiki will try to serve the page for the appropriate language. If no wiki page exists for that language, it will fall back to the default language. Comments, however, are shared amongst all translations of a wiki page.

            New translations for a page cannot be added through the web interface and have to be added through the Subversion repository.

            To add a translation of a page, first checkout the wiki from Subversion:

            svn checkout https://yourproject.googlecode.com/svn/wiki/ yourdirectory -username yourusername

            Then create a new directory under /wiki/ using the two letter ISO-639 code as the name of that directory. Place all translated files in the new directory and submit those changes to the Subversion repository.

            The following is an example of a valid wiki directory:

            wiki/
               ja/
                  ProjectHistory.wiki
                  StyleGuide.wiki
               zh-Hans/
                  ProjectHistory.wiki
                  StyleGuide.wiki
               zh-Hant/
                  ProjectHistory.wiki
                  StyleGuide.wiki
               ProjectHistory.wiki
               StyleGuide.wiki

            Once the files been be submitted to the project's subversion repository, they can now be edited through the wiki's web editor. The process is the same for Mercurial or Git projects, except that the wiki lives in the root directory (not wiki/) of https://wiki.yourproject.googlecode.com/hg/ or https://wiki.yourproject.googlecode.com/git/.

            Note: The wiki accepts a subset of ISO-639 two letter language codes, where a few of the codes (such as zh_Hans) contain locale-specific codes. Such locale-specific codes should use a hyphen (zh-Hans) separator. A few example language codes have been specified in the table below.

            Language (Locale) Directory Name
            Arabic ar
            Bulgarian bg
            Chinese (China) zh-Hans
            Chinese (Taiwan) zh-Hant
            Croatian hr
            Czech cs
            Danish da
            Dutch nl
            English (United Kingdom) en-GB
            English (United States) en-US
            Finnish fi
            French fr
            German de
            Greek el
            Hebrew he
            Hungarian hu
            Italian it
            Japanese ja
            Korean ko
            Norwegian no
            Polish pl
            Portuguese (Brazil) pt-BR
            Romanian ro
            Russian ru
            Slovak sk
            Spanish es
            Swedish sv
            Turkish tr

            The content on this page created by Google is licensed under the Creative Commons Attribution 3.0 License. User-generated content is not included in this license.

            posted @ 2011-11-09 06:52 RTY 閱讀(536) | 評論 (0)編輯 收藏

            Google Breakpad 完全解析(二) —— Windows前臺實現篇

            2011年02月7日 — Asp J

            Table of contents for Google Breakpad 完全解析

            1. Google Breakpad 完全解析(一) —— Windows入門篇
            2. Google Breakpad 完全解析(二) —— Windows前臺實現篇

            原創(chuàng)文章,轉載請標明出處:Soul Apogee (http://bigasp.com),謝謝。

            好,看完了如何使用breakpad,我們現在看看breakpad在Windows下到底是如何實現的呢?

            代碼結構

            在我們來看breakpad是如何實現其強大的功能之前,我們先來看一下他的代碼結構吧。

            Google breakpad的源代碼都在src的目錄下,他分為如下幾個文件夾:
            client:這下面包含了前臺應用程序中捕捉dump的部分代碼,里面按照平臺分成各個子文件夾
            common:前臺后臺都會用到的部分基礎代碼,字符串轉換,內存讀寫,md5神馬的
            google_breakpad:breakpad中公共的頭文件
            processor:用于在后臺處理崩潰的核心代碼
            testing:測試工程
            third_party:第三方庫
            tools:一些小工具,用于處理dump文件和符號表

            我們先來看Windows下前臺實現的部分,也就是client文件夾下的代碼。

            breakpad的崩潰捕獲機制

            在Windows下捕獲崩潰,大家很容易會想到那個捕獲結構化異常的Api:SetUnhandledExceptionFilter

            breakpad中也使用了這個Api來實現的崩潰捕獲,另外,breakpad還捕獲了另外兩種C++運行庫提供的崩潰,一種是使用_set_purecall_handler捕獲純虛函數調用產生的崩潰,還有一種是使用_set_invalid_parameter_handler捕獲錯誤的參數調用產生的崩潰。

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
                if (handler_types & HANDLER_EXCEPTION)
                  previous_filter_ = SetUnhandledExceptionFilter(HandleException);
             
            #if _MSC_VER >= 1400  // MSVC 2005/8
                if (handler_types & HANDLER_INVALID_PARAMETER)
                  previous_iph_ = _set_invalid_parameter_handler(HandleInvalidParameter);
            #endif  // _MSC_VER >= 1400
             
                if (handler_types & HANDLER_PURECALL)
                  previous_pch_ = _set_purecall_handler(HandlePureVirtualCall);

            另外由于C++運行庫提供的崩潰回調中,并不會提供當前的線程現場和崩潰信息,所以breakpad會自己生成好這些信息,然后請求生成dump。
            這里值得一說的是,在非異常崩潰處理中,breakpad獲取線程現場使用的函數是RtlCaptureContext而不是GetThreadContext。
            RtlCaptureContext只能捕獲當前線程的現場,而GetThreadContext可以捕獲任意線程的現場,只要有這個線程的句柄即可。
            但是GetThreadContext有兩個不好的地方:不能獲取當前線程的現場;獲取現場前必須先用SuspendThread暫停目標線程。
            而RtlCaptureContext雖然只能獲取當前線程的現場,但是調用他時可以不用暫停線程的運行。
            對于breakpad來說,崩潰發(fā)生后越早獲取現場就越好,所以breakpad使用RtlCaptureContext函數作為他的線程獲取函數。

            breakpad中的C/S結構

            由于breakpad是在進程外抓取dump,所以breakpad需要實現一個C/S結構來處理崩潰進程抓取dump的請求。

            1. breakpad跨進程通信的實現
            breakpad中使用了命名管道來實現IPC。

            在客戶端,初始化ExceptionHandler的時候,如果指定了PipeName,也就表示此時需要使用進程外的dump抓 取,ExceptionHandler,會建立一個 CrashGenerationClient的對象,由這個對象連接服務端,將自己注冊到服務端上 去。
            大家可以參看exception_handler.cc中的ExceptionHandler::Initialize函數。

            在服務端,初始化CrashGenerationServer的時候,就會建立一個命名管道,并等待客戶端來連接。一旦有客戶端連接上來,服務端會 為每一個客戶端生成一個ClientInfo的對象,之后用這個對象來管理所有的客戶端,一旦有崩潰發(fā)生,服務端都會從這個對象中取出dump所需要的信 息。
            大家可以參看crash_generation_server.cc中的CrashGenerationServer::HandleReadDoneState函數。

            2. breakpad捕獲崩潰生成dump的流程
            breakpad進程外生成dump的流程大概如下:
            google-breakpad-out-of-process-dump:
            google-breakpad-out-of-process-dump
            這段流程的代碼就是crash_generation_client.cc和crash_generation_server.cc。

            有兩個簡單的問題,這里說明一下,高手們就請直接忽略吧,咩哈哈:
            在服務端如何為客戶端生成事件句柄?
            使用DuplicateHandle,即可把任意一個內核對象的句柄復制到其他進程,并且可以指定產生的句柄的權限。

            如何異步的等待一個事件?
            使用RegisterWaitForSingleObject,即可異步的等待一個事件,當事件發(fā)生的時候,就可以回調到一個指定的回 調函數中,但是要注意的是,RegisterWaitForSingleObject會在一個新的線程中來等待這個事件,此處很容易產生多線程的調用,需 要注意線程問題。

            3. 服務端關鍵數據結構:ClientInfo
            ClientInfo是服務端中最重要的數據結構,服務端通過它來管理所有的客戶端。客戶端注冊時,會保存或生成里面所有的信息,在客戶端請求生成dump的時候,服務端就會通過ClientInfo獲取所有客戶端的信息。ClientInfo中保存了如下信息:

            • 客戶端進程pid和句柄
            • 生成Minidump的類型
            • 自定義的客戶端信息
            • 客戶端崩潰的線程ID
            • 客戶端崩潰的信息
            • 客戶端請求崩潰所使用的事件句柄

            這里有一個問題:在客戶端發(fā)生崩潰時,服務器如何通過ClientInfo獲取到客戶端的崩潰信息呢?

            客戶端中有幾個用于保存崩潰信息的變量,在注冊時,客戶端會將這幾個變量的地址發(fā)送至服務端,服務端將其保存在ClientInfo中,然后當崩潰 發(fā)生的時候,服務端就可以通過ReadProcessMemory讀取客戶端中的信息,從而生成dump。這樣做就避免了每次發(fā)生崩潰,都要通過Pipe 將崩潰信息傳遞到服務端中去了。

            這些變量分別是:崩潰的線程ID,EXCEPTION_POINTERS和MDRawAssertionInfo。
            EXCEPTION_POINTERS和MDRawAssertionInfo的區(qū)別在于,異常崩潰的信息會被寫入EXCEPTION_POINTERS,非異常崩潰(非法參數和純虛函數調用)的信息會被寫入MDRawAssertionInfo中。

            dump文件的上傳

            在breakpad的工程中,有一個工程叫做:crash_report_sender,里面是一個上傳崩潰文件的類,他的實現很簡單,他使用Windows Internet Api來完成dump文件的上傳。
            在使用crash_report_sender時,可以為其指定一個checkpoint_file。

            1
            explicit CrashReportSender(const wstring &checkpoint_file);

            這個文件只有一個作用,就是用來保存上次上傳崩潰的時間和今天上傳過的崩潰的次數。通過這個文件,我們就可以來設置每日上傳的崩潰的最大數量。

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            CrashReportSender::CrashReportSender(const wstring &checkpoint_file)
                : checkpoint_file_(checkpoint_file),
                  max_reports_per_day_(-1),
                  last_sent_date_(-1),
                  reports_sent_(0) {
              FILE *fd;
              if (OpenCheckpointFile(L"r", &fd) == 0) {
                ReadCheckpoint(fd);
                fclose(fd);
              }
            }
             
            ReportResult CrashReportSender::SendCrashReport(
                const wstring &url, const map<wstring, wstring> &parameters,
                const wstring &dump_file_name, wstring *report_code) {
              int today = GetCurrentDate();
              if (today == last_sent_date_ &&
                  max_reports_per_day_ != -1 &&
                  reports_sent_ >= max_reports_per_day_) {
                return RESULT_THROTTLED;
              }
             
              // 上傳文件部分代碼,省略
            }

            調整每日上傳崩潰的最大數量的函數是set_max_reports_per_day。

            需要注意的是:在上傳dump文件的時候,crash_report_sender并不會對dump文件進行分析,而是直接上傳整個dump文件, 如果你需要上傳的dump文件非常大的話,可以考慮把崩潰分析處理的邏輯放入前臺,通過去重或者直接上傳分析結果,減少上傳的文件大小。

            breakpad存在的問題

            進程外生成dump有很多好處,其中最大的好處就是不會被崩潰進程影響,這樣dump的過程就不容易出錯,但是這樣也有一定的弊端。

            1. 部分崩潰無法抓取
            在一些極端的崩潰,如堆棧溢出之類的崩潰,進程外抓取dump有時候會失敗。

            2. 無法抓取死鎖或者其他原因導致的進程僵死
            breakpad現在沒有檢測進程死鎖的代碼,也沒有在服務端控制客戶端請求dump的代碼,所以現在breakpad無法抓取死鎖等進程僵死的問題。不過因為breakpad的定位是處理崩潰,如果有這種需要的童鞋,可以自行修改breakpad的代碼,添加這些功能。

            3. 對服務端有依賴
            如果指定了在使用進程外抓取dump,breakpad對服務端就有依賴。主要體現在抓取dump時,如果服務端不存在,客戶端將無法正常抓取dump,甚至有時會出現阻塞。

            當然對于這些問題,隨著breakpad的發(fā)展肯定會越來越完善。如果,你遇到了了這些問題,而又繞過不了,那就改代碼,并且提交給breakpad吧,開源項目就是這么發(fā)展的。

            好,到此breakpad的Windows實現就已經說完了,如果有神馬問題,還請多多指教。謝謝大家。

            北京德勝門中醫(yī)院http://www.0531jsk.com/德勝門中醫(yī)院

            posted @ 2011-11-07 21:36 RTY 閱讀(2398) | 評論 (0)編輯 收藏

            Google Breakpad 完全解析(一) —— Windows入門篇

            2011年01月23日 — Asp J

            Table of contents for Google Breakpad 完全解析

            1. Google Breakpad 完全解析(一) —— Windows入門篇
            2. Google Breakpad 完全解析(二) —— Windows前臺實現篇

            原創(chuàng)文章,轉載請標明出處:Soul Apogee (http://bigasp.com),謝謝。

            Google breakpad是 一個非常實用的跨平臺的崩潰轉儲和分析模塊,他支持Windows,Linux和Mac和Solaris。由于他本身跨平臺,所以很大的減少我們在平臺移 植時的工作,畢竟崩潰轉儲,每個平臺下都不同,使用起來很難統一,而Google breakpad就幫我們做到了這一點,不管是哪個平臺下的崩潰,都能夠進行統一的分析。現在很多工程都在使用他:最著名的幾個如 Chrome,Firefox,Picasa和Google Earth。另外他的License是BSD的,也就是說,我們即便是在商業(yè)軟件中使用,也是合法的,哈哈,這么好的東西,我們能放過么?現在就讓我們來 看看這個神奇的軟件吧。

            原理簡介

            breakpad抓取dump的方式和一般我們抓取dump的方式不一樣。在breakpad的wiki上有一幅圖可以很好的概括他的原理。

            breakpad把應用程序分成三個部分,代碼,breakpad客戶端和調試信息。

            1. 在build system中,通過symbol dumper用平臺相關的調試信息生成平臺無關的symbol文件。這樣做的好處很明顯,一旦平臺無關了,所有平臺的崩潰就可以做統一的分析了。
            2. breakpad采取進程外轉儲和分析崩潰的方式,他使用C/S結構,客戶端用來捕獲當前進程中發(fā)生的崩潰,并通知服務端崩潰發(fā)生。服務端用來響應客戶端,抓取dump文件。這樣做的目的是為了減少崩潰進程對dump的影響。
            3. Dump生成后轉發(fā)到崩潰分析器中,這個部分可以在本地也可以在服務器上,他對Dump文件進行解析,生成可讀的堆棧信息。

            這就是breakpad處理dump大概的流程。

            對于原理的介紹google寫的已經相當好了。更多的詳細信息,可以直接移步到breakpad的wiki

            安裝和編譯

            breakpad的編譯比較曲折,所以在此記錄一下。

            編譯breakpad,請確認你的機器上裝有以下的軟件:
            1. python 2.4.3
            請不要使用python3,會報錯。另外python2中推薦這個版本,使用新的版本在編譯其他google的工程時有時會報錯

            2. Windows SDK 7
            如果沒有這個,編譯會報錯。另外這個是在線安裝,時間很久,最好并行做其他的事情。

            3. VS2005的補丁
            KB918559
            KB926601
            KB935225
            KB943969
            KB947315

            已經安裝了以上軟件的童鞋,就可以開始進行下面的工作鳥

            1. 使用svn把代碼checkout下來

            1
            2
            # Non-members may check out a read-only working copy anonymously over HTTP.
            svn checkout http://google-breakpad.googlecode.com/svn/trunk/ google-breakpad-read-only

            2. 設置Windows SDK 7
            裝過其他版本Windows SDK的童鞋,記得一定要進行這一步,SDK的安裝程序,并不會幫你設置VS。
            運行開始菜單->程序->Microsoft Windows SDK v7.0->Visual Studio Registration->Windows SDK Configuration Tool,選擇v7.0,點擊Make Current。

            3. 為python設置環(huán)境變量
            由于breakpad使用python來生成Windows下的工程文件,所以需要將python所在目錄,設置到環(huán)境變量PATH中去。

            4. 生成Windows工程文件

            1
            2
            3
            4
            cd "源碼目錄/src/tools/gyp"
             
            # 注意,此處不能使用全路徑,不然會出錯
            gyp.bat "../../client/windows/breakpad_client.gyp"

            此時,在src/client/windows下就可以看到生成好的breakpad_client.sln了。運行吧!

            5. Hello World!
            編譯build all,現在一般是不會報錯了,如果報錯,請檢查是不是漏了什么步驟,特別是補丁。
            編譯完成之后,運行crash_generation_app吧,這是他的測試程序,dump的默認位置保存在C:Dumps下,請注意先建立好目錄,不然會無法使用。
            啟動測試程序之后,此時還不能抓取dump,因為這個是breakpad中的服務器端,需要再啟動一個測試程序,在第二個測試程序中,我們就可以試驗Client菜單中的各種崩潰了。這些崩潰都會被抓住轉存到C:Dumps目錄下。

            如何使用breakpad

            在Windows下使用breakpad的方法很簡單,只需要創(chuàng)建一個ExceptionHandler的類即可,大家可以在crash_generation_app這個工程中找到示例代碼,也可以直接移步Wiki,上面說的也很詳細。

            1.進程內抓取Dump文件

            進程內抓取Dump文件是最簡單的breakpad的用法。使用方法很簡單:

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            const std::wstring s_strCrashDir = L"c:\dumps";
             
            bool
            InitBreakpad()
            {
                google_breakpad::ExceptionHandler *pCrashHandler =
                    new google_breakpad::ExceptionHandler(s_strCrashDir,
                    onExceptionFilter,
                    onMinidumpDumped,
                    NULL,
                    google_breakpad::ExceptionHandler::HANDLER_ALL,
                    MiniDumpNormal,
                    NULL,
                    NULL);
             
                if(pCrashHandler == NULL) {
                    return false;
                }
             
                return true;
            }

            2.進程外抓取Dump文件

            使用進程外抓取Dump時,需要指定服務端和客戶端,在服務端中需要創(chuàng)建CrashGenerationServer的實例,而在客戶端中則只需要創(chuàng)建ExceptionHandler即可。此外,如果服務端自己需要抓進程內的Dump,請將pipe的參數置為NULL。

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            25
            26
            27
            28
            29
            30
            31
            32
            33
            34
            35
            36
            37
            38
            39
            40
            41
            42
            43
            44
            const wchar_t s_pPipeName[] = L"\\.\pipe\breakpad\crash_handler_server";
            const std::wstring s_strCrashDir = L"c:\dumps";
             
            bool
            InitBreakpad()
            {
                google_breakpad::CrashGenerationServer *pCrashServer =
                    new google_breakpad::CrashGenerationServer(s_pPipeName,
                    NULL,
                    onClientConnected,
                    NULL,
                    onClientDumpRequest,
                    NULL,
                    onClientExited,
                    NULL,
                    true,
                    &s_strCrashDir);
             
                if(pCrashServer == NULL) {
                    return false;
                }
             
                // 如果已經服務端已經啟動了,此處啟動會失敗
                if(!pCrashServer->Start()) {
                    delete pCrashServer;
                    pCrashServer = NULL;
                }
             
                google_breakpad::ExceptionHandler *pCrashHandler =
                    new google_breakpad::ExceptionHandler(s_strCrashDir,
                    onExceptionFilter,
                    onMinidumpDumped,
                    NULL,
                    google_breakpad::ExceptionHandler::HANDLER_ALL,
                    MiniDumpNormal,
                    (pCrashServer == NULL) ? s_pPipeName : NULL, // 如果是服務端,則直接使用進程內dump
                    NULL);
             
                if(pCrashHandler == NULL) {
                    return false;
                }
             
                return true;
            }

            使用breakpad的時候,有兩個地方需要注意:
            1. 記得把breakpad的solution下的幾個工程,包含到你開發(fā)的工程中,或者直接包含他們的lib。
            common:基礎功能,包含一個對GUID的封裝和http上傳的類。
            exception_handler:用來捕獲崩潰的類。
            crash_generation_server:breakpad的服務端,用來在產生崩潰時抓取dump。
            crash_generation_client:breakpad的客戶端,用來捕獲當前進程的崩潰。

            2. 在初始化breakpad之前,記得先創(chuàng)建好dump文件的目錄,不然breakpad服務端將不能正常的寫dump,這會導致breakpad客戶端在崩潰時無限等待服務端dump寫完的消息,最后失去響應。

            posted @ 2011-11-07 21:34 RTY 閱讀(1795) | 評論 (0)編輯 收藏

            調試Release發(fā)布版程序的Crash錯誤 (轉)

            調試Release發(fā)布版程序的Crash錯誤

            http://blog.sina.com.cn/s/blog_48f93b530100fsln.html

             

            Windows平臺下用C++開發(fā)應用程序,最不想見到的情況恐怕就是程序崩潰,而要想解決引起問題的bug,最困難的應該就是調試release版本了。因為release版本來就少了很多調試信息,更何況一般都是發(fā)布出去由用戶使用,crash的現場很難保留和重現。本文將給出幾個解決方案,完成對release版應用程序crash錯誤的調試。(本文只討論Windows平臺MSVC環(huán)境下的調試,對于其他平臺和開發(fā)環(huán)境沒有關注,請大家自己借鑒和嘗試。)

             

                方案一:崩潰地址 + MAP文件

                這種方案只能對VC7以前的版本開發(fā)的程序使用。 

                1、崩潰地址

                 所謂崩潰地址就是引起程序崩潰的內存地址,在WinXP下應用程序crash的對話框如下圖:

            clip_image001

            clip_image002

            clip_image003

                上面第2張圖中畫紅線的值為crash的代碼偏移地址,第3張圖為即crash絕對地址;一般引起crash的原因多為內存操作錯誤,我們用這兩個地址和MAP文件就能定位出錯的代碼行。

                2MAP文件

                MAP文件是記錄應用程序信息的文件(文本文件),里面大概包含了程序的全局符號、源碼模塊名、源碼文件和行號等信息,而這些信息能夠幫助我們定位出錯的代碼行。

                怎樣生成MAP文件呢?以VC6為例,在 Project Settings -> C/C++ -> Debug info中,選擇 Line Numbers Only ;在 Project Settings -> Link 中,選擇 Generate mapfile項,并在Project Options 里面輸入 /MAPINFO:LINES/MAPINFO:EXPORTS,重新編譯程序就會生成.map文件。

                以上設置對應的編譯鏈接選項分別分:

                /Zi — 表示生成pdb調試信息;

                /MAP[:filename] — 表示生成map文件名;

                /MAPINFO:EXPORTS — 表示生成的map文件中加入exported functions(生成DLL文件時);

                /MAPINFO:LINES — 表示生成的map文件中加入代碼行信息。

                由于/MAPINFO:LINES選項在VC8以后的版本中不再支持,因此通過MAP文件中的信息和crash地址定位出錯代碼行就比較困難了,所以這種方案只能在VC7及以前的版本中使用。

                一個MAP文件片段示例如下: 

                clip_image004  

                clip_image005

                圖中Rva+Base列的地址為該行函數對應的函數絕對地址,Address列中冒號后面的地址為函數相對偏移地址。   

                3、定位crash代碼

                有了上面的介紹,定位crash代碼就很簡單了。用下面的公式來進行定位:

                崩潰行偏移 = 崩潰地址 - 崩潰函數絕對地址 + 函數相對偏移

                我們首先根據崩潰地址(絕對地址),按照找到第2張圖中Rva+Base列的地址找到發(fā)生崩潰的函數(即崩潰地址大于該函數行的Rva+Base地址且小于下個函數的地址),然后找到該行對應的函數相對偏移地址,帶入公式中,就得到了崩潰行偏移,該值表示崩潰行的代碼相對于代碼所在函數的偏移量。用該值去與第3張圖中對應函數冒號后面的偏移量去比較,最接近的值前面的那個十進制數即為代碼所在函數中的行號。

                ok,到此我們已經成功找到了崩潰的代碼行,只不過這種方法還是比較費力,并且限制比較多,我們看看下面的方案。

            上篇給出的方案一還要補充幾句。通過“crash地址 + MAP文件”來定位出錯代碼位置雖然需要經過比較復雜的地址計算,但卻是最簡單實現的方式。如果僅僅想通過崩潰地址定位出錯的函數,就更加方便了。我在網上找到一個解析MAP文件的小工具,可以非常清晰的列出每個函數的地址,并且可以將分析表格導出為Excel文件。工具下載地址:http://e.ys168.com/?tinyfun,工具目錄下VCMapper.exe。

                另外上篇主要參考兩篇文章:

                http://www.vckbase.com/document/viewdoc/?id=908

                http://www.vckbase.com/document/viewdoc/?id=1473

             

                方案二:崩潰地址 + MAP文件 + COD文件

                由于VC8以后的版本都不再支持MAP文件中產生代碼行信息,因此我們尋找另一種定位方式:COD文件。

                1COD文件

                COD文件是一個包含了匯編碼、二進制機器碼和源代碼對應信息的文件,每一個cpp都對應一個COD文件。通過這個文件,我們可以非常方便地進行定位。

               VC6中生成COD文件的設置方式為:Project Settings -> C/C++,在 Category 中選 Listing Files,在 Listing file type 組合框中選 Assembly,Machine code,and source。在VC8中生成COD文件的設置方式為:Project Properties -> C/C++ -> Output Files -> Assembler Output 項,選擇 Assembly,Machine code,and Source(/Facs)。

               

                2、定位崩潰行

                下面通過舉例進行說明。現在我有一個基于對話框的MFC應用程序CrashTest,在CCrashTestDlg::OnInitDialog函數中寫入導致crash的代碼語句(第99行),源文件如下:

                clip_image006

                根據崩潰地址(0x004012A3)以及MAP文件(定位片段圖片如下),定位crash函數為OnInitDialog;并且我們可以很容易地計算出崩潰地址相對于崩潰函數的偏移量為 0x004012A3 - 0x004011E0 = 0xC3。

                clip_image007

                再來看看CrashTestDlg.cod文件,我們根據文件中源碼信息找到OnInitDialog函數信息片段:

                clip_image008

                可以看到圖片中第一行為OnInitDialog函數匯編代碼的起始行;找到“int * p = NULL;”這一句源碼,其前面的98表示這行代碼在源文件中的行號,下面的000c1表示相對于函數開始位置的偏移量,后面的“33 c0”為機器碼,“xor eax,eax”為匯編碼。那么我們根據前面算出來的偏移量0xC3,找到對應出錯的語句為99行:“*p = 5;”。

                總結一下定位步驟:

                1) 根據公式 崩潰語句在函數中偏移地址 = 崩潰地址 - 崩潰函數地址 計算出偏移量X;

                2) 根據公式 崩潰語句在COD文件中地址 = 崩潰函數在COD文件中地址 + X 計算出地址Y。其中崩潰函數在COD文件中地址為COD文件中函數起始括號“{”后面表明的地址,一般情況下為0x0000;

                3) 根據Y在COD文件中找到對應代碼行。

               

                ok,方案二介紹完了。這種方法最大的好處是沒有VC開發(fā)環(huán)境版本限制,而且COD文件里面包含的信息更加豐富,不但可以幫助我們定位crash,還能幫我們分析很多東西。當然,這也導致編譯生成了很多信息文件。

            根據前面兩篇博文,我們要定位崩潰行代碼,必須要自己根據相關信息文件進行計算。如果需要處理的量比較大,恐怕會很費力氣。有沒有更簡單快速的辦法呢?

                最直接的想法就是寫一個小工具,根據規(guī)則和信息進行自動定位,不過開發(fā)起來也是要費一番功夫的。令人開心的是,我們可以找到類似的工具,而且是開源免費的!程序員的世界也許很多時候都是這么單純而樂于分享!

               

                方案三:崩潰地址 + PDB文件 + CrashFinder

                CrashFinder是一個開源工具,作者是John Robbin,大家可以去他的blog上去找關于CrashFinder的信息。我們這里以CrashFinder2.5版本為例介紹,相關文章鏈接為:http://www.wintellect.com/CS/blogs/jrobbins/archive/2006/04/19/crashfinder-returns.aspx

                1PDB文件

                PDB(Program Database)文件中包含了exe程序所有的調試相關信息,具體可以查閱MSDN。當編譯選項設置為/Zi,鏈接選項設置為/DEBUG,/OPT:REF時,就會生成工程的.pdb文件。具體到VC2005中,就是 Project Propertise -> C/C++ -> General -> Debug Information Format 項設置為 Program Database(/Zi),Linker -> Debugging -> Generate Debug Info 項設置為 Yes(/Debug),Linker -> Optimization -> References 項設置為 Eliminate Unreferenced Data(/OPT:REF)。

                只要設置以上選項,release版本也能生成PDB文件。當然,對應的應用程序也會稍大。

                2CrashFinder

                CrashFinder能夠運行需要兩個條件:一是系統必須要有dbghelp.dll文件;二是PDB文件必須與exe文件在一個路徑下。對于dbghelp.dll,一般在系統system32路徑下都有,如果沒有下載一個放到這個目錄下就可以了。

                先看一下CrashFinder的界面。

               

            clip_image009

                用起來也非常簡單。首先選擇File->New或點擊工具欄新建按鈕,選擇要調試的exe文件打開,會發(fā)現exe及所依賴的dll文件信息都已經加載進來。在下半部分的編輯框中輸入崩潰地址(16進制),點右邊的“Find”按鈕,就會在下面顯示崩潰的源文件路徑、名稱以及崩潰所在行號了,如下圖所示。

            clip_image010

               CrashFinder進行crash定位真的非常方便。但是我在使用過程中發(fā)現了一個bug,每次啟動程序后,直接新建的話加載進來的exe模塊都顯示叉,提示找不到debug symbols。但是用打開按鈕隨便打開一個文件失敗后,再新建就能成功。猜測可能是直接新建,定位PDB文件時的路徑不對引起的。有源碼,但是懶的看了呵呵,大家感興趣可以試一下。

                好了,方案三就介紹到這里,后面還有更加強大的方案 : )

            前面幾個方案都是直接定位crash的代碼位置,但是在比較大型的程序中,只知道這個信息還是遠遠不夠的,我們希望知道更多關于調用函數順序及變量值等信息,也就是crash時調用堆棧信息。

             

                方案四:SetUnhandledExceptionFilter + StackWalker

                這個方案需要自己動手往工程里添加代碼了。要實現上面的想法,需要做兩件事情:1、需要在crash時有機會對程序堆棧進行處理;2、對堆棧信息進行收集。

                1SetUnhandleExceptionFilter函數

                Windows平臺下的C++程序異常通常可分為兩種:結構化異常(Structured Exception,可以理解為與操作系統相關的異常)和C++異常。對于結構化異常處理(SEH),可以找到很多資料,在此不細說。對于crash錯誤,一般由未被正常捕獲的異常引起,Windows操作系統提供了一個API函數可以在程序crash之前有機會處理這些異常,就是SetUnhandleExceptionFilter函數。(C++也有一個類似函數set_terminate可以處理未被捕獲的C++異常。)

                SetUnhandleExceptionFilter函數聲明如下:

                LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(
                  __in          LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
                );

                其中 LPTOP_LEVEL_EXCEPTION_FILTER 定義如下:

                typedef LONG (WINAPI *PTOP_LEVEL_EXCEPTION_FILTER)(
                    __in struct _EXCEPTION_POINTERS *ExceptionInfo
                );
                typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER;

                簡單來說,SetUnhandleExceptionFilter允許我們設置一個自己的函數作為全局SEH過濾函數,當程序crash前會調用我們的函數進行處理。我們可以利用的是 _EXCEPTION_POINTERS 結構類型的變量ExceptionInfo,它包含了對異常的描述以及發(fā)生異常的線程狀態(tài),過濾函數可以通過返回不同的值來讓系統繼續(xù)運行或退出應用程序。

                關于 SetUnhandleExceptionFilter 函數的具體用法和示例請參考MSDN。

             

                2StackWalker
                現在我們已經有機會可以在crash之前對程序狀態(tài)信息進行處理了,只需要生成并保存堆棧信息就大功告成了。Windows的dbghelp.dll庫提供了一個函數可以得到當前堆棧信息:StackWalk64(在Win2K以前版本中為StackWalk)。該函數聲明如下:

                BOOL WINAPI StackWalk64(
                  __in          DWORD MachineType,
                  __in          HANDLE hProcess,
                  __in          HANDLE hThread,
                  __in_out      LPSTACKFRAME64 StackFrame,
                  __in_out      PVOID ContextRecord,
                  __in          PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
                  __in          PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
                  __in          PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
                  __in          PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
                );
                該函數的具體用法可以參考MSDN。在這里推薦一個牛人寫好的StackWalker,可以直接拿來用,開源的。StackWalker提供了一個基類,給出了幾個簡單的接口,可以方便地生成堆棧信息,并且支持一系列VC版本,非常好用。我們可以自己寫一個子類,并重載虛函數OnOutput,就可以將堆棧信息輸出為特定格式了。StackWalker的地址為:http://www.codeproject.com/KB/threads/StackWalker.aspx

                不過對于Release版本來說,StackWalk64函數獲得的堆棧信息有可能不完整。如果異常是由MFC的模塊拋出,那么獲得的堆棧可能缺少前面調用模塊信息。另外,StackWalk64需要最新的dbghelp.dll文件支持才能工作;要正確輸出crash的函數名和行號,需要要pdb文件支持。以上不足有可能影響輸出信息的完整性和效果,而對于發(fā)布在外的程序,要帶上pdb文件幾乎不可能,因此這個方案還是有缺憾的,比較適用于本地的release版本調試。

                下一篇我們將介紹一個更加完善的解決方案

            當我們把自己的release版本程序發(fā)布出去以后,一般都是在用戶的機器上運行。這種情況下,對于第四種方案,因為需要pdb文件才能夠正確生成堆棧調用的函數行號及代碼行號,因此方案四只適用于本地release版的調試,否則只能生成不完整的堆棧信息。對于前三種方案,其實只需要用戶告知崩潰地址,然后在本地查找crash地址就可以了,但是定位crash的過程非常不方便,如果crash的情況比較多,前三種方案都不合適。而且,前三種方案均不能生成堆棧調用信息,對于debug的作用有限。

                下面我們就來看一個更加完善的解決方案。

             

                方案五:SetUnhandledExceptionFilter + Minidump

                SetUnhandleExceptionFilter函數我們已經介紹過了,本方案的思路還是要利用我們自己的異常處理函數,來生成minidump文件。

                1Minidump概念

                minidump(小存儲器轉儲)可以理解為一個dump文件,里面記錄了能夠幫助調試crash的最小有用信息。實際上,如果你在 系統屬性 -> 高級 -> 啟動和故障恢復 -> 設置 -> 寫入調試信息 中選擇“小內存轉儲(64 KB)”的話,當系統意外停止時都會在C:\Windows\Minidump\路徑下生成一個.dmp后綴的文件,這個文件就是minidump文件,只不過這個是內核態(tài)的minidump。

               我們要生成的是用戶態(tài)的minidump,文件中包含了程序運行的模塊信息、線程信息、堆棧調用信息等。而且為了符合其mini的特性,dump文件是壓縮過的。

                2、生成minidump文件

                生成minidump文件的API函數是MiniDumpWriteDump,該函數需要dbghelp.lib支持,其原型如下:

                BOOL WINAPI MiniDumpWriteDump(
                  __in          HANDLE hProcess,
                  __in          DWORD ProcessId,
                  __in          HANDLE hFile,
                  __in          MINIDUMP_TYPE DumpType,
                  __in          PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
                  __in          PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
                  __in          PMINIDUMP_CALLBACK_INFORMATION CallbackParam
                );

                在我們的異常處理函數中加入以下代碼:

                HANDLE hFile = ::CreateFile( _T("E:\\dumpfile.dmp"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
                 if( hFile != INVALID_HANDLE_VALUE)
                 {
                     MINIDUMP_EXCEPTION_INFORMATION einfo;
                     einfo.ThreadId = ::GetCurrentThreadId();
                     einfo.ExceptionPointers = pExInfo;
                     einfo.ClientPointers = FALSE;

                    ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, &einfo, NULL, NULL);
                    ::CloseHandle(hFile);
                 }

                其中,pExInfo變量為異常處理函數PEXCEPTION_POINTERS類型的參數。具體請參考MSDN。

                3、調試minidump

                調試dump文件首先需要pdb文件,因此我們build程序時需要設置 Debug Infomation Format 為 “Program Database(/Zi)”。其次,我們還要確保所用的dump文件與源代碼、exe、pdb文件版本是一致的,這要求我們必須維護好程序版本信息。

                調試minidump最方便的環(huán)境就是VS了,我們只要將.dmp、.exe、.pdb文件放在一個路徑下,保證源代碼文件的路徑與編譯時的路徑一致就可以了,剩下的就是VS幫我們完成。雙擊.dmp文件或者在文件打開工程中選擇“dump files”,加載dump文件,然后按F5運行就能直接恢復crash時的現場了,你可以定位crash的代碼,可以查看調用堆棧,可以查看線程和模塊信息...一切都跟你設置斷點調試一樣,太強大了!看個截圖吧。

            clip_image012

                需要注意的是,對于release版的程序來說,很多代碼是經過編譯器優(yōu)化過的,因此定位的時候可能會有所偏差,大家可以考慮設置選項去掉代碼優(yōu)化。

                其他可以調試minidump的工具還有WinDbg等,大家可以查閱相關資料。

                本文主要參考了這篇文章:http://vicchina.51.net/research/other/seh/minidumps/intro.htm

                下一篇,我們將給出一個調試release發(fā)布程序的完美解決方案,適合用戶量較大的應用發(fā)布程序的調試。

            上一篇我們已經給出了方案,能夠非常方便的通過dump文件對crash錯誤進行調試和定位;從整個流程上看還差最后一步,即怎樣拿到crash時產生的dump文件。如果可以讓用戶把文件發(fā)送過來自然不錯,但對于類似免費共享軟件等在互聯網上發(fā)布的程序呢?我們的用戶是不確定的,而且用戶量有可能非常大,即使我們能想辦法聯系到用戶,總不能挨個去收集crash信息吧。

                我們需要一種方案,能夠提供crash信息匯報功能。

                我們可以架設一臺服務器專門進行信息收集,只要客戶端在crash時正確匯報即可,但是相應的維護成本和開發(fā)難度也不可忽視。有沒有更簡單的方法呢?還記得我的博文“為程序添加自動發(fā)送Email功能嗎?這就是簡單有效的方法!

             

                方案六:minidump + email

                我們只需要在異常處理時,先生成minidump信息文件,再用email方式將文件發(fā)送到指定郵箱就行了。剩下的就是我們每天查看郵箱,提取dump文件進行調試了。

                1Email功能

                首先我們來看一下email發(fā)送都需要哪些相關信息。

                a、發(fā)送端郵箱帳戶;

                b、接收端郵箱帳戶;

                c、email標題,一般應有軟件名稱及版本信息;

                d、email正文,一般應有簡單的crash信息提示,以區(qū)別不同原因造成的crash;

                e、email附件,當然就是我們的dump文件了,還可以加上軟件生成的log文件等。

                當然,對于標題應該盡量多加一些信息區(qū)別引起crash的原因,比如將crash的地址信息加到標題中;因為當每天有成百上千的crash匯報上來,重復的crash占大多數,把時間都花在區(qū)分它們身上有點太浪費。由此看來,前面方案中提到的StackWalker還是有些用處的,我們可以用它來生成一些crash的文字描述信息,寫到標題或正文中去。

                dump文件的大小是否適合作為郵件的附件呢?實際上minidump產生的文件一般在幾K到幾十K之間,作為email的附件沒有任何問題。

                關于發(fā)送email相關技術細節(jié),已經在“為程序添加自動發(fā)送Email功能文中介紹了,大家可以參考。其實,對接受郵箱中郵件的處理還是很費時費力的,大家可以考慮寫一些腳本將處理流程自動化,提高效率。

                2google breakpad

                google breakpad是一個開源的跨平臺crash report系統,光從開源和跨平臺這兩個特點上來看,它就足以稱的上是一個完善而有效的工具了。其實,breakpad在整個crash report層次上給出了一個系統級的解決方案,也就是說它幾乎能適應各種軟件、各種平臺的應用要求。

                breakpad的整體思路跟上面介紹的方案是相似的,只不過最后提交dump文件的方式更加完善。大家有興趣可以去它的官方網址查閱相關資料:http://code.google.com/p/google-breakpad/

             

                ok,關于調試release發(fā)布程序的crash錯誤系列文章就寫完了。這幾篇文章給出的方案由簡單到復雜,由簡陋到完善,對crash調試有了一個比較全面的總結。當然,其中涉及到的概念和技術還很多,需要我們去不斷學習和領悟,也希望大家能夠互相交流。

            posted @ 2011-11-07 21:15 RTY 閱讀(1241) | 評論 (0)編輯 收藏

            僅列出標題
            共31頁: First 3 4 5 6 7 8 9 10 11 Last 
            亚洲精品乱码久久久久久蜜桃图片 | 久久久国产亚洲精品| 久久国产精品久久国产精品| 一级做a爰片久久毛片免费陪 | 国产高潮国产高潮久久久| 久久亚洲日韩看片无码| 久久久久人妻一区精品果冻| 久久综合九色综合97_久久久| 久久精品久久久久观看99水蜜桃| 久久九九久精品国产免费直播| 久久久久久综合一区中文字幕| 国产情侣久久久久aⅴ免费| 久久亚洲精品成人AV| 久久SE精品一区二区| 久久久久久久精品成人热色戒 | 久久久高清免费视频| 亚洲va久久久久| 伊人久久大香线蕉AV色婷婷色| 亚洲精品美女久久777777| 久久久久人妻一区精品性色av| 99久久无码一区人妻a黑| 国产三级久久久精品麻豆三级| 久久精品国产影库免费看| 成人精品一区二区久久久| 国内精品久久久久影院网站| 久久精品国产99久久丝袜| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 日本久久久久亚洲中字幕| 久久久久久亚洲AV无码专区| 国产精品久久网| 久久九九久精品国产| 亚洲欧美成人综合久久久| 国产成人无码久久久精品一| 久久99精品国产麻豆婷婷| 久久精品国产99国产精品导航| 精品久久久久久亚洲精品| 国内精品久久久久久久亚洲| 国产精品99久久久精品无码 | 久久亚洲中文字幕精品一区| 免费久久人人爽人人爽av| 久久久久夜夜夜精品国产|