### BEGIN LICENSE ###
### Use of the triage tools and related source code is subject to the terms
### of the license below.
###
### ------------------------------------------------------------------------
### Copyright (C) 2011 Carnegie Mellon University. All Rights Reserved.
### Portions Copyright 2013 BlackBerry Ltd. All Rights Reserved.
### ------------------------------------------------------------------------
### Redistribution and use in source and binary forms, with or without
### modification, are permitted provided that the following conditions are
### met:
###
### 1. Redistributions of source code must retain the above copyright
###    notice, this list of conditions and the following acknowledgments
###    and disclaimers.
###
### 2. Redistributions in binary form must reproduce the above copyright
###    notice, this list of conditions and the following disclaimer in the
###    documentation and/or other materials provided with the distribution.
###
### 3. The names "Department of Homeland Security," "Carnegie Mellon
###    University," "CERT" and/or "Software Engineering Institute" shall
###    not be used to endorse or promote products derived from this software
###    without prior written permission. For written permission, please
###    contact permission@sei.cmu.edu.
###
### 4. Products derived from this software may not be called "CERT" nor
###    may "CERT" appear in their names without prior written permission of
###    permission@sei.cmu.edu.
###
### 5. Redistributions of any form whatsoever must retain the following
###    acknowledgment:
###
###    "This product includes software developed by CERT with funding
###     and support from the Department of Homeland Security under
###     Contract No. FA 8721-05-C-0003."
###
### THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
### CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
### EXPRESS OR IMPLIED, AS TO ANY MATTER, AND ALL SUCH WARRANTIES, INCLUDING
### WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE
### EXPRESSLY DISCLAIMED. WITHOUT LIMITING THE GENERALITY OF THE FOREGOING,
### CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND
### RELATING TO EXCLUSIVITY, INFORMATIONAL CONTENT, ERROR-FREE OPERATION,
### RESULTS TO BE OBTAINED FROM USE, FREEDOM FROM PATENT, TRADEMARK AND
### COPYRIGHT INFRINGEMENT AND/OR FREEDOM FROM THEFT OF TRADE SECRETS.
### END LICENSE ###
'''
A collection of basic Python objects used throughout this project.
'''

import functools

class AttrDict(dict):
    def __getattribute__(self, name):
        try:
            return dict.__getattribute__(self, name)
        except AttributeError:
            if name in self:
                return self[name]
            raise
    def __setattr__(self, name, value):
        dict.__setattr__(self, name, value)
        try:
            del self[name]
        except KeyError:
            pass

def memoized(func):
    @functools.wraps(func)
    def _wrapper(tgt, *args):
        #start = time.time()
        if not hasattr(tgt, "__memo__"):
            tgt.__memo__ = {}
        key = "{}{}".format(func.__name__, repr(args))
        try:
            return tgt.__memo__[key]
        except KeyError:
            pass
        res = func(tgt, *args)
        tgt.__memo__[key] = res
        #print "{} = {} {:0.2f}s".format(key, res, time.time() - start)
        return res
    return _wrapper

def print_machine_string(c, target):
    '''
    Returns a machine-parsable string representation of this
    Classification.
    NOTE: This code is deprecated and may be removed in a future update.
    '''
    print("Warning: machine string printing is deprecated and may be "
        "removed in a future release.")
    if not c.tags:
        print("No matches")
    else:
        print("EXCEPTION_FAULTING_ADDRESS:{:#016x}".format(target.si_addr()))
        print("EXCEPTION_CODE:{}".format(target.si_signo()))
        try:
            print("FAULTING_INSTRUCTION:{}".format(str(target.current_instruction()).split(":\t")[1].strip()))
        except IndexError:
            print("FAULTING_INSTRUCTION:?")
        print("MAJOR_HASH:{}".format(c.hash.major))
        print("MINOR_HASH:{}".format(c.hash.minor))
        bt_result = ["STACK_FRAME:{}".format(i.terse()) for i in target.backtrace() if i.type() != 2]
        print("STACK_DEPTH:{}".format(len(bt_result)))
        for bt in bt_result:
            print(bt)
        print("INSTRUCTION_ADDRESS:{:#016x}".format(target.pc()))
        try:
            print("INVOKING_STACK_FRAME:{}".format(target.faulting_frame().position))
        except AttributeError:
            print("INVOKING_STACK_FRAME:?")
        print("DESCRIPTION:{}".format(c.desc))
        print("SHORT_DESCRIPTION:{}".format(c.tags[0]))
        if len(c.tags) > 1:
            print("OTHER_RULES:{}".format(", ".join(str(t) for t in c.tags[1:])))
        print("CLASSIFICATION:{}".format(c.category))
        print("EXPLANATION:{}".format(c.explanation))

