diff options
Diffstat (limited to 'base')
47 files changed, 10850 insertions, 0 deletions
diff --git a/base/bitfield.hh b/base/bitfield.hh new file mode 100644 index 000000000..ee5ea72cf --- /dev/null +++ b/base/bitfield.hh @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __BITFIELD_HH +#define __BITFIELD_HH + +#include <inttypes.h> + +/** + * Generate a 64-bit mask of 'nbits' 1s, right justified. + */ +inline uint64_t +mask(int nbits) +{ + return (nbits == 64) ? (uint64_t)-1LL : (1ULL << nbits) - 1; +} + + +/** + * Extract the bitfield from position 'first' to 'last' (inclusive) + * from 'val' and right justify it. MSB is numbered 63, LSB is 0. + */ +template <class T> +inline +T +bits(T val, int first, int last) +{ + int nbits = first - last + 1; + return (val >> last) & mask(nbits); +} + +/** + * Sign-extend an N-bit value to 64 bits. + */ +template <int N> +inline +int64_t +sext(uint64_t val) +{ + int sign_bit = bits(val, N-1, N-1); + return sign_bit ? (val | ~mask(N)) : val; +} + +#endif diff --git a/base/callback.hh b/base/callback.hh new file mode 100644 index 000000000..a1d23b5ed --- /dev/null +++ b/base/callback.hh @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CALLBACK_HH__ +#define __CALLBACK_HH__ + +#include <list> + +class Callback { + public: + virtual ~Callback() {} + virtual void process() = 0; +}; + +class CallbackQueue +{ + protected: + std::list<Callback *> callbacks; + + public: + void add(Callback *callback) { callbacks.push_back(callback); } + bool empty() const { return callbacks.empty(); } + void processOne() { + Callback *c = callbacks.front(); + callbacks.pop_front(); + c->process(); + } + void processAll() { while (!empty()) processOne(); } +}; + +#endif // __CALLBACK_HH__ diff --git a/base/circlebuf.cc b/base/circlebuf.cc new file mode 100644 index 000000000..482c97f84 --- /dev/null +++ b/base/circlebuf.cc @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <algorithm> +#include <string> + +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "cprintf.hh" +#include "circlebuf.hh" +#include "intmath.h" + +using namespace std; + +CircleBuf::CircleBuf(int l) + : rollover(false), buflen(l), size(0), start(0), stop(0) +{ buf = new char[buflen]; } + +CircleBuf::~CircleBuf() +{ if (buf) delete [] buf; } + +void +CircleBuf::dump() +{ + cprintf("start = %10d, stop = %10d, buflen = %10d\n", start, stop, buflen); + fflush(stdout); + ::write(STDOUT_FILENO, buf, buflen); + ::write(STDOUT_FILENO, "<\n", 2); +} + +void +CircleBuf::flush() +{ + start = 0; + stop = 0; + rollover = false; +} + +void +CircleBuf::read(char *b, int len) +{ + size -= len; + if (size < 0) + size = 0; + + if (stop > start) { + len = min(len, stop - start); + memcpy(b, buf + start, len); + start += len; + } + else { + int endlen = buflen - start; + if (endlen > len) { + memcpy(b, buf + start, len); + start += len; + } + else { + memcpy(b, buf + start, endlen); + start = min(len - endlen, stop); + memcpy(b + endlen, buf, start); + } + } +} + +void +CircleBuf::read(int fd, int len) +{ + size -= len; + if (size < 0) + size = 0; + + if (stop > start) { + len = min(len, stop - start); + ::write(fd, buf + start, len); + start += len; + } + else { + int endlen = buflen - start; + if (endlen > len) { + ::write(fd, buf + start, len); + start += len; + } + else { + ::write(fd, buf + start, endlen); + start = min(len - endlen, stop); + ::write(fd, buf, start); + } + } +} + +void +CircleBuf::read(int fd) +{ + size = 0; + + if (stop > start) { + ::write(fd, buf + start, stop - start); + } + else { + ::write(fd, buf + start, buflen - start); + ::write(fd, buf, stop); + } + + start = stop; +} + +void +CircleBuf::readall(int fd) +{ + if (rollover) + ::write(fd, buf + stop, buflen - stop); + + ::write(fd, buf, stop); + start = stop; +} + +void +CircleBuf::write(char b) +{ write(&b, 1); } + +void +CircleBuf::write(const char *b) +{ write(b, strlen(b)); } + +void +CircleBuf::write(const char *b, int len) +{ + if (len <= 0) + return; + + size += len; + if (size > buflen) + size = buflen; + + int old_start = start; + int old_stop = stop; + + if (len >= buflen) { + start = 0; + stop = buflen; + rollover = true; + memcpy(buf, b + (len - buflen), buflen); + return; + } + + if (stop + len <= buflen) { + memcpy(buf + stop, b, len); + stop += len; + } else { + int end_len = buflen - old_stop; + stop = len - end_len; + memcpy(buf + old_stop, b, end_len); + memcpy(buf, b + end_len, stop); + rollover = true; + } + + if (old_start > old_stop && old_start < stop || + old_start < old_stop && stop < old_stop) + start = stop + 1; +} diff --git a/base/circlebuf.hh b/base/circlebuf.hh new file mode 100644 index 000000000..e0abed31c --- /dev/null +++ b/base/circlebuf.hh @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CIRCLEBUF_HH__ +#define __CIRCLEBUF_HH__ + + +class CircleBuf +{ +protected: + char *buf; + bool rollover; + int buflen; + int size; + int start; + int stop; + +public: + explicit CircleBuf(int l); + ~CircleBuf(); + + bool empty() { return size == 0; } + void dump(); + void flush(); + void read(char *b, int len); + void read(int fd, int len); + void read(int fd); + void readall(int fd); + void write(char b); + void write(const char *b); + void write(const char *b, int len); +}; + +#endif // __CIRCLEBUF_HH__ diff --git a/base/cprintf.cc b/base/cprintf.cc new file mode 100644 index 000000000..be6e64f59 --- /dev/null +++ b/base/cprintf.cc @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <cassert> +#include <iomanip> +#include <iostream> +#include <sstream> + +#include "cprintf.hh" + +using namespace std; + +namespace cp { + +void +ArgList::dump(const string &format) +{ + const char *p = format.c_str(); + + stream->fill(' '); + stream->flags((ios::fmtflags)0); + + Format fmt; + + while (*p) { + switch (*p) { + case '%': { + if (p[1] == '%') { + *stream << '%'; + p += 2; + continue; + } + + if (objects.empty()) + format_invalid(*stream); + + Base *data = objects.front(); + + fmt.clear(); + bool done = false; + bool end_number = false; + bool have_precision = false; + int number = 0; + + while (!done) { + ++p; + if (*p >= '0' && *p <= '9') { + if (end_number) + continue; + } else if (number > 0) + end_number = true; + + switch (*p) { + case 's': + fmt.format = Format::string; + done = true; + break; + + case 'c': + fmt.format = Format::character; + done = true; + break; + + case 'l': + continue; + + case 'p': + fmt.format = Format::integer; + fmt.base = Format::hex; + fmt.alternate_form = true; + done = true; + break; + + case 'X': + fmt.uppercase = true; + case 'x': + fmt.base = Format::hex; + fmt.format = Format::integer; + done = true; + break; + + case 'o': + fmt.base = Format::oct; + fmt.format = Format::integer; + done = true; + break; + + case 'd': + case 'i': + case 'u': + fmt.format = Format::integer; + done = true; + break; + + case 'G': + fmt.uppercase = true; + case 'g': + fmt.format = Format::floating; + fmt.float_format = Format::best; + done = true; + break; + + case 'E': + fmt.uppercase = true; + case 'e': + fmt.format = Format::floating; + fmt.float_format = Format::scientific; + done = true; + break; + + case 'f': + fmt.format = Format::floating; + fmt.float_format = Format::fixed; + done = true; + break; + + case 'n': + *stream << "we don't do %n!!!\n"; + done = true; + break; + + case '#': + fmt.alternate_form = true; + break; + + case '-': + fmt.flush_left = true; + break; + + case '+': + fmt.print_sign = true; + break; + + case ' ': + fmt.blank_space = true; + break; + + case '.': + fmt.width = number; + fmt.precision = 0; + have_precision = true; + number = 0; + end_number = false; + break; + + case '0': + if (number == 0) { + fmt.fill_zero = true; + break; + } + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + number = number * 10 + (*p - '0'); + break; + + case '%': + assert("we shouldn't get here"); + break; + + default: + done = true; + break; + } + + if (end_number) { + if (have_precision) + fmt.precision = number; + else + fmt.width = number; + + end_number = false; + number = 0; + } + } + + ios::fmtflags saved_flags = stream->flags(); + char old_fill = stream->fill(); + int old_precision = stream->precision(); + + data->process(*stream, fmt); + + stream->flags(saved_flags); + stream->fill(old_fill); + stream->precision(old_precision); + + delete data; + objects.pop_front(); + ++p; + } + break; + + case '\n': + *stream << endl; + ++p; + break; + case '\r': + ++p; + if (*p != '\n') + *stream << endl; + break; + + default: { + size_t len = strcspn(p, "%\n\r\0"); + stream->write(p, len); + p += len; + } + break; + } + + ios::iostate state = stream->rdstate(); + if (state) { +#if 0 + cout << "stream->rdstate() == " << state << endl; + if (state & ios::badbit) + cout << "stream is bad!\n"; + if (state & ios::eofbit) + cout << "stream at eof!\n"; + if (state & ios::failbit) + cout << "stream failed!\n"; + if (state & ios::goodbit) + cout << "stream is good!!\n"; +#endif + stream->clear(); + } + } + + while (!objects.empty()) { + Base *data = objects.front(); + data->process(*stream, fmt); + delete data; + objects.pop_front(); + } +} + +string +ArgList::dumpToString(const string &format) +{ + stringstream ss; + + dump(ss, format); + + return ss.str(); +} + +} diff --git a/base/cprintf.hh b/base/cprintf.hh new file mode 100644 index 000000000..2dc84502a --- /dev/null +++ b/base/cprintf.hh @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPRINTF_HH__ +#define __CPRINTF_HH__ + +#include <iostream> +#include <list> +#include <sstream> +#include <string> + +namespace cp { + +#include "cprintf_formats.hh" + +class ArgList +{ + private: + class Base + { + public: + virtual ~Base() {} + virtual void process(std::ostream &out, Format &fmt) = 0; + }; + + template <typename T> + class Node : public Base + { + public: + const T &data; + + public: + Node(const T &d) : data(d) {} + virtual void process(std::ostream &out, Format &fmt) { + switch (fmt.format) { + case Format::character: + format_char(out, data, fmt); + break; + + case Format::integer: + format_integer(out, data, fmt); + break; + + case Format::floating: + format_float(out, data, fmt); + break; + + case Format::string: + format_string(out, data, fmt); + break; + + default: + format_invalid(out); + break; + } + } + }; + + typedef std::list<Base *> list_t; + + protected: + list_t objects; + std::ostream *stream; + + public: + ArgList() : stream(&std::cout) {} + + template<class T> + void append(const T &data) { + Base *obj = new ArgList::Node<T>(data); + objects.push_back(obj); + } + + template<class T> + void prepend(const T &data) { + Base *obj = new ArgList::Node<T>(data); + objects.push_front(obj); + } + + void dump(const std::string &format); + void dump(std::ostream &strm, const std::string &fmt) + { stream = &strm; dump(fmt); } + + std::string dumpToString(const std::string &format); + + friend ArgList &operator<<(std::ostream &str, ArgList &list); +}; + +template<class T> +inline ArgList & +operator,(ArgList &alist, const T &data) +{ + alist.append(data); + return alist; +} + +class ArgListNull { +}; + +inline ArgList & +operator,(ArgList &alist, ArgListNull) +{ return alist; } + +// +// cprintf(format, args, ...) prints to cout +// (analogous to printf()) +// +inline void +__cprintf(const std::string &format, ArgList &args) +{ args.dump(format); delete &args; } +#define __cprintf__(format, args...) \ + cp::__cprintf(format, (*(new cp::ArgList), args)) +#define cprintf(args...) \ + __cprintf__(args, cp::ArgListNull()) + +// +// ccprintf(stream, format, args, ...) prints to the specified stream +// (analogous to fprintf()) +// +inline void +__ccprintf(std::ostream &stream, const std::string &format, ArgList &args) +{ args.dump(stream, format); delete &args; } +#define __ccprintf__(stream, format, args...) \ + cp::__ccprintf(stream, format, (*(new cp::ArgList), args)) +#define ccprintf(stream, args...) \ + __ccprintf__(stream, args, cp::ArgListNull()) + +// +// csprintf(format, args, ...) returns a string +// (roughly analogous to sprintf()) +// +inline std::string +__csprintf(const std::string &format, ArgList &args) +{ std::string s = args.dumpToString(format); delete &args; return s; } +#define __csprintf__(format, args...) \ + cp::__csprintf(format, (*(new cp::ArgList), args)) +#define csprintf(args...) \ + __csprintf__(args, cp::ArgListNull()) + +template<class T> +inline ArgList & +operator<<(ArgList &list, const T &data) +{ + list.append(data); + return list; +} + +inline ArgList & +operator<<(std::ostream &str, ArgList &list) +{ + list.stream = &str; + return list; +} + +class ArgListTemp +{ + private: + std::string format; + ArgList *args; + + public: + ArgListTemp(const std::string &f) : format(f) { args = new ArgList; } + ~ArgListTemp() { args->dump(format); delete args; } + + operator ArgList *() { return args; } +}; + +#define cformat(format) \ + (*((cp::ArgList *)cp::ArgListTemp(format))) +} + +#endif // __CPRINTF_HH__ diff --git a/base/cprintf_formats.hh b/base/cprintf_formats.hh new file mode 100644 index 000000000..1e5de4fdf --- /dev/null +++ b/base/cprintf_formats.hh @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPRINTF_FORMATS_HH__ +#define __CPRINTF_FORMATS_HH__ + +struct Format +{ + bool alternate_form; + bool flush_left; + bool print_sign; + bool blank_space; + bool fill_zero; + bool uppercase; + enum { dec, hex, oct } base; + enum { none, string, integer, character, floating } format; + enum { best, fixed, scientific } float_format; + int precision; + int width; + + Format() { } + void clear() { + alternate_form = false; + flush_left = false; + print_sign = false; + blank_space = false; + fill_zero = false; + uppercase = false; + base = dec; + format = none; + precision = -1; + width = 0; + } +}; + +inline void +format_invalid(std::ostream &out) +{ + using namespace std; + + out << "format invalid!!!" << endl; +} + + +template <typename T> +inline void +_format_char(std::ostream &out, const T& data, Format &fmt) +{ + using namespace std; + + out << data; +} + +template <typename T> +inline void +_format_integer(std::ostream &out, const T& data, Format &fmt) +{ + using namespace std; + + switch (fmt.base) { + case Format::hex: + out.setf(ios::hex, ios::basefield); + break; + + case Format::oct: + out.setf(ios::oct, ios::basefield); + break; + + case Format::dec: + out.setf(ios::dec, ios::basefield); + break; + } + + if (fmt.alternate_form) { + if (!fmt.fill_zero) + out.setf(ios::showbase); + else { + switch (fmt.base) { + case Format::hex: + out << "0x"; + fmt.width -= 2; + break; + case Format::oct: + out << "0"; + fmt.width -= 1; + break; + case Format::dec: + break; + } + } + } + + if (fmt.fill_zero) + out.fill('0'); + + if (fmt.width > 0) + out.width(fmt.width); + + if (fmt.flush_left && !fmt.fill_zero) + out.setf(ios::left); + + if (fmt.print_sign) + out.setf(ios::showpos); + + if (fmt.uppercase) + out.setf(ios::uppercase); + + out << data; +} + +template <typename T> +inline void +_format_float(std::ostream &out, const T& data, Format &fmt) +{ + using namespace std; + + switch (fmt.float_format) { + case Format::scientific: + if (fmt.precision != -1) { + if (fmt.width > 0) + out.width(fmt.width); + + if (fmt.precision == 0) + fmt.precision = 1; + else + out.setf(ios::scientific); + + out.precision(fmt.precision); + } else + if (fmt.width > 0) + out.width(fmt.width); + + if (fmt.uppercase) + out.setf(ios::uppercase); + break; + + case Format::fixed: + if (fmt.precision != -1) { + if (fmt.width > 0) + out.width(fmt.width); + + out.setf(ios::fixed); + out.precision(fmt.precision); + } else + if (fmt.width > 0) + out.width(fmt.width); + + break; + + default: + if (fmt.precision != -1) + out.precision(fmt.precision); + + if (fmt.width > 0) + out.width(fmt.width); + + break; + } + + out << data; +} + +template <typename T> +inline void +_format_string(std::ostream &out, const T& data, Format &fmt) +{ + using namespace std; + +#if defined(__GNUC__) && (__GNUC__ < 3) || 1 + if (fmt.width > 0) { + std::stringstream foo; + foo << data; + int flen = foo.str().size(); + + if (fmt.width > flen) { + char *spaces = new char[fmt.width - flen + 1]; + memset(spaces, ' ', fmt.width - flen); + spaces[fmt.width - flen] = 0; + + if (fmt.flush_left) + out << foo.str() << spaces; + else + out << spaces << foo.str(); + + delete [] spaces; + } else + out << data; + } else + out << data; +#else + if (fmt.width > 0) + out.width(fmt.width); + if (fmt.flush_left) + out.setf(ios::left); + + out << data; +#endif +} + +///////////////////////////////////////////////////////////////////////////// +// +// The code below controls the actual usage of formats for various types +// + +// +// character formats +// +template <typename T> +inline void +format_char(std::ostream &out, const T& data, Format &fmt) +{ format_invalid(out); } + +inline void +format_char(std::ostream &out, char data, Format &fmt) +{ _format_char(out, data, fmt); } + +inline void +format_char(std::ostream &out, unsigned char data, Format &fmt) +{ _format_char(out, data, fmt); } + +inline void +format_char(std::ostream &out, signed char data, Format &fmt) +{ _format_char(out, data, fmt); } + +inline void +format_char(std::ostream &out, short data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, unsigned short data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, int data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, unsigned int data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, long data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, unsigned long data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, long long data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, unsigned long long data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +// +// integer formats +// +template <typename T> +inline void +format_integer(std::ostream &out, const T &data, Format &fmt) +{ _format_integer(out, data, fmt); } + +#if 0 +inline void +format_integer(std::ostream &out, char data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, unsigned char data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, signed char data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, short data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, unsigned short data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, int data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, unsigned int data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, long data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, unsigned long data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, long long data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, unsigned long long data, Format &fmt) +{ _format_integer(out, data, fmt); } +#endif + +// +// floating point formats +// +template <typename T> +inline void +format_float(std::ostream &out, const T& data, Format &fmt) +{ format_invalid(out); } + +inline void +format_float(std::ostream &out, float data, Format &fmt) +{ _format_float(out, data, fmt); } + +inline void +format_float(std::ostream &out, double data, Format &fmt) +{ _format_float(out, data, fmt); } + +// +// string formats +// +template <typename T> +inline void +format_string(std::ostream &out, const T& data, Format &fmt) +{ _format_string(out, data, fmt); } + +inline void +format_string(std::ostream &out, const std::stringstream& data, Format &fmt) +{ _format_string(out, data.str(), fmt); } + +#endif // __CPRINTF_FORMATS_HH__ diff --git a/base/date.cc b/base/date.cc new file mode 100644 index 000000000..f961b9c21 --- /dev/null +++ b/base/date.cc @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +const char *compileDate = __DATE__ " " __TIME__; diff --git a/base/dbl_list.hh b/base/dbl_list.hh new file mode 100644 index 000000000..4f6d61a45 --- /dev/null +++ b/base/dbl_list.hh @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DBL_LIST_HH__ +#define __DBL_LIST_HH__ + +class DblListEl { + DblListEl *next; + DblListEl *prev; + + // remove this from list + void remove() { + prev->next = next; + next->prev = prev; + } + + // insert this before old_el + void insertBefore(DblListEl *old_el) { + prev = old_el->prev; + next = old_el; + prev->next = this; + next->prev = this; + } + + // insert this after old_el + void insertAfter(DblListEl *old_el) { + next = old_el->next; + prev = old_el; + next->prev = this; + prev->next = this; + } + + friend class DblListBase; +}; + + +// +// doubly-linked list of DblListEl objects +// +class DblListBase { + // dummy list head element: dummy.next is head, dummy.prev is tail + DblListEl dummy; + + // length counter + unsigned length; + + DblListEl *valid_or_null(DblListEl *el) { + // make sure users never see the dummy element + return (el == &dummy) ? NULL : el; + } + + public: + + DblListEl *head() { + return valid_or_null(dummy.next); + } + + DblListEl *tail() { + return valid_or_null(dummy.prev); + } + + DblListEl *next(DblListEl *el) { + return valid_or_null(el->next); + } + + DblListEl *prev(DblListEl *el) { + return valid_or_null(el->prev); + } + + bool is_empty() { + return (dummy.next == &dummy); + } + + void remove(DblListEl *el) { + el->remove(); + --length; + } + + void insertBefore(DblListEl *new_el, DblListEl *old_el) { + new_el->insertBefore(old_el); + ++length; + } + + void insertAfter(DblListEl *new_el, DblListEl *old_el) { + new_el->insertAfter(old_el); + ++length; + } + + // append to end of list, i.e. as dummy.prev + void append(DblListEl *el) { + insertBefore(el, &dummy); + } + + // prepend to front of list (push), i.e. as dummy.next + void prepend(DblListEl *el) { + insertAfter(el, &dummy); + } + + DblListEl *pop() { + DblListEl *hd = head(); + if (hd != NULL) + remove(hd); + return hd; + } + + // constructor + DblListBase() { + dummy.next = dummy.prev = &dummy; + length = 0; + } +}; + + +// +// Template class serves solely to cast args & return values +// to appropriate type (T *) +// +template<class T> class DblList : private DblListBase { + + public: + + T *head() { return (T *)DblListBase::head(); } + T *tail() { return (T *)DblListBase::tail(); } + + T *next(T *el) { return (T *)DblListBase::next(el); } + T *prev(T *el) { return (T *)DblListBase::prev(el); } + + bool is_empty() { return DblListBase::is_empty(); } + + void remove(T *el) { DblListBase::remove(el); } + + void append(T *el) { DblListBase::append(el); } + void prepend(T *el) { DblListBase::prepend(el); } + + T *pop() { return (T *)DblListBase::pop(); } + + DblList<T>() { } +}; + +#endif // __DBL_LIST_HH__ diff --git a/base/endian.hh b/base/endian.hh new file mode 100644 index 000000000..2877744ae --- /dev/null +++ b/base/endian.hh @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ENDIAN_HH__ +#define __ENDIAN_HH__ + +#include <arpa/inet.h> + +inline bool +HostBigEndian() +{ + int x = 0x11223344; + return x == htonl(x); +} + +#endif // __ENDIAN_HH__ diff --git a/base/fast_alloc.cc b/base/fast_alloc.cc new file mode 100644 index 000000000..290e59113 --- /dev/null +++ b/base/fast_alloc.cc @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This code was originally written by Steve Reinhardt as part of + * the Wisconsin Wind Tunnel simulator. Relicensed as part of M5 + * by permission. + */ + +#ifdef __GNUC__ +#pragma implementation +#endif + +#include <assert.h> +#include "fast_alloc.hh" + +void *FastAlloc::freeLists[Num_Buckets]; + +#ifdef FAST_ALLOC_STATS +unsigned FastAlloc::newCount[Num_Buckets]; +unsigned FastAlloc::deleteCount[Num_Buckets]; +unsigned FastAlloc::allocCount[Num_Buckets]; +#endif + +void *FastAlloc::moreStructs(int bucket) +{ + assert(bucket > 0 && bucket < Num_Buckets); + + int sz = bucket * Alloc_Quantum; + const int nstructs = Num_Structs_Per_New; // how many to allocate? + char *p = ::new char[nstructs * sz]; + +#ifdef FAST_ALLOC_STATS + ++allocCount[bucket]; +#endif + + freeLists[bucket] = p; + for (int i = 0; i < (nstructs-2); ++i, p += sz) + *(void **)p = p + sz; + *(void **)p = 0; + + return (p + sz); +} + + +#ifdef FAST_ALLOC_DEBUG + +#include <typeinfo> +#include <iostream> +#include <iomanip> +#include <map> +#include <string> + +using namespace std; + +// count of in-use FastAlloc objects +int FastAlloc::numInUse; + +// dummy head & tail object for doubly linked list of in-use FastAlloc +// objects +FastAlloc FastAlloc::inUseHead(&FastAlloc::inUseHead, &FastAlloc::inUseHead); + +// special constructor for dummy head: make inUsePrev & inUseNext +// point to self +FastAlloc::FastAlloc(FastAlloc *prev, FastAlloc *next) +{ + inUsePrev = prev; + inUseNext = next; +} + + +// constructor: marks as in use, add to in-use list +FastAlloc::FastAlloc() +{ + // mark this object in use + inUse = true; + + // update count + ++numInUse; + + // add to tail of list of in-use objects ("before" dummy head) + FastAlloc *myNext = &inUseHead; + FastAlloc *myPrev = inUseHead.inUsePrev; + + inUsePrev = myPrev; + inUseNext = myNext; + myPrev->inUseNext = this; + myNext->inUsePrev = this; +} + +// destructor: mark not in use, remove from in-use list +FastAlloc::~FastAlloc() +{ + assert(inUse); + inUse = false; + + --numInUse; + assert(numInUse >= 0); + + // remove me from in-use list + inUsePrev->inUseNext = inUseNext; + inUseNext->inUsePrev = inUsePrev; +} + + +// summarize in-use list +void +FastAlloc::dump_summary() +{ + map<string, int> typemap; + + for (FastAlloc *p = inUseHead.inUseNext; p != &inUseHead; p = p->inUseNext) + { + ++typemap[typeid(*p).name()]; + } + + map<string, int>::const_iterator mapiter; + + cout << " count type\n" + << " ----- ----\n"; + for (mapiter = typemap.begin(); mapiter != typemap.end(); ++mapiter) + { + cout << setw(6) << mapiter->second << " " << mapiter->first << endl; + } +} + + +// show oldest n items on in-use list +void +FastAlloc::dump_oldest(int n) +{ + // sanity check: don't want to crash the debugger if you forget to + // pass in a parameter + if (n < 0 || n > numInUse) + { + cout << "FastAlloc::dump_oldest: bad arg " << n + << " (" << numInUse << " objects in use" << endl; + return; + } + + for (FastAlloc *p = inUseHead.inUsePrev; + p != &inUseHead && n > 0; + p = p->inUsePrev, --n) + { + cout << p << " " << typeid(*p).name() << endl; + } +} + + +// +// C interfaces to FastAlloc::dump_summary() and FastAlloc::dump_oldest(). +// gdb seems to have trouble with calling C++ functions directly. +// +extern "C" void +fast_alloc_summary() +{ + FastAlloc::dump_summary(); +} + +extern "C" void +fast_alloc_oldest(int n) +{ + FastAlloc::dump_oldest(n); +} + +#endif diff --git a/base/fast_alloc.hh b/base/fast_alloc.hh new file mode 100644 index 000000000..7d699abd1 --- /dev/null +++ b/base/fast_alloc.hh @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This code was originally written by Steve Reinhardt as part of + * the Wisconsin Wind Tunnel simulator. Relicensed as part of M5 + * by permission. + */ + +#ifndef __FAST_ALLOC_H__ +#define __FAST_ALLOC_H__ + +#include <stddef.h> + +// Fast structure allocator. Designed for small objects that are +// frequently allocated and deallocated. This code is derived from the +// 'alloc_struct' package used in WWT and Blizzard. C++ provides a +// much nicer framework for the same optimization. The package is +// implemented as a class, FastAlloc. Allocation and deletion are +// performed using FastAlloc's new and delete operators. Any object +// that derives from the FastAlloc class will transparently use this +// allocation package. + +// The static allocate() and deallocate() methods can also be called +// directly if desired. + +// In order for derived classes to call delete with the correct +// structure size even when they are deallocated via a base-type +// pointer, they must have a virtual destructor. It is sufficient for +// FastAlloc to declare a virtual destructor (as it does); it is not +// required for derived classes to declare their own destructor. The +// compiler will automatically generate a virtual destructor for each +// derived class. However, it is more efficient if each derived class +// defines an inline destructor, so that the compiler can statically +// collapse the destructor call chain back up the inheritance +// hierarchy. + +// Uncomment this #define to track in-use objects +// (for debugging memory leaks). +//#define FAST_ALLOC_DEBUG + +// Uncomment this #define to count news, deletes, and chunk allocations +// (by bucket). +// #define FAST_ALLOC_STATS + +class FastAlloc { + public: + + static void *allocate(size_t); + static void deallocate(void *, size_t); + + void *operator new(size_t); + void operator delete(void *, size_t); + +#ifdef FAST_ALLOC_DEBUG + FastAlloc(); + FastAlloc(FastAlloc*,FastAlloc*); // for inUseHead, see below + virtual ~FastAlloc(); +#else + virtual ~FastAlloc() {} +#endif + + private: + + // Max_Alloc_Size is the largest object that can be allocated with + // this class. There's no fundamental limit, but this limits the + // size of the freeLists array. Let's not make this really huge + // like in Blizzard. + static const int Max_Alloc_Size = 512; + + // Alloc_Quantum is the difference in size between adjacent + // buckets in the free list array. + static const int Log2_Alloc_Quantum = 3; + static const int Alloc_Quantum = (1 << Log2_Alloc_Quantum); + + // Num_Buckets = bucketFor(Max_Alloc_Size) + 1 + static const int Num_Buckets = + ((Max_Alloc_Size + Alloc_Quantum - 1) >> Log2_Alloc_Quantum) + 1; + + // when we call new() for more structures, how many should we get? + static const int Num_Structs_Per_New = 20; + + static int bucketFor(size_t); + static void *moreStructs(int bucket); + + static void *freeLists[Num_Buckets]; + +#ifdef FAST_ALLOC_STATS + static unsigned newCount[Num_Buckets]; + static unsigned deleteCount[Num_Buckets]; + static unsigned allocCount[Num_Buckets]; +#endif + +#ifdef FAST_ALLOC_DEBUG + // per-object debugging fields + bool inUse; // in-use flag + FastAlloc *inUsePrev; // ptrs to build list of in-use objects + FastAlloc *inUseNext; + + // static (global) debugging vars + static int numInUse; // count in-use objects + static FastAlloc inUseHead; // dummy head for list of in-use objects + + public: + // functions to dump debugging info (see fast_alloc.cc for C + // versions that might be more agreeable to call from gdb) + static void dump_summary(); + static void dump_oldest(int n); +#endif +}; + + +inline +int FastAlloc::bucketFor(size_t sz) +{ + return (sz + Alloc_Quantum - 1) >> Log2_Alloc_Quantum; +} + + +inline +void *FastAlloc::allocate(size_t sz) +{ + int b; + void *p; + + if (sz > Max_Alloc_Size) + return (void *)::new char[sz]; + + b = bucketFor(sz); + p = freeLists[b]; + + if (p) + freeLists[b] = *(void **)p; + else + p = moreStructs(b); + +#ifdef FAST_ALLOC_STATS + ++newCount[b]; +#endif + + return p; +} + + +inline +void FastAlloc::deallocate(void *p, size_t sz) +{ + int b; + + if (sz > Max_Alloc_Size) + { + ::delete [] (char *)p; + return; + } + + b = bucketFor(sz); + *(void **)p = freeLists[b]; + freeLists[b] = p; +#ifdef FAST_ALLOC_STATS + ++deleteCount[b]; +#endif +} + + +inline +void *FastAlloc::operator new(size_t sz) +{ + return allocate(sz); +} + + +inline +void FastAlloc::operator delete(void *p, size_t sz) +{ + deallocate(p, sz); +} + +#endif // __FAST_ALLOC_H__ diff --git a/base/fifo_buffer.cc b/base/fifo_buffer.cc new file mode 100644 index 000000000..d0b59e832 --- /dev/null +++ b/base/fifo_buffer.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fifo_buffer.hh" + +template<class T> +void +FifoBuffer<T>::dump(void) +{ + if (buffer->count() > 0) + for (iterator i=buffer->tail(); i.notnull(); i=i.prev()) + i->dump(); +} + + diff --git a/base/fifo_buffer.hh b/base/fifo_buffer.hh new file mode 100644 index 000000000..27b4973ac --- /dev/null +++ b/base/fifo_buffer.hh @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __FIFO_BUFFER_HH__ +#define __FIFO_BUFFER_HH__ + +#include "res_list.hh" + + +// +// The FifoBuffer requires only that the objects to be used have a default +// constructor and a dump() method +// +template<class T> +class FifoBuffer { + public: + typedef typename res_list<T>::iterator iterator; + + private: + res_list<T> *buffer; + + unsigned size; + + public: + FifoBuffer(unsigned sz) + { + buffer = new res_list<T>(sz, true, 0); + size = sz; + } + + void add(T &item) + { + assert(buffer->num_free() > 0); + buffer->add_head(item); + } + + iterator head(void) { return buffer->head(); } + iterator tail(void) { return buffer->tail(); } + + unsigned count(void) {return buffer->count();} + unsigned free_slots(void) {return buffer->num_free();} + + T * peek(void) + { + if (count() > 0) { + return tail().data_ptr(); + } + else { + return 0; + } + } + + T remove(void) + { + assert(buffer->count() > 0); + T rval = *buffer->tail(); + buffer->remove_tail(); + return rval; + } + + void dump(void); + + ~FifoBuffer() { delete buffer; } +}; + + +#endif + diff --git a/base/hashmap.hh b/base/hashmap.hh new file mode 100644 index 000000000..21d4a818e --- /dev/null +++ b/base/hashmap.hh @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __HASHMAP_HH__ +#define __HASHMAP_HH__ + +#if defined(__GNUC__) && __GNUC__ >= 3 +#include <ext/hash_map> +#else +#include <hash_map> +#endif + +#include <string> + +#include "host.hh" + +#if defined(__GNUC__) && __GNUC__ >= 3 + #define __hash_namespace __gnu_cxx +#else + #define __hash_namespace std +#endif + +namespace m5 { + using ::__hash_namespace::hash_multimap; + using ::__hash_namespace::hash_map; + using ::__hash_namespace::hash; +} + + +/////////////////////////////////// +// Some default Hashing Functions +// + +namespace __hash_namespace { + template<> + struct hash<uint64_t> { + size_t operator()(uint64_t r) const { + return r; + } + }; + + template<> + struct hash<Counter> { + size_t operator()(Counter r) const { + return r; + }; + }; + + template<> + struct hash<std::string> { + size_t operator()(const std::string &s) const { + return(__stl_hash_string(s.c_str())); + } + }; +} + + +#endif // __HASHMAP_HH__ diff --git a/base/inet.cc b/base/inet.cc new file mode 100644 index 000000000..33483bb32 --- /dev/null +++ b/base/inet.cc @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sstream> +#include <string> + +#include "cprintf.hh" +#include "host.hh" +#include "inet.hh" + +using namespace::std; +string +eaddr_string(const uint8_t a[6]) +{ + stringstream stream; + ccprintf(stream, "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]); + + return stream.str(); +} + +/* + * Copyright (c) 1988, 1992, 1993 + * The Regents of the University of California. 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 disclaimer. + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/*********************************************************************** + This section of code taken from NetBSD +***********************************************************************/ + +#define ETHER_CRC_POLY_LE 0xedb88320 +#define ETHER_CRC_POLY_BE 0x04c11db6 + +#if 0 +/* + * This is for reference. We have a table-driven version + * of the little-endian crc32 generator, which is faster + * than the double-loop. + */ +uint32_t +crc32le(const uint8_t *buf, size_t len) +{ + uint32_t c, crc, carry; + size_t i, j; + + crc = 0xffffffffU; /* initial value */ + + for (i = 0; i < len; i++) { + c = buf[i]; + for (j = 0; j < 8; j++) { + carry = ((crc & 0x01) ? 1 : 0) ^ (c & 0x01); + crc >>= 1; + c >>= 1; + if (carry) + crc = (crc ^ ETHER_CRC_POLY_LE); + } + } + + return (crc); +} +#else +uint32_t +crc32le(const uint8_t *buf, size_t len) +{ + static const uint32_t crctab[] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + uint32_t crc; + int i; + + crc = 0xffffffffU; /* initial value */ + + for (i = 0; i < len; i++) { + crc ^= buf[i]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + } + + return (crc); +} +#endif + +uint32_t +crc32be(const uint8_t *buf, size_t len) +{ + uint32_t c, crc, carry; + size_t i, j; + + crc = 0xffffffffU; /* initial value */ + + for (i = 0; i < len; i++) { + c = buf[i]; + for (j = 0; j < 8; j++) { + carry = ((crc & 0x80000000U) ? 1 : 0) ^ (c & 0x01); + crc <<= 1; + c >>= 1; + if (carry) + crc = (crc ^ ETHER_CRC_POLY_BE) | carry; + } + } + + return (crc); +} + +/*********************************************************************** + This is the end of the NetBSD code +***********************************************************************/ diff --git a/base/inet.hh b/base/inet.hh new file mode 100644 index 000000000..1c48d0730 --- /dev/null +++ b/base/inet.hh @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __INET_HH__ +#define __INET_HH__ + +#include "host.hh" + +uint32_t crc32be(const uint8_t *buf, size_t len); +uint32_t crc32le(const uint8_t *buf, size_t len); +std::string eaddr_string(const uint8_t a[6]); +#endif // __INET_HH__ diff --git a/base/inifile.cc b/base/inifile.cc new file mode 100644 index 000000000..3f80ec259 --- /dev/null +++ b/base/inifile.cc @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define USE_CPP +// #define CPP_PIPE + + +#ifdef USE_CPP +#include <sys/signal.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#endif + +#include <fstream> +#include <iostream> +#if __GNUC__ >= 3 +#include <ext/stdio_filebuf.h> +#endif + +#include <vector> +#include <string> + +#include "inifile.hh" +#include "str.hh" + +using namespace std; + +IniFile::IniFile() +{} + +IniFile::~IniFile() +{ + ConfigTable::iterator i = table.begin(); + ConfigTable::iterator end = table.end(); + + while (i != end) { + delete (*i).second; + ++i; + } +} + + +#ifdef USE_CPP +bool +IniFile::loadCPP(const string &file, vector<char *> &cppArgs) +{ + int fd[2]; + +#ifdef CPP_PIPE + if (pipe(fd) == -1) + return false; +#else + char tempfile[] = "/tmp/configXXXXXX"; + fd[0] = fd[1] = mkstemp(tempfile); +#endif + + int pid = fork(); + + if (pid == -1) + return 1; + + if (pid == 0) { + char filename[FILENAME_MAX]; + string::size_type i = file.copy(filename, sizeof(filename) - 1); + filename[i] = '\0'; + + int arg_count = cppArgs.size(); + + char **args = new char *[arg_count + 20]; + + int nextArg = 0; + args[nextArg++] = "g++"; + args[nextArg++] = "-E"; + args[nextArg++] = "-P"; + args[nextArg++] = "-nostdinc"; + args[nextArg++] = "-nostdinc++"; + args[nextArg++] = "-x"; + args[nextArg++] = "c++"; + args[nextArg++] = "-undef"; + + for (int i = 0; i < arg_count; i++) + args[nextArg++] = cppArgs[i]; + + args[nextArg++] = filename; + args[nextArg++] = NULL; + + close(STDOUT_FILENO); + if (dup2(fd[1], STDOUT_FILENO) == -1) + return 1; + + execvp("g++", args); + + exit(1); + } + + int retval; + waitpid(pid, &retval, 0); + + // check for normal completion of CPP + if (!WIFEXITED(retval) || WEXITSTATUS(retval) != 0) + return false; + +#ifdef CPP_PIPE + close(fd[1]); +#else + lseek(fd[0], 0, SEEK_SET); +#endif + + bool status = false; + +#if __GNUC__ >= 3 + using namespace __gnu_cxx; + stdio_filebuf<char> fbuf(fd[0], ios_base::in, true, + static_cast<stdio_filebuf<char>::int_type>(BUFSIZ)); + + if (fbuf.is_open()) { + istream f(&fbuf); + status = load(f); + } + +#else + ifstream f(fd[0]); + if (f.is_open()) + status = load(f); +#endif + +#ifndef CPP_PIPE + unlink(tempfile); +#endif + + return status; +} +#endif + +bool +IniFile::load(const string &file) +{ + ifstream f(file.c_str()); + + if (!f.is_open()) + return false; + + return load(f); +} + + +const string & +IniFile::Entry::getValue() const +{ + referenced = true; + return value; +} + + +void +IniFile::Section::addEntry(const std::string &entryName, + const std::string &value) +{ + EntryTable::iterator ei = table.find(entryName); + + if (ei == table.end()) { + // new entry + table[entryName] = new Entry(value); + } + else { + // override old entry + ei->second->setValue(value); + } +} + + +IniFile::Entry * +IniFile::Section::findEntry(const std::string &entryName) const +{ + referenced = true; + + EntryTable::const_iterator ei = table.find(entryName); + + return (ei == table.end()) ? NULL : ei->second; +} + + +IniFile::Section * +IniFile::addSection(const string §ionName) +{ + ConfigTable::iterator ci = table.find(sectionName); + + if (ci != table.end()) { + return ci->second; + } + else { + // new entry + Section *sec = new Section(); + table[sectionName] = sec; + return sec; + } +} + + +IniFile::Section * +IniFile::findSection(const string §ionName) const +{ + ConfigTable::const_iterator ci = table.find(sectionName); + + return (ci == table.end()) ? NULL : ci->second; +} + + +// Take string of the form "<section>:<parameter>=<value>" and add to +// database. Return true if successful, false if parse error. +bool +IniFile::add(const string &str) +{ + // find ':' + string::size_type offset = str.find(':'); + if (offset == string::npos) // no ':' found + return false; + + string sectionName = str.substr(0, offset); + string rest = str.substr(offset + 1); + + offset = rest.find('='); + if (offset == string::npos) // no '='found + return false; + + string entryName = rest.substr(0, offset); + string value = rest.substr(offset + 1); + + eat_white(sectionName); + eat_white(entryName); + eat_white(value); + + Section *s = addSection(sectionName); + s->addEntry(entryName, value); + + return true; +} + +bool +IniFile::load(istream &f) +{ + Section *section = NULL; + + while (!f.eof()) { + f >> ws; // Eat whitespace + if (f.eof()) { + break; + } + + string line; + getline(f, line); + if (line.size() == 0) + continue; + + eat_end_white(line); + int last = line.size() - 1; + + if (line[0] == '[' && line[last] == ']') { + string sectionName = line.substr(1, last - 1); + eat_white(sectionName); + section = addSection(sectionName); + continue; + } + + if (section == NULL) + continue; + + string::size_type offset = line.find('='); + string entryName = line.substr(0, offset); + string value = line.substr(offset + 1); + + eat_white(entryName); + eat_white(value); + + section->addEntry(entryName, value); + } + + return true; +} + +bool +IniFile::find(const string §ionName, const string &entryName, + string &value) const +{ + Section *section = findSection(sectionName); + if (section == NULL) + return false; + + Entry *entry = section->findEntry(entryName); + if (entry == NULL) + return false; + + value = entry->getValue(); + + return true; +} + +bool +IniFile::findDefault(const string &_section, const string &entry, + string &value) const +{ + string section = _section; + while (!find(section, entry, value)) { + if (!find(section, "default", section)) + return false; + } + + return true; +} + + +bool +IniFile::Section::printUnreferenced(const string §ionName) +{ + bool unref = false; + bool search_unref_entries = false; + vector<string> unref_ok_entries; + + Entry *entry = findEntry("unref_entries_ok"); + if (entry != NULL) { + tokenize(unref_ok_entries, entry->getValue(), ' '); + if (unref_ok_entries.size()) { + search_unref_entries = true; + } + } + + for (EntryTable::iterator ei = table.begin(); + ei != table.end(); ++ei) { + const string &entryName = ei->first; + Entry *entry = ei->second; + + if (entryName == "unref_section_ok" || + entryName == "unref_entries_ok") + { + continue; + } + + if (!entry->isReferenced()) { + if (search_unref_entries && + (std::find(unref_ok_entries.begin(), unref_ok_entries.end(), + entryName) != unref_ok_entries.end())) + { + continue; + } + + cerr << "Parameter " << sectionName << ":" << entryName + << " not referenced." << endl; + unref = true; + } + } + + return unref; +} + + +bool +IniFile::printUnreferenced() +{ + bool unref = false; + + for (ConfigTable::iterator ci = table.begin(); + ci != table.end(); ++ci) { + const string §ionName = ci->first; + Section *section = ci->second; + + if (!section->isReferenced()) { + if (section->findEntry("unref_section_ok") == NULL) { + cerr << "Section " << sectionName << " not referenced." + << endl; + unref = true; + } + } + else { +#if 0 + if (section->findEntry("unref_entries_ok") == NULL) { + bool unrefEntries = section->printUnreferenced(sectionName); + unref = unref || unrefEntries; + } +#else + if (section->printUnreferenced(sectionName)) { + unref = true; + } +#endif + } + } + + return unref; +} + + +void +IniFile::Section::dump(const string §ionName) +{ + for (EntryTable::iterator ei = table.begin(); + ei != table.end(); ++ei) { + cout << sectionName << ": " << (*ei).first << " => " + << (*ei).second << "\n"; + } +} + +void +IniFile::dump() +{ + for (ConfigTable::iterator ci = table.begin(); + ci != table.end(); ++ci) { + ci->second->dump(ci->first); + } +} diff --git a/base/inifile.hh b/base/inifile.hh new file mode 100644 index 000000000..b384fe21a --- /dev/null +++ b/base/inifile.hh @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __INIFILE_HH__ +#define __INIFILE_HH__ + +#include <fstream> +#include <list> +#include <string> +#include <vector> + +#include "hashmap.hh" + +class IniFile +{ + protected: + class Entry + { + std::string value; + mutable bool referenced; + + public: + Entry(const std::string &v) + : value(v), referenced(false) + { + } + + bool isReferenced() { return referenced; } + + const std::string &getValue() const; + + void setValue(const std::string &v) { value = v; } + }; + + class Section + { + typedef m5::hash_map<std::string, Entry *> EntryTable; + + EntryTable table; + mutable bool referenced; + + public: + Section() + : table(), referenced(false) + { + } + + bool isReferenced() { return referenced; } + + void addEntry(const std::string &entryName, const std::string &value); + Entry *findEntry(const std::string &entryName) const; + + bool printUnreferenced(const std::string §ionName); + void dump(const std::string §ionName); + }; + + typedef m5::hash_map<std::string, Section *> ConfigTable; + + protected: + ConfigTable table; + + Section *addSection(const std::string §ionName); + Section *findSection(const std::string §ionName) const; + + bool load(std::istream &f); + + public: + IniFile(); + ~IniFile(); + + bool loadCPP(const std::string &file, std::vector<char *> &cppFlags); + bool load(const std::string &file); + + bool add(const std::string &s); + + bool find(const std::string §ion, const std::string &entry, + std::string &value) const; + bool findDefault(const std::string §ion, const std::string &entry, + std::string &value) const; + + bool printUnreferenced(); + + void dump(); +}; + +#endif // __INIFILE_HH__ diff --git a/base/intmath.cc b/base/intmath.cc new file mode 100644 index 000000000..8d08e59a8 --- /dev/null +++ b/base/intmath.cc @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "intmath.h" + +int +PrevPrime(int n) +{ + int decr; + + // If the number is even, let's start with the previous odd number. + if (!(n & 1)) + --n; + + // Lets test for divisibility by 3. Then we will be able to easily + // avoid numbers that are divisible by 3 in the future. + decr = n % 3; + if (decr == 0) { + n -= 2; + decr = 2; + } + else if (decr == 1) + decr = 4; + + for(;;) { + if (IsPrime(n)) + return n; + n -= decr; + // Toggle between 2 and 4 to prevent trying numbers that are known + // to be divisible by 3. + decr = 6 - decr; + } +} diff --git a/base/intmath.h b/base/intmath.h new file mode 100644 index 000000000..814dacd5f --- /dev/null +++ b/base/intmath.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __INTMATH_H__ +#define __INTMATH_H__ + +// Returns the prime number one less than n. +int PrevPrime(int n); + +// Determine if a number is prime +inline bool +IsPrime(int n) +{ + int i; + + if (n == 2 || n == 3) + return true; + + // Don't try every odd number to prove if it is a prime. + // Toggle between every 2nd and 4th number. + // (This is because every 6th odd number is divisible by 3.) + for (i = 5; i*i <= n; i += 6) { + if (((n % i) == 0 ) || ((n % (i + 2)) == 0) ) { + return false; + } + } + + return true; +} + +inline unsigned +LeastSigBit(unsigned n) +{ return n & ~(n - 1); } + +inline bool +IsPowerOf2(unsigned n) +{ return n != 0 && LeastSigBit(n) == n; } + +inline int +FloorLog2(unsigned x) +{ + if (x == 0) + return -1; + + int y = 0; + + if (x & 0xffff0000) { y += 16; x >>= 16; } + if (x & 0x0000ff00) { y += 8; x >>= 8; } + if (x & 0x000000f0) { y += 4; x >>= 4; } + if (x & 0x0000000c) { y += 2; x >>= 2; } + if (x & 0x00000002) { y += 1; } + + return y; +} + +inline int +CeilLog2(unsigned n) +{ return FloorLog2(n-1)+1; } + +inline unsigned +FloorPow2(unsigned n) +{ return 1 << FloorLog2(n); } + +inline unsigned +CeilPow2(unsigned n) +{ return 1 << CeilLog2(n); } + +inline bool +IsHex(char c) +{ return (c >= '0' && c <= '9' || + c >= 'A' && c <= 'F' || + c >= 'a' && c <= 'f'); +} + +inline bool +IsOct(char c) +{ return (c >= '0' && c <= '7'); } + +inline bool +IsDec(char c) +{ return (c >= '0' && c <= '9'); } + +inline int +Hex2Int(char c) +{ + if (c >= '0' && c <= '9') + return (c - '0'); + + if(c >= 'A' && c <= 'F') + return (c - 'A') + 10; + + if (c >= 'a' && c <= 'f') + return (c - 'a') + 10; + + return 0; +} + +#endif // __INTMATH_H__ diff --git a/base/kgdb.h b/base/kgdb.h new file mode 100644 index 000000000..35f74f4ba --- /dev/null +++ b/base/kgdb.h @@ -0,0 +1,203 @@ +/* $Id$ */ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * 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 disclaimer. + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)remote-sl.h 8.1 (Berkeley) 6/11/93 + */ + +/* $NetBSD: kgdb.h,v 1.4 1998/08/13 02:10:59 eeh Exp $ */ + +#ifndef __KGDB_H__ +#define __KGDB_H__ + +/* + * Message types. + */ +#define KGDB_SIGNAL '?' // last sigal +#define KGDB_SET_BAUD 'b' // set baud (deprecated) +#define KGDB_SET_BREAK 'B' // set breakpoint (deprecated) +#define KGDB_CONT 'c' // resume +#define KGDB_ASYNC_CONT 'C' // continue with signal +#define KGDB_DEBUG 'd' // toggle debug flags (deprecated) +#define KGDB_DETACH 'D' // detach remote gdb +#define KGDB_REG_R 'g' // read general registers +#define KGDB_REG_W 'G' // write general registers +#define KGDB_SET_THREAD 'H' // set thread +#define KGDB_CYCLE_STEP 'i' // step a single cycle +#define KGDB_SIG_CYCLE_STEP 'I' // signal then single cycle step +#define KGDB_KILL 'k' // kill program +#define KGDB_MEM_R 'm' // read memory +#define KGDB_MEM_W 'M' // write memory +#define KGDB_READ_REG 'p' // read register +#define KGDB_SET_REG 'P' // write register +#define KGDB_QUERY_VAR 'q' // query variable +#define KGDB_SET_VAR 'Q' // set variable +#define KGDB_RESET 'r' // reset system. (Deprecated) +#define KGDB_STEP 's' // step +#define KGDB_ASYNC_STEP 'S' // signal and step +#define KGDB_THREAD_ALIVE 'T' // find out if the thread is alive. +#define KGDB_TARGET_EXIT 'W' // target exited +#define KGDB_BINARY_DLOAD 'X' // write memory +#define KGDB_CLR_HW_BKPT 'z' // remove breakpoint or watchpoint +#define KGDB_SET_HW_BKPT 'Z' // insert breakpoint or watchpoint + +/* + * start of frame/end of frame + */ +#define KGDB_START '$' +#define KGDB_END '#' +#define KGDB_GOODP '+' +#define KGDB_BADP '-' + +/* + * Stuff for KGDB. + */ +#define KGDB_NUMREGS 66 /* from tm-alpha.h, NUM_REGS */ +#define KGDB_REG_V0 0 +#define KGDB_REG_T0 1 +#define KGDB_REG_T1 2 +#define KGDB_REG_T2 3 +#define KGDB_REG_T3 4 +#define KGDB_REG_T4 5 +#define KGDB_REG_T5 6 +#define KGDB_REG_T6 7 +#define KGDB_REG_T7 8 +#define KGDB_REG_S0 9 +#define KGDB_REG_S1 10 +#define KGDB_REG_S2 11 +#define KGDB_REG_S3 12 +#define KGDB_REG_S4 13 +#define KGDB_REG_S5 14 +#define KGDB_REG_S6 15 /* FP */ +#define KGDB_REG_A0 16 +#define KGDB_REG_A1 17 +#define KGDB_REG_A2 18 +#define KGDB_REG_A3 19 +#define KGDB_REG_A4 20 +#define KGDB_REG_A5 21 +#define KGDB_REG_T8 22 +#define KGDB_REG_T9 23 +#define KGDB_REG_T10 24 +#define KGDB_REG_T11 25 +#define KGDB_REG_RA 26 +#define KGDB_REG_T12 27 +#define KGDB_REG_AT 28 +#define KGDB_REG_GP 29 +#define KGDB_REG_SP 30 +#define KGDB_REG_ZERO 31 +#define KGDB_REG_F0 32 +#define KGDB_REG_F1 33 +#define KGDB_REG_F2 34 +#define KGDB_REG_F3 35 +#define KGDB_REG_F4 36 +#define KGDB_REG_F5 37 +#define KGDB_REG_F6 38 +#define KGDB_REG_F7 39 +#define KGDB_REG_F8 40 +#define KGDB_REG_F9 41 +#define KGDB_REG_F10 42 +#define KGDB_REG_F11 43 +#define KGDB_REG_F12 44 +#define KGDB_REG_F13 45 +#define KGDB_REG_F14 46 +#define KGDB_REG_F15 47 +#define KGDB_REG_F16 48 +#define KGDB_REG_F17 49 +#define KGDB_REG_F18 50 +#define KGDB_REG_F19 51 +#define KGDB_REG_F20 52 +#define KGDB_REG_F21 53 +#define KGDB_REG_F22 54 +#define KGDB_REG_F23 55 +#define KGDB_REG_F24 56 +#define KGDB_REG_F25 57 +#define KGDB_REG_F26 58 +#define KGDB_REG_F27 59 +#define KGDB_REG_F28 60 +#define KGDB_REG_F29 61 +#define KGDB_REG_F30 62 +#define KGDB_REG_F31 63 +#define KGDB_REG_PC 64 +#define KGDB_REG_VFP 65 + +/* Too much? Must be large enough for register transfer. */ +#define KGDB_BUFLEN 1024 + +/* + * Kernel Entry Vectors. [OSF/1 PALcode Specific] + */ + +#define ALPHA_KENTRY_INT 0 +#define ALPHA_KENTRY_ARITH 1 +#define ALPHA_KENTRY_MM 2 +#define ALPHA_KENTRY_IF 3 +#define ALPHA_KENTRY_UNA 4 +#define ALPHA_KENTRY_SYS 5 + +/* + * MMCSR Fault Type Codes. [OSF/1 PALcode Specific] + */ + +#define ALPHA_MMCSR_INVALTRANS 0 +#define ALPHA_MMCSR_ACCESS 1 +#define ALPHA_MMCSR_FOR 2 +#define ALPHA_MMCSR_FOE 3 +#define ALPHA_MMCSR_FOW 4 + +/* + * Instruction Fault Type Codes. [OSF/1 PALcode Specific] + */ + +#define ALPHA_IF_CODE_BPT 0 +#define ALPHA_IF_CODE_BUGCHK 1 +#define ALPHA_IF_CODE_GENTRAP 2 +#define ALPHA_IF_CODE_FEN 3 +#define ALPHA_IF_CODE_OPDEC 4 + +#define BKPT_INST 0x00000080 // breakpoint instruction +#define BKPT_SIZE (4) // size of breakpoint inst + +#define IS_BREAKPOINT_TRAP(type, code) ((type) == ALPHA_KENTRY_IF && \ + (code) == ALPHA_IF_CODE_BPT) +#define IS_WATCHPOINT_TRAP(type, code) 0 + + +#endif /* __KGDB_H__ */ diff --git a/base/misc.cc b/base/misc.cc new file mode 100644 index 000000000..0ce9f7be9 --- /dev/null +++ b/base/misc.cc @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <iostream> +#include <string> + +#include "host.hh" +#include "cprintf.hh" +#include "misc.hh" +#include "universe.hh" +#include "trace.hh" + +using namespace std; + +void +__panic(const string &format, cp::ArgList &args, const char *func, + const char *file, int line) +{ + string fmt = "panic: " + format + " [%s:%s, line %d]\n"; + args.append(func); + args.append(file); + args.append(line); + args.dump(cerr, fmt); + + delete &args; + +#if TRACING_ON + // dump trace buffer, if there is one + Trace::theLog.dump(cerr); +#endif + + abort(); +} + +void +__fatal(const string &format, cp::ArgList &args, const char *func, + const char *file, int line) +{ + long mem_usage(); + + string fmt = "fatal: " + format + " [%s:%s, line %d]\n" + "\n%d\nMemory Usage: %ld KBytes\n"; + + args.append(func); + args.append(file); + args.append(line); + args.append(curTick); + args.append(mem_usage()); + args.dump(cerr, fmt); + + delete &args; + + exit(1); +} + +void +__warn(const string &format, cp::ArgList &args, const char *func, + const char *file, int line) +{ + string fmt = "warn: " + format; +#ifdef VERBOSE_WARN + fmt += " [%s:%s, line %d]\n"; + args.append(func); + args.append(file); + args.append(line); +#else + fmt += "\n"; +#endif + args.dump(cerr, fmt); + + delete &args; +} diff --git a/base/misc.hh b/base/misc.hh new file mode 100644 index 000000000..3ac4d1491 --- /dev/null +++ b/base/misc.hh @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MISC_HH__ +#define __MISC_HH__ + +#include <assert.h> +#include "cprintf.hh" + +// +// This implements a cprintf based panic +// +void __panic(const std::string&, cp::ArgList &, const char*, const char*, int) + __attribute__((noreturn)); +#define __panic__(format, args...) \ + __panic(format, (*(new cp::ArgList), args), \ + __FUNCTION__, __FILE__, __LINE__) +#define panic(args...) \ + __panic__(args, cp::ArgListNull()) + +// +// This implements a cprintf based fatal +// +void __fatal(const std::string&, cp::ArgList &, const char*, const char*, int) + __attribute__((noreturn)); +#define __fatal__(format, args...) \ + __fatal(format, (*(new cp::ArgList), args), \ + __FUNCTION__, __FILE__, __LINE__) +#define fatal(args...) \ + __fatal__(args, cp::ArgListNull()) + +// +// This implements a cprintf based warn +// +void __warn(const std::string&, cp::ArgList &, const char*, const char*, int); +#define __warn__(format, args...) \ + __warn(format, (*(new cp::ArgList), args), \ + __FUNCTION__, __FILE__, __LINE__) +#define warn(args...) \ + __warn__(args, cp::ArgListNull()) + +// +// assert() that prints out the current cycle +// +#define m5_assert(TEST) \ + if (!(TEST)) { \ + std::cerr << "Assertion failure, curTick = " << curTick << std::endl; \ + } \ + assert(TEST); + +#endif // __MISC_HH__ diff --git a/base/mod_num.hh b/base/mod_num.hh new file mode 100644 index 000000000..3b4ef9bb8 --- /dev/null +++ b/base/mod_num.hh @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +template<class T, T MV> +class ModNum { + private: + T value; + + // Compiler should optimize this + void setValue(T n) { value = n % MV; } + + public: + ModNum() {} + ModNum(T n) { setValue(n); } + ModNum(const ModNum<T, MV> &n) : value(n.value) {} + + ModNum operator=(T n) { + setValue(n); + return *this; + } + + const ModNum operator=(ModNum n) { + value = n.value; + return *this; + } + + // Return the value if object used as RHS + operator T() const { return value; } + + // + // Operator "+=" + // + const ModNum<T, MV> operator+=(ModNum<T, MV> r) { + setValue(value + r.value); + return *this; + } + + const ModNum<T, MV> operator+=(T r) { + setValue(value + r); + return *this; + } + + // + // Operator "-=" + // + const ModNum<T, MV> operator-=(ModNum<T, MV> r) { + setValue(value - r.value); + return *this; + } + + const ModNum<T, MV> operator-=(T r) { + setValue(value - r); + return *this; + } + + // + // Operator "++" + // + // PREFIX (like ++a) + const ModNum<T, MV> operator++() { + *this += 1; + return *this; + } + + // POSTFIX (like a++) + const ModNum<T, MV> operator++(int) { + ModNum<T, MV> rv = *this; + + *this += 1; + + return rv; + } + + // + // Operator "--" + // + // PREFIX (like --a) + const ModNum<T, MV> operator--() { + *this -= 1; + return *this; + } + + // POSTFIX (like a--) + const ModNum<T, MV> operator--(int) { + ModNum<T, MV> rv = *this; + *this -= 1; + return rv; + } +}; + + +// +// Define operator "+" like this to avoid creating a temporary +// +template<class T, T MV> +inline ModNum<T, MV> +operator+(ModNum<T, MV> l, ModNum<T, MV> r) { + l += r; + return l; +} + +template<class T, T MV> +inline ModNum<T, MV> +operator+(ModNum<T, MV> l, T r) { + l += r; + return l; +} + +template<class T, T MV> +inline ModNum<T, MV> +operator+(T l, ModNum<T, MV> r) { + r += l; + return r; +} + + +// +// Define operator "-" like this to avoid creating a temporary +// +template<class T, T MV> +inline ModNum<T, MV> +operator-(ModNum<T, MV> l, ModNum<T, MV> r) { + l -= r; + return l; +} + +template<class T, T MV> +inline ModNum<T, MV> +operator-(ModNum<T, MV> l, T r) { + l -= r; + return l; +} + +template<class T, T MV> +inline ModNum<T, MV> +operator-(T l, ModNum<T, MV> r) { + r -= l; + return r; +} + + +// +// Comparison operators +// (all other cases are handled with conversons) +// +template<class T, T MV> +inline bool +operator<(ModNum<T, MV> l, ModNum<T, MV> r) { + return l.value < r.value; +} + +template<class T, T MV> +inline bool +operator>(ModNum<T, MV> l, ModNum<T, MV> r) { + return l.value > r.value; +} + +template<class T, T MV> +inline bool +operator==(ModNum<T, MV> l, ModNum<T, MV> r) { + return l.value == r.value; +} + +template<class T, T MV> +inline bool +operator<=(ModNum<T, MV> l, ModNum<T, MV> r) { + return l.value <= r.value; +} + +template<class T, T MV> +inline bool +operator>=(ModNum<T, MV> l, ModNum<T, MV> r) { + return l.value >= r.value; +} + + diff --git a/base/object_file.cc b/base/object_file.cc new file mode 100644 index 000000000..b9542f280 --- /dev/null +++ b/base/object_file.cc @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <list> +#include <string> + +#include <sys/types.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> + +#include "cprintf.hh" +#include "ecoff.hh" +#include "object_file.hh" +#include "symtab.hh" + +using namespace std; + +ObjectFile::ObjectFile() + : descriptor(-1), data(NULL) +{} + +ObjectFile::ObjectFile(string file) + : descriptor(-1), data(NULL) +{ open(file); } + +ObjectFile::~ObjectFile() +{ close(); } + +bool +ObjectFile::open(string file_name) +{ + close(); + + name = file_name; + + descriptor = ::open(name.c_str(), O_RDONLY); + if (descriptor < 0) + return false; + + len = (size_t)::lseek(descriptor, 0, SEEK_END); + + data = (uint8_t *)::mmap(NULL, len, PROT_READ, MAP_SHARED, descriptor, 0); + if (data == MAP_FAILED) + return false; + + postOpen(); + + return true; +} + +void +ObjectFile::close() +{ + if (descriptor >= 0) + ::close(descriptor); + + if (data) + ::munmap(data, len); +} + +void +EcoffObject::postOpen() +{ + exec = &(((EcoffExecHeader *)data)->f); + aout = &(((EcoffExecHeader *)data)->a); + + text_off = aout->text_start; + data_off = aout->data_start; + bss_off = aout->bss_start; + + text_size = aout->tsize; + data_size = aout->dsize; + bss_size = aout->bsize; +} + +bool +EcoffObject::loadGlobals(SymbolTable *symtab) +{ + if (!symtab) + return false; + + if (exec->f_magic != ALPHAMAGIC) { + cprintf("wrong magic\n"); + return false; + } + + EcoffSymHeader *syms = (EcoffSymHeader *)(data + exec->f_symptr); + if (syms->magic != ECOFF_SYM_MAGIC) { + cprintf("bad symbol header magic\n"); + exit(1); + } + + EcoffExtSymEntry *ext_syms = + (EcoffExtSymEntry *)(data + syms->cbExtOffset); + + char *ext_strings = (char *)(data + syms->cbSsExtOffset); + for (int i = 0; i < syms->iextMax; i++) { + EcoffSymEntry *entry = &(ext_syms[i].asym); + if (entry->iss != -1) + symtab->insert(entry->value, ext_strings + entry->iss); + } + + return true; +} + +bool +EcoffObject::loadLocals(SymbolTable *symtab) +{ + if (!symtab) + return false; + + if (exec->f_magic != ALPHAMAGIC) { + cprintf("wrong magic\n"); + return false; + } + + EcoffSymHeader *syms = (EcoffSymHeader *)(data + exec->f_symptr); + if (syms->magic != ECOFF_SYM_MAGIC) { + cprintf("bad symbol header magic\n"); + exit(1); + } + + EcoffSymEntry *local_syms = (EcoffSymEntry *)(data + syms->cbSymOffset); + char *local_strings = (char *)(data + syms->cbSsOffset); + EcoffFileDesc *fdesc = (EcoffFileDesc *)(data + syms->cbFdOffset); + + for (int i = 0; i < syms->ifdMax; i++) { + EcoffSymEntry *entry = + (EcoffSymEntry *)(local_syms + fdesc[i].isymBase); + char *strings = (char *)(local_strings + fdesc[i].issBase); + for (int j = 0; j < fdesc[i].csym; j++) { + if (entry[j].st == 1 || entry[j].st == 6) + if (entry[j].iss != -1) + symtab->insert(entry[j].value, strings + entry[j].iss); + } + } + + for (int i = 0; i < syms->isymMax; i++) { + EcoffSymEntry *entry = &(local_syms[i]); + if (entry->st == 6) + if (entry->st == 1 || entry->st == 6) + symtab->insert(entry->value, local_strings + entry->iss); + } + + return true; +} diff --git a/base/object_file.hh b/base/object_file.hh new file mode 100644 index 000000000..c100efc94 --- /dev/null +++ b/base/object_file.hh @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __OBJECT_FILE_HH__ +#define __OBJECT_FILE_HH__ + +#include "ecoff.hh" +#include "isa_traits.hh" // for Addr + +class SymbolTable; + +class ObjectFile +{ + protected: + std::string name; + int descriptor; + uint8_t *data; + size_t len; + + public: + ObjectFile(); + explicit ObjectFile(std::string file); + virtual ~ObjectFile(); + + bool open(std::string file); + void close(); + + virtual bool loadGlobals(SymbolTable *symtab) = 0; + virtual bool loadLocals(SymbolTable *symtab) = 0; + virtual void postOpen() = 0; + + protected: + Addr text_off; + Addr data_off; + Addr bss_off; + + size_t text_size; + size_t data_size; + size_t bss_size; + + public: + Addr textOffset() const { return text_off; } + Addr dataOffset() const { return data_off; } + Addr bssOffset() const { return bss_off; } + + size_t textSize() const { return text_size; } + size_t dataSize() const { return data_size; } + size_t bssSize() const { return bss_size; } +}; + +class EcoffObject : public ObjectFile +{ + protected: + EcoffFileHeader *exec; + EcoffAOutHeader *aout; + + public: + EcoffObject() {} + explicit EcoffObject(std::string file) { open(file); } + virtual ~EcoffObject() {} + + virtual bool loadGlobals(SymbolTable *symtab); + virtual bool loadLocals(SymbolTable *symtab); + virtual void postOpen(); +}; + +#endif // __OBJECT_FILE_HH__ diff --git a/base/pollevent.cc b/base/pollevent.cc new file mode 100644 index 000000000..fd08d4c4c --- /dev/null +++ b/base/pollevent.cc @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/ioctl.h> +#include <sys/types.h> + +#include <fcntl.h> +#include <signal.h> +#include <unistd.h> + +#include "async.hh" +#include "host.hh" +#include "misc.hh" +#include "pollevent.hh" +#include "universe.hh" + +PollQueue pollQueue; + +///////////////////////////////////////////////////// +// +PollEvent::PollEvent(int _fd, int _events) + : queue(NULL), enabled(true) +{ + pfd.fd = _fd; + pfd.events = _events; +} + +PollEvent::~PollEvent() +{ + if (queue) + queue->remove(this); +} + +void +PollEvent::disable() +{ + if (!enabled) return; + enabled = false; + + if (queue) + queue->copy(); +} + +void +PollEvent::enable() +{ + if (enabled) return; + enabled = true; + + if (queue) + queue->copy(); +} + +///////////////////////////////////////////////////// +// +PollQueue::PollQueue() + : poll_fds(NULL), max_size(0), num_fds(0) +{ } + +PollQueue::~PollQueue() +{ + removeHandler(); + for (int i = 0; i < num_fds; i++) + setupAsyncIO(poll_fds[0].fd, false); + + delete [] poll_fds; +} + +void +PollQueue::copy() +{ + eventvec_t::iterator i = events.begin(); + eventvec_t::iterator end = events.end(); + + num_fds = 0; + + while (i < end) { + if ((*i)->enabled) + poll_fds[num_fds++] = (*i)->pfd; + ++i; + } +} + +void +PollQueue::remove(PollEvent *event) +{ + eventvec_t::iterator i = events.begin(); + eventvec_t::iterator end = events.end(); + + while (i < end) { + if (*i == event) { + events.erase(i); + copy(); + event->queue = NULL; + return; + } + + ++i; + } + + panic("Event does not exist. Cannot remove."); +} + +void +PollQueue::schedule(PollEvent *event) +{ + if (event->queue) + panic("Event already scheduled!"); + + event->queue = this; + events.push_back(event); + setupAsyncIO(event->pfd.fd, true); + + // if we ran out of space in the fd array, double the capacity + // if this is the first time that we've scheduled an event, create + // the array with an initial size of 16 + if (++num_fds > max_size) { + if (max_size > 0) { + delete [] poll_fds; + max_size *= 2; + } else { + max_size = 16; + setupHandler(); + } + + poll_fds = new pollfd[max_size]; + } + + copy(); +} + +void +PollQueue::service() +{ + int ret = poll(poll_fds, num_fds, 0); + + if (ret <= 0) + return; + + for (int i = 0; i < num_fds; i++) { + int revents = poll_fds[i].revents; + if (revents) { + events[i]->process(revents); + if (--ret <= 0) + break; + } + } +} + +struct sigaction PollQueue::oldio; +struct sigaction PollQueue::oldalrm; +bool PollQueue::handler = false; + +void +PollQueue::setupAsyncIO(int fd, bool set) +{ + int flags = fcntl(fd, F_GETFL); + if (flags == -1) + panic("Could not set up async IO"); + + if (set) + flags |= FASYNC; + else + flags &= ~(FASYNC); + + if (fcntl(fd, F_SETFL, flags) == -1) + panic("Could not set up async IO"); + + if (set) { + if (fcntl(fd, F_SETOWN, getpid()) == -1) + panic("Could not set up async IO"); + } +} + +void +PollQueue::setupHandler() +{ + struct sigaction act; + + act.sa_handler = handleIO; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + if (sigaction(SIGIO, &act, &oldio) == -1) + panic("could not do sigaction"); + + act.sa_handler = handleALRM; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + if (sigaction(SIGALRM, &act, &oldalrm) == -1) + panic("could not do sigaction"); + + alarm(1); + + handler = true; +} + +void +PollQueue::removeHandler() +{ + if (sigaction(SIGIO, &oldio, NULL) == -1) + panic("could not remove handler"); + + if (sigaction(SIGIO, &oldalrm, NULL) == -1) + panic("could not remove handler"); +} + +void +PollQueue::handleIO(int sig) +{ + if (sig != SIGIO) + panic("Wrong Handler"); + + async_event = true; + async_io = true; +} + +void +PollQueue::handleALRM(int sig) +{ + if (sig != SIGALRM) + panic("Wrong Handler"); + + async_event = true; + async_alarm = true; + alarm(1); +} + diff --git a/base/pollevent.hh b/base/pollevent.hh new file mode 100644 index 000000000..57e12f549 --- /dev/null +++ b/base/pollevent.hh @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __POLLEVENT_H__ +#define __POLLEVENT_H__ + +#include <vector> +#include <poll.h> +#include "universe.hh" + +class PollEvent +{ + private: + friend class PollQueue; + + protected: + pollfd pfd; + PollQueue *queue; + bool enabled; + + public: + PollEvent(int fd, int event); + virtual ~PollEvent(); + + void disable(); + void enable(); + virtual void process(int revent) = 0; +}; + +class PollQueue +{ + private: + typedef std::vector<PollEvent *> eventvec_t; + eventvec_t events; + + pollfd *poll_fds; + int max_size; + int num_fds; + + public: + PollQueue(); + ~PollQueue(); + + void copy(); + void remove(PollEvent *event); + void schedule(PollEvent *event); + void service(); + + protected: + static bool handler; + static struct sigaction oldio; + static struct sigaction oldalrm; + + public: + static void setupAsyncIO(int fd, bool set); + static void handleIO(int); + static void handleALRM(int); + static void removeHandler(); + static void setupHandler(); +}; + +extern PollQueue pollQueue; + +#endif // __POLLEVENT_H__ diff --git a/base/random.cc b/base/random.cc new file mode 100644 index 000000000..42a169c06 --- /dev/null +++ b/base/random.cc @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <cstdlib> +#include <cmath> + +#include "param.hh" +#include "random.hh" + +using namespace std; + +class RandomContext : public ParamContext +{ + public: + RandomContext(const string &_iniSection) + : ::ParamContext(_iniSection) {} + ~RandomContext(); + + void checkParams(); +}; + +RandomContext paramContext("random"); + +Param<unsigned> +seed(¶mContext, "seed", "seed to random number generator", 1); + +void +RandomContext::checkParams() +{ + ::srandom(seed); +} + +long +getLong() +{ + return random(); +} + +// idea for generating a double from erand48 +double +getDouble() +{ + union { + uint32_t _long[2]; + uint16_t _short[4]; + }; + + _long[0] = random(); + _long[1] = random(); + + return ldexp((double) _short[0], -48) + + ldexp((double) _short[1], -32) + + ldexp((double) _short[2], -16); +} diff --git a/base/random.hh b/base/random.hh new file mode 100644 index 000000000..f1b383eda --- /dev/null +++ b/base/random.hh @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __RANDOM_HH__ +#define __RANDOM_HH__ + +#include "host.hh" + +long getLong(); +double getDouble(); + +template <typename T> +struct Random; + +struct Random<int8_t> +{ + static int8_t get() + { return getLong() & (int8_t)-1; } +}; + +struct Random<uint8_t> +{ + uint8_t get() + { return getLong() & (uint8_t)-1; } +}; + +struct Random<int16_t> +{ + int16_t get() + { return getLong() & (int16_t)-1; } +}; + +struct Random<uint16_t> +{ + uint16_t get() + { return getLong() & (uint16_t)-1; } +}; + +struct Random<int32_t> +{ + int32_t get() + { return (int32_t)getLong(); } +}; + +struct Random<uint32_t> +{ + uint32_t get() + { return (uint32_t)getLong(); } +}; + +struct Random<int64_t> +{ + int64_t get() + { return (int64_t)getLong() << 32 || (uint64_t)getLong(); } +}; + +struct Random<uint64_t> +{ + uint64_t get() + { return (uint64_t)getLong() << 32 || (uint64_t)getLong(); } +}; + +struct Random<float> +{ + float get() + { return getDouble(); } +}; + +struct Random<double> +{ + double get() + { return getDouble(); } +}; + +#endif // __RANDOM_HH__ diff --git a/base/range.hh b/base/range.hh new file mode 100644 index 000000000..254e71460 --- /dev/null +++ b/base/range.hh @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __RANGE_HH__ +#define __RANGE_HH__ + +#include <assert.h> + +#include "str.hh" +#include "intmath.h" + +template<class T> +class Range +{ + private: + bool valid; + + public: + T start; + T end; + + public: + Range() {} + + Range(const Range &r) { operator=(r); } + + Range(const T& s, const T& e) + : start(s), end(e) + { + valid = (start <= end); + } + + Range(const std::string &s) { valid = parse(s); } + + ~Range() {} + + int compare(const T &p); + bool parse(const std::string &s); + const Range &operator=(const Range &r); + + bool isValid() const { return valid; } +}; + + +template<class T> +inline int +Range<T>::compare(const T &p) +{ + assert(isValid()); + + if (p < start) + return -1; + else if (p > end) + return 1; + else + return 0; +} + +// Parse a range string +// +// Ranges are in the following format: +// <range> := {<start_val>}:{<end>} +// <end> := <end_val> | +<delta> +template<class T> +inline bool +Range<T>::parse(const std::string &str) +{ + std::vector<std::string> values; + tokenize(values, str, ':'); + + T thestart, theend; + + if (values.size() != 2) + return false; + + std::string s = values[0]; + std::string e = values[1]; + + if (!to_number(s, thestart)) + return false; + + bool increment = (e[0] == '+'); + if (increment) + e = e.substr(1); + + if (!to_number(e, theend)) + return false; + + if (increment) + theend += thestart; + + start = thestart; + end = theend; + + if (start > end) + return false; + + return true; +} + + +template<class T> +inline const Range<T> & +Range<T>::operator=(const Range<T> &r) +{ + if (this != &r) { + start = r.start; + end = r.end; + + valid = r.valid; + } + else { + valid = false; + } + + return *this; +} + +template<class T> +inline std::ostream & +operator<<(std::ostream &o, const Range<T> &r) +{ + // don't currently support output of invalid ranges + assert(r.isValid()); + o << r.start << ":" << r.end; + return o; +} + +////////////////////////////////////////// +// +// Compare two ranges +// +template<class T> +inline bool +operator==(const Range<T> &l, const Range<T> &r) +{ + // ranges must both be valid to be equal + return (l.isValid() && r.isValid() && + (l.start == r.start) && (l.end == r.end)); +} + +template<class T> +inline bool +operator!=(const Range<T> &l, const Range<T> &r) +{ + // for symmetry with ==, an invalid range is not equal to any other + return (!l.isValid() || !r.isValid() || + (l.start != r.start) || (l.end != r.end)); +} + +////////////////////////////////////////// +// +// Compare position to a range +// +// - 'pos == range' indicates that position pos is within the given range. +// This test always returns false if the range is invalid. +// +// - 'pos < range' and 'pos > range' indicate that the position is +// before the start of or after the end of the range, respectively. +// The range must be valid for these comparisons to be made. +// +// All other comparisons do the obvious thing based on these definitions. +// +// + +// +// Basic comparisons +// +template<class T> +inline bool +operator==(const T &pos, const Range<T> &range) +{ return range.isValid() && pos >= range.start && pos <= range.end; } + +template<class T> +inline bool +operator<(const T &pos, const Range<T> &range) +{ assert(range.isValid()); return pos < range.start; } + +template<class T> +inline bool +operator>(const T &pos, const Range<T> &range) +{ assert(range.isValid()); return pos > range.end; } + +// +// Derived comparisons +// +template<class T> +inline bool +operator<=(const T &pos, const Range<T> &range) +{ assert(range.isValid()); return pos <= range.end; } + +template<class T> +inline bool +operator>=(const T &pos, const Range<T> &range) +{ assert(range.isValid()); return pos >= range.start; } + +template<class T> +inline bool +operator!=(const T &pos, const Range<T> &range) +{ return !(pos == range); } + +// +// Define symmetric comparisons based on above +// +template<class T> +inline bool +operator>(const Range<T> &range, const T &pos) +{ return pos < range; } + +template<class T> +inline bool +operator<(const Range<T> &range, const T &pos) +{ return pos > range; } + +template<class T> +inline bool +operator<=(const Range<T> &range, const T &pos) +{ return pos >= range; } + +template<class T> +inline bool +operator>=(const Range<T> &range, const T &pos) +{ return pos <= range; } + +template<class T> +inline bool +operator==(const Range<T> &range, const T &pos) +{ return (pos == range); } + +template<class T> +inline bool +operator!=(const Range<T> &range, const T &pos) +{ return (pos != range); } + +#endif // __RANGE_HH__ diff --git a/base/refcnt.hh b/base/refcnt.hh new file mode 100644 index 000000000..5bc62ae23 --- /dev/null +++ b/base/refcnt.hh @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __REFCNT_HH__ +#define __REFCNT_HH__ + +class RefCounted +{ + private: + int count; + + private: + RefCounted(const RefCounted &); + + public: + RefCounted() : count(0) {} + virtual ~RefCounted() {} + + void incref() { ++count; } + void decref() { if (--count <= 0) delete this; } +}; + +template <class T> +class RefCountingPtr +{ + private: + T *data; + + void copy(T *d) { + data = d; + if (data) + data->incref(); + } + void del() { + if (data) + data->decref(); + } + + public: + RefCountingPtr() : data(NULL) {} + RefCountingPtr(T *data) { copy(data); } + RefCountingPtr(const RefCountingPtr& r) { copy(r.data); } + ~RefCountingPtr() { del(); } + + T *operator->() { return data; } + T &operator*() { return *data; } + T *get() { return data; } + + const T *operator->() const { return data; } + const T &operator*() const { return *data; } + const T *get() const { return data; } + + RefCountingPtr &operator=(T *p) { + if (data != p) { + del(); + copy(p); + } + return *this; + } + + RefCountingPtr &operator=(const RefCountingPtr& r) { + if (data != r.data) { + del(); + copy(r.data); + } + return *this; + } + + bool operator!() const { return data == 0; } + operator bool() const { return data != 0; } +}; + +template<class T> +bool operator==(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r) +{ return l.get() == r.get(); } + +template<class T> +bool operator==(const RefCountingPtr<T> &l, const T *r) +{ return l.get() == r; } + +template<class T> +bool operator==(const T &l, const RefCountingPtr<T> &r) +{ return l == r.get(); } + +template<class T> +bool operator!=(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r) +{ return l.get() != r.get(); } + +template<class T> +bool operator!=(const RefCountingPtr<T> &l, const T *r) +{ return l.get() != r; } + +template<class T> +bool operator!=(const T &l, const RefCountingPtr<T> &r) +{ return l != r.get(); } + +#endif // __REFCNT_HH__ diff --git a/base/remote_gdb.cc b/base/remote_gdb.cc new file mode 100644 index 000000000..5a6987877 --- /dev/null +++ b/base/remote_gdb.cc @@ -0,0 +1,1150 @@ +/* $Id$ */ +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * 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 disclaimer. + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 + */ + +/*- + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * 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 disclaimer. + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * $NetBSD: kgdb_stub.c,v 1.8 2001/07/07 22:58:00 wdk Exp $ + * + * Taken from NetBSD + * + * "Stub" to allow remote cpu to debug over a serial line using gdb. + */ + +#include <sys/signal.h> + +#include <unistd.h> + +#include <string> + +#include "exec_context.hh" +#include "intmath.h" +#include "kgdb.h" + +#include "physical_memory.hh" +#include "remote_gdb.hh" +#include "socket.hh" +#include "trace.hh" +#include "vtophys.hh" +#include "system.hh" +#include "static_inst.hh" + +using namespace std; + +#ifdef DEBUG +RemoteGDB *theDebugger = NULL; + +void +debugger() +{ + if (theDebugger) + theDebugger->trap(ALPHA_KENTRY_IF); +} +#endif + +/////////////////////////////////////////////////////////// +// +// +// + +GDBListener::Event::Event(GDBListener *l, int fd, int e) + : PollEvent(fd, e), listener(l) +{} + +void +GDBListener::Event::process(int revent) +{ + listener->accept(); +} + +GDBListener::GDBListener(RemoteGDB *g, int p) + : event(NULL), gdb(g), port(p) +{} + +GDBListener::~GDBListener() +{ + if (event) + delete event; +} + +void +GDBListener::listen() +{ + while (!listener.listen(port, true)) { + DPRINTF(RGDB, "GDBListener(listen): Can't bind port %d\n", port); + port++; + } + + cerr << "Listening for remote gdb connection on port " << port << endl; + event = new Event(this, listener.getfd(), POLLIN); + pollQueue.schedule(event); +} + +void +GDBListener::accept() +{ + if (!listener.islistening()) + panic("GDBListener(accept): cannot accept a connection if we're not listening!"); + + int sfd = listener.accept(true); + + if (sfd != -1) { + if (gdb->isattached()) + close(sfd); + else + gdb->attach(sfd); + } +} + +/////////////////////////////////////////////////////////// +// +// +// +int digit2i(char); +char i2digit(int); +void mem2hex(void *, const void *, int); +const char *hex2mem(void *, const char *, int); +Addr hex2i(const char **); + +RemoteGDB::Event::Event(RemoteGDB *g, int fd, int e) + : PollEvent(fd, e), gdb(g) +{} + +void +RemoteGDB::Event::process(int revent) +{ gdb->trap(ALPHA_KENTRY_IF); } + +RemoteGDB::RemoteGDB(System *_system, ExecContext *c) + : event(NULL), fd(-1), active(false), attached(false), + system(_system), pmem(_system->physmem), context(c) +{ +#ifdef DEBUG + theDebugger = this; +#endif + memset(gdbregs, 0, sizeof(gdbregs)); +} + +RemoteGDB::~RemoteGDB() +{ + if (event) + delete event; +} + +bool +RemoteGDB::isattached() +{ return attached; } + +void +RemoteGDB::attach(int f) +{ + fd = f; + + event = new Event(this, fd, POLLIN); + pollQueue.schedule(event); + + attached = true; + DPRINTFN("remote gdb attached\n"); +} + +void +RemoteGDB::detach() +{ + attached = false; + close(fd); + fd = -1; + + pollQueue.remove(event); + DPRINTFN("remote gdb detached\n"); +} + +const char * +gdb_command(char cmd) +{ + switch (cmd) { + case KGDB_SIGNAL: return "KGDB_SIGNAL"; + case KGDB_SET_BAUD: return "KGDB_SET_BAUD"; + case KGDB_SET_BREAK: return "KGDB_SET_BREAK"; + case KGDB_CONT: return "KGDB_CONT"; + case KGDB_ASYNC_CONT: return "KGDB_ASYNC_CONT"; + case KGDB_DEBUG: return "KGDB_DEBUG"; + case KGDB_DETACH: return "KGDB_DETACH"; + case KGDB_REG_R: return "KGDB_REG_R"; + case KGDB_REG_W: return "KGDB_REG_W"; + case KGDB_SET_THREAD: return "KGDB_SET_THREAD"; + case KGDB_CYCLE_STEP: return "KGDB_CYCLE_STEP"; + case KGDB_SIG_CYCLE_STEP: return "KGDB_SIG_CYCLE_STEP"; + case KGDB_KILL: return "KGDB_KILL"; + case KGDB_MEM_W: return "KGDB_MEM_W"; + case KGDB_MEM_R: return "KGDB_MEM_R"; + case KGDB_SET_REG: return "KGDB_SET_REG"; + case KGDB_READ_REG: return "KGDB_READ_REG"; + case KGDB_QUERY_VAR: return "KGDB_QUERY_VAR"; + case KGDB_SET_VAR: return "KGDB_SET_VAR"; + case KGDB_RESET: return "KGDB_RESET"; + case KGDB_STEP: return "KGDB_STEP"; + case KGDB_ASYNC_STEP: return "KGDB_ASYNC_STEP"; + case KGDB_THREAD_ALIVE: return "KGDB_THREAD_ALIVE"; + case KGDB_TARGET_EXIT: return "KGDB_TARGET_EXIT"; + case KGDB_BINARY_DLOAD: return "KGDB_BINARY_DLOAD"; + case KGDB_CLR_HW_BKPT: return "KGDB_CLR_HW_BKPT"; + case KGDB_SET_HW_BKPT: return "KGDB_SET_HW_BKPT"; + case KGDB_START: return "KGDB_START"; + case KGDB_END: return "KGDB_END"; + case KGDB_GOODP: return "KGDB_GOODP"; + case KGDB_BADP: return "KGDB_BADP"; + default: return "KGDB_UNKNOWN"; + } +} + +/////////////////////////////////////////////////////////// +// RemoteGDB::acc +// +// Determine if the mapping at va..(va+len) is valid. +// +bool +RemoteGDB::acc(Addr va, size_t len) +{ + Addr last_va; + Addr pte; + + va = alpha_trunc_page(va); + last_va = alpha_round_page(va + len); + + do { + if (va < ALPHA_K0SEG_BASE) { + DPRINTF(RGDB, "RGDB(acc): Mapping is invalid %#x < K0SEG\n", va); + return false; + } + + if (va < ALPHA_K1SEG_BASE) { + if (va < (ALPHA_K0SEG_BASE + pmem->getSize())) { + DPRINTF(RGDB, "RGDB(acc): Mapping is valid K0SEG <= " + "%#x < K0SEG + size\n", va); + return true; + } else { + DPRINTF(RGDB, "RGDB(acc): Mapping is invalid %#x < K0SEG\n", + va); + return false; + } + } + + Addr ptbr = context->regs.ipr[AlphaISA::IPR_PALtemp20]; + pte = kernel_pte_lookup(pmem, ptbr, va); + if (!pte || !entry_valid(pmem->phys_read_qword(pte))) { + DPRINTF(RGDB, "RGDB(acc): %#x pte is invalid\n", va); + return false; + } + va += ALPHA_PGBYTES; + } while (va < last_va); + + DPRINTF(RGDB, "RGDB(acc): %#x mapping is valid\n", va); + return true; +} + +/////////////////////////////////////////////////////////// +// RemoteGDB::signal +// +// Translate a trap number into a Unix-compatible signal number. +// (GDB only understands Unix signal numbers.) +// +int +RemoteGDB::signal(int type) +{ + switch (type) { + case ALPHA_KENTRY_UNA: + return (SIGBUS); + + case ALPHA_KENTRY_ARITH: + return (SIGFPE); + + case ALPHA_KENTRY_IF: + return (SIGILL); + + case ALPHA_KENTRY_MM: + return (SIGSEGV); + + default: + panic("unknown signal type"); + return 0; + } +} + +/////////////////////////////////////////////////////////// +// RemoteGDB::getregs +// +// Translate the kernel debugger register format into +// the GDB register format. +void +RemoteGDB::getregs() +{ + memset(gdbregs, 0, sizeof(gdbregs)); + memcpy(&gdbregs[KGDB_REG_V0], context->regs.intRegFile, 32 * sizeof(uint64_t)); +#ifdef KGDB_FP_REGS + memcpy(&gdbregs[KGDB_REG_F0], context->regs.floatRegFile.q, + 32 * sizeof(uint64_t)); +#endif + gdbregs[KGDB_REG_PC] = context->regs.pc; +} + +/////////////////////////////////////////////////////////// +// RemoteGDB::setregs +// +// Translate the GDB register format into the kernel +// debugger register format. +// +void +RemoteGDB::setregs() +{ + memcpy(context->regs.intRegFile, &gdbregs[KGDB_REG_V0], 32 * sizeof(uint64_t)); +#ifdef KGDB_FP_REGS + memcpy(context->regs.floatRegFile.q, &gdbregs[KGDB_REG_F0], + 32 * sizeof(uint64_t)); +#endif + context->regs.pc = gdbregs[KGDB_REG_PC]; +} + +void +RemoteGDB::setTempBreakpoint(TempBreakpoint &bkpt, Addr addr) +{ + DPRINTF(RGDB, "RGDB(setTempBreakpoint): addr=%#x\n", addr); + + bkpt.address = addr; + insertHardBreak(addr, 4); +} + +void +RemoteGDB::clearTempBreakpoint(TempBreakpoint &bkpt) +{ + DPRINTF(RGDB, "RGDB(setTempBreakpoint): addr=%#x\n", + bkpt.address); + + + removeHardBreak(bkpt.address, 4); + bkpt.address = 0; +} + +void +RemoteGDB::clearSingleStep() +{ + DPRINTF(RGDB, "clearSingleStep bt_addr=%#x nt_addr=%#x\n", + takenBkpt.address, notTakenBkpt.address); + + if (takenBkpt.address != 0) + clearTempBreakpoint(takenBkpt); + + if (notTakenBkpt.address != 0) + clearTempBreakpoint(notTakenBkpt); +} + +void +RemoteGDB::setSingleStep() +{ + Addr pc = context->regs.pc; + Addr npc, bpc; + bool set_bt = false; + + npc = pc + sizeof(MachInst); + + // User was stopped at pc, e.g. the instruction at pc was not + // executed. + MachInst inst = read<MachInst>(pc); + StaticInstPtr<TheISA> si(inst); + if (si->hasBranchTarget(pc, context, bpc)) { + // Don't bother setting a breakpoint on the taken branch if it + // is the same as the next pc + if (bpc != npc) + set_bt = true; + } + + DPRINTF(RGDB, "setSingleStep bt_addr=%#x nt_addr=%#x\n", + takenBkpt.address, notTakenBkpt.address); + + setTempBreakpoint(notTakenBkpt, npc); + + if (set_bt) + setTempBreakpoint(takenBkpt, bpc); +} + +///////////////////////// +// +// + +uint8_t +RemoteGDB::getbyte() +{ + uint8_t b; + ::read(fd, &b, 1); + return b; +} + +void +RemoteGDB::putbyte(uint8_t b) +{ + ::write(fd, &b, 1); +} + +// Send a packet to gdb +void +RemoteGDB::send(const char *bp) +{ + const char *p; + uint8_t csum, c; + +// DPRINTF(RGDB, "RGDB(send): %s\n", bp); + + do { + p = bp; + putbyte(KGDB_START); + for (csum = 0; (c = *p); p++) { + putbyte(c); + csum += c; + } + putbyte(KGDB_END); + putbyte(i2digit(csum >> 4)); + putbyte(i2digit(csum)); + } while ((c = getbyte() & 0x7f) == KGDB_BADP); +} + +// Receive a packet from gdb +int +RemoteGDB::recv(char *bp, int maxlen) +{ + char *p; + int c, csum; + int len; + + do { + p = bp; + csum = len = 0; + while ((c = getbyte()) != KGDB_START) + ; + + while ((c = getbyte()) != KGDB_END && len < maxlen) { + c &= 0x7f; + csum += c; + *p++ = c; + len++; + } + csum &= 0xff; + *p = '\0'; + + if (len >= maxlen) { + putbyte(KGDB_BADP); + continue; + } + + csum -= digit2i(getbyte()) * 16; + csum -= digit2i(getbyte()); + + if (csum == 0) { + putbyte(KGDB_GOODP); + // Sequence present? + if (bp[2] == ':') { + putbyte(bp[0]); + putbyte(bp[1]); + len -= 3; + bcopy(bp + 3, bp, len); + } + break; + } + putbyte(KGDB_BADP); + } while (1); + +// DPRINTF(RGDB, "RGDB(recv): %s: %s\n", gdb_command(*bp), bp); + + return (len); +} + +// Read bytes from kernel address space for debugger. +bool +RemoteGDB::read(Addr vaddr, size_t size, char *data) +{ + static Addr lastaddr = 0; + static size_t lastsize = 0; + + uint8_t *maddr; + + if (vaddr < 10) { + DPRINTF(RGDB, "\nRGDB(read): reading memory location zero!\n"); + vaddr = lastaddr + lastsize; + } + + DPRINTF(RGDB, "RGDB(read): addr=%#x, size=%d", vaddr, size); +#if TRACING_ON + char *d = data; + size_t s = size; +#endif + + lastaddr = vaddr; + lastsize = size; + + size_t count = min((Addr)size, + VMPageSize - (vaddr & (VMPageSize - 1))); + + maddr = vtomem(context, vaddr, count); + memcpy(data, maddr, count); + + vaddr += count; + data += count; + size -= count; + + while (size >= VMPageSize) { + maddr = vtomem(context, vaddr, count); + memcpy(data, maddr, VMPageSize); + + vaddr += VMPageSize; + data += VMPageSize; + size -= VMPageSize; + } + + if (size > 0) { + maddr = vtomem(context, vaddr, count); + memcpy(data, maddr, size); + } + +#if TRACING_ON + if (DTRACE(RGDB)) { + char buf[1024]; + mem2hex(buf, d, s); + cprintf(": %s\n", buf); + } +#endif + + return true; +} + +// Write bytes to kernel address space for debugger. +bool +RemoteGDB::write(Addr vaddr, size_t size, const char *data) +{ + static Addr lastaddr = 0; + static size_t lastsize = 0; + + uint8_t *maddr; + + if (vaddr < 10) { + DPRINTF(RGDB, "RGDB(write): writing memory location zero!\n"); + vaddr = lastaddr + lastsize; + } + + if (DTRACE(RGDB)) { + char buf[1024]; + mem2hex(buf, data, size); + cprintf("RGDB(write): addr=%#x, size=%d: %s\n", vaddr, size, buf); + } + + lastaddr = vaddr; + lastsize = size; + + size_t count = min((Addr)size, + VMPageSize - (vaddr & (VMPageSize - 1))); + + maddr = vtomem(context, vaddr, count); + memcpy(maddr, data, count); + + vaddr += count; + data += count; + size -= count; + + while (size >= VMPageSize) { + maddr = vtomem(context, vaddr, count); + memcpy(maddr, data, VMPageSize); + + vaddr += VMPageSize; + data += VMPageSize; + size -= VMPageSize; + } + + if (size > 0) { + maddr = vtomem(context, vaddr, count); + memcpy(maddr, data, size); + } + +#ifdef IMB + alpha_pal_imb(); +#endif + + return true; +} + + +PCEventQueue *RemoteGDB::getPcEventQueue() +{ + return &system->pcEventQueue; +} + + +RemoteGDB::HardBreakpoint::HardBreakpoint(RemoteGDB *_gdb, Addr pc) + : PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc), + gdb(_gdb), refcount(0) +{ + DPRINTF(RGDB, "creating hardware breakpoint at %#x\n", evpc); + schedule(); +} + +void +RemoteGDB::HardBreakpoint::process(ExecContext *xc) +{ + DPRINTF(RGDB, "handling hardware breakpoint at %#x\n", pc()); + + if (xc == gdb->context) + gdb->trap(ALPHA_KENTRY_IF); +} + +bool +RemoteGDB::insertSoftBreak(Addr addr, size_t len) +{ + if (len != sizeof(MachInst)) + panic("invalid length\n"); + + return insertHardBreak(addr, len); +} + +bool +RemoteGDB::removeSoftBreak(Addr addr, size_t len) +{ + if (len != sizeof(MachInst)) + panic("invalid length\n"); + + return removeHardBreak(addr, len); +} + +bool +RemoteGDB::insertHardBreak(Addr addr, size_t len) +{ + if (len != sizeof(MachInst)) + panic("invalid length\n"); + + DPRINTF(RGDB, "inserting hardware breakpoint at %#x\n", addr); + + HardBreakpoint *&bkpt = hardBreakMap[addr]; + if (bkpt == 0) + bkpt = new HardBreakpoint(this, addr); + + bkpt->refcount++; + + return true; + +#if 0 + break_iter_t i = hardBreakMap.find(addr); + if (i == hardBreakMap.end()) { + HardBreakpoint *bkpt = new HardBreakpoint(this, addr); + hardBreakMap[addr] = bkpt; + i = hardBreakMap.insert(make_pair(addr, bkpt)); + if (i == hardBreakMap.end()) + return false; + } + + (*i).second->refcount++; +#endif +} + +bool +RemoteGDB::removeHardBreak(Addr addr, size_t len) +{ + if (len != sizeof(MachInst)) + panic("invalid length\n"); + + DPRINTF(RGDB, "removing hardware breakpoint at %#x\n", addr); + + break_iter_t i = hardBreakMap.find(addr); + if (i == hardBreakMap.end()) + return false; + + HardBreakpoint *hbp = (*i).second; + if (--hbp->refcount == 0) { + delete hbp; + hardBreakMap.erase(i); + } + + return true; +} + +const char * +break_type(char c) +{ + switch(c) { + case '0': return "software breakpoint"; + case '1': return "hardware breakpoint"; + case '2': return "write watchpoint"; + case '3': return "read watchpoint"; + case '4': return "access watchpoint"; + default: return "unknown breakpoint/watchpoint"; + } +} + +// This function does all command processing for interfacing to a +// remote gdb. Note that the error codes are ignored by gdb at +// present, but might eventually become meaningful. (XXX) It might +// makes sense to use POSIX errno values, because that is what the +// gdb/remote.c functions want to return. +bool +RemoteGDB::trap(int type) +{ + uint64_t val; + size_t datalen, len; + char data[KGDB_BUFLEN + 1]; + char buffer[sizeof(gdbregs) * 2 + 256]; + char temp[KGDB_BUFLEN]; + const char *p; + char command, subcmd; + string var; + bool ret; + + if (!attached) + return false; + + DPRINTF(RGDB, "RGDB(trap): PC=%#x NPC=%#x\n", + context->regs.pc, context->regs.npc); + + clearSingleStep(); + + /* + * The first entry to this function is normally through + * a breakpoint trap in kgdb_connect(), in which case we + * must advance past the breakpoint because gdb will not. + * + * On the first entry here, we expect that gdb is not yet + * listening to us, so just enter the interaction loop. + * After the debugger is "active" (connected) it will be + * waiting for a "signaled" message from us. + */ + if (!active) { + if (!IS_BREAKPOINT_TRAP(type, 0)) { + // No debugger active -- let trap handle this. + return false; + } + active = true; + } else { + // Tell remote host that an exception has occurred. + sprintf((char *)buffer, "S%02x", signal(type)); + send(buffer); + } + + // Stick frame regs into our reg cache. + getregs(); + + for (;;) { + datalen = recv(data, sizeof(data)); + data[sizeof(data) - 1] = 0; // Sentinel + command = data[0]; + subcmd = 0; + p = data + 1; + switch (command) { + + case KGDB_SIGNAL: + // if this command came from a running gdb, answer it -- + // the other guy has no way of knowing if we're in or out + // of this loop when he issues a "remote-signal". + sprintf((char *)buffer, "S%02x", signal(type)); + send(buffer); + continue; + + case KGDB_REG_R: + if (2 * sizeof(gdbregs) > sizeof(buffer)) + panic("buffer too small"); + + mem2hex(buffer, gdbregs, sizeof(gdbregs)); + send(buffer); + continue; + + case KGDB_REG_W: + p = hex2mem(gdbregs, p, sizeof(gdbregs)); + if (p == NULL || *p != '\0') + send("E01"); + else { + setregs(); + send("OK"); + } + continue; + +#if 0 + case KGDB_SET_REG: + val = hex2i(&p); + if (*p++ != '=') { + send("E01"); + continue; + } + if (val < 0 && val >= KGDB_NUMREGS) { + send("E01"); + continue; + } + + gdbregs[val] = hex2i(&p); + setregs(); + send("OK"); + + continue; +#endif + + case KGDB_MEM_R: + val = hex2i(&p); + if (*p++ != ',') { + send("E02"); + continue; + } + len = hex2i(&p); + if (*p != '\0') { + send("E03"); + continue; + } + if (len > sizeof(buffer)) { + send("E04"); + continue; + } + if (!acc(val, len)) { + send("E05"); + continue; + } + + if (read(val, (size_t)len, (char *)buffer)) { + mem2hex(temp, buffer, len); + send(temp); + } else { + send("E05"); + } + continue; + + case KGDB_MEM_W: + val = hex2i(&p); + if (*p++ != ',') { + send("E06"); + continue; + } + len = hex2i(&p); + if (*p++ != ':') { + send("E07"); + continue; + } + if (len > datalen - (p - data)) { + send("E08"); + continue; + } + p = hex2mem(buffer, p, sizeof(buffer)); + if (p == NULL) { + send("E09"); + continue; + } + if (!acc(val, len)) { + send("E0A"); + continue; + } + if (write(val, (size_t)len, (char *)buffer)) + send("OK"); + else + send("E0B"); + continue; + + case KGDB_SET_THREAD: + subcmd = *p++; + val = hex2i(&p); + if (val == 0) + send("OK"); + else + send("E01"); + continue; + + case KGDB_DETACH: + case KGDB_KILL: + active = false; + clearSingleStep(); + detach(); + goto out; + + case KGDB_ASYNC_CONT: + subcmd = hex2i(&p); + if (*p++ == ';') { + val = hex2i(&p); + context->regs.pc = val; + context->regs.npc = val + sizeof(MachInst); + } + clearSingleStep(); + goto out; + + case KGDB_CONT: + if (p - data < datalen) { + val = hex2i(&p); + context->regs.pc = val; + context->regs.npc = val + sizeof(MachInst); + } + clearSingleStep(); + goto out; + + case KGDB_ASYNC_STEP: + subcmd = hex2i(&p); + if (*p++ == ';') { + val = hex2i(&p); + context->regs.pc = val; + context->regs.npc = val + sizeof(MachInst); + } + setSingleStep(); + goto out; + + case KGDB_STEP: + if (p - data < datalen) { + val = hex2i(&p); + context->regs.pc = val; + context->regs.npc = val + sizeof(MachInst); + } + setSingleStep(); + goto out; + + case KGDB_CLR_HW_BKPT: + subcmd = *p++; + if (*p++ != ',') send("E0D"); + val = hex2i(&p); + if (*p++ != ',') send("E0D"); + len = hex2i(&p); + + DPRINTF(RGDB, "kgdb: clear %s, addr=%#x, len=%d\n", + break_type(subcmd), val, len); + + ret = false; + + switch (subcmd) { + case '0': // software breakpoint + ret = removeSoftBreak(val, len); + break; + + case '1': // hardware breakpoint + ret = removeHardBreak(val, len); + break; + + case '2': // write watchpoint + case '3': // read watchpoint + case '4': // access watchpoint + default: // unknown + send(""); + break; + } + + send(ret ? "OK" : "E0C"); + continue; + + case KGDB_SET_HW_BKPT: + subcmd = *p++; + if (*p++ != ',') send("E0D"); + val = hex2i(&p); + if (*p++ != ',') send("E0D"); + len = hex2i(&p); + + DPRINTF(RGDB, "kgdb: set %s, addr=%#x, len=%d\n", + break_type(subcmd), val, len); + + ret = false; + + switch (subcmd) { + case '0': // software breakpoint + ret = insertSoftBreak(val, len); + break; + + case '1': // hardware breakpoint + ret = insertHardBreak(val, len); + break; + + case '2': // write watchpoint + case '3': // read watchpoint + case '4': // access watchpoint + default: // unknown + send(""); + break; + } + + send(ret ? "OK" : "E0C"); + continue; + + case KGDB_QUERY_VAR: + var = string(p, datalen - 1); + if (var == "C") + send("QC0"); + else + send(""); + continue; + + case KGDB_SET_BAUD: + case KGDB_SET_BREAK: + case KGDB_DEBUG: + case KGDB_CYCLE_STEP: + case KGDB_SIG_CYCLE_STEP: + case KGDB_READ_REG: + case KGDB_SET_VAR: + case KGDB_RESET: + case KGDB_THREAD_ALIVE: + case KGDB_TARGET_EXIT: + case KGDB_BINARY_DLOAD: + // Unsupported command + DPRINTF(RGDB, "kgdb: Unsupported command: %s\n", + gdb_command(command)); + DDUMP(RGDB, (uint8_t *)data, datalen); + send(""); + continue; + + default: + // Unknown command. + DPRINTF(RGDB, "kgdb: Unknown command: %c(%#x)\n", + command, command); + send(""); + continue; + + + } + } + + out: + return true; +} + +// Convert a hex digit into an integer. +// This returns -1 if the argument passed is no valid hex digit. +int +digit2i(char c) +{ + if (c >= '0' && c <= '9') + return (c - '0'); + else if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + else if (c >= 'A' && c <= 'F') + + return (c - 'A' + 10); + else + return (-1); +} + +// Convert the low 4 bits of an integer into an hex digit. +char +i2digit(int n) +{ + return ("0123456789abcdef"[n & 0x0f]); +} + +// Convert a byte array into an hex string. +void +mem2hex(void *vdst, const void *vsrc, int len) +{ + char *dst = (char *)vdst; + const char *src = (const char *)vsrc; + + while (len--) { + *dst++ = i2digit(*src >> 4); + *dst++ = i2digit(*src++); + } + *dst = '\0'; +} + +// Convert an hex string into a byte array. +// This returns a pointer to the character following the last valid +// hex digit. If the string ends in the middle of a byte, NULL is +// returned. +const char * +hex2mem(void *vdst, const char *src, int maxlen) +{ + char *dst = (char *)vdst; + int msb, lsb; + + while (*src && maxlen--) { + msb = digit2i(*src++); + if (msb < 0) + return (src - 1); + lsb = digit2i(*src++); + if (lsb < 0) + return (NULL); + *dst++ = (msb << 4) | lsb; + } + return (src); +} + +// Convert an hex string into an integer. +// This returns a pointer to the character following the last valid +// hex digit. +Addr +hex2i(const char **srcp) +{ + const char *src = *srcp; + Addr r = 0; + int nibble; + + while ((nibble = digit2i(*src)) >= 0) { + r *= 16; + r += nibble; + src++; + } + *srcp = src; + return (r); +} + diff --git a/base/remote_gdb.hh b/base/remote_gdb.hh new file mode 100644 index 000000000..315860ead --- /dev/null +++ b/base/remote_gdb.hh @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __REMOTE_GDB_HH__ +#define __REMOTE_GDB_HH__ + +#include "kgdb.h" +#include "pc_event.hh" +#include "pollevent.hh" +#include "socket.hh" + +class System; +class ExecContext; +class PhysicalMemory; + +class RemoteGDB +{ + protected: + class Event : public PollEvent + { + protected: + RemoteGDB *gdb; + + public: + Event(RemoteGDB *g, int fd, int e); + void process(int revent); + }; + + friend class Event; + Event *event; + + protected: + int fd; + uint64_t gdbregs[KGDB_NUMREGS]; + + protected: +#ifdef notyet + label_t recover; +#endif + bool active; + bool attached; + + System *system; + PhysicalMemory *pmem; + ExecContext *context; + + protected: + uint8_t getbyte(); + void putbyte(uint8_t b); + + int recv(char *data, int len); + void send(const char *data); + + protected: + // Machine memory + bool read(Addr addr, size_t size, char *data); + bool write(Addr addr, size_t size, const char *data); + + template <class T> T read(Addr addr); + template <class T> void write(Addr addr, T data); + + public: + RemoteGDB(System *system, ExecContext *context); + ~RemoteGDB(); + + void attach(int fd); + void detach(); + bool isattached(); + + bool acc(Addr addr, size_t len); + static int signal(int type); + bool trap(int type); + + protected: + void getregs(); + void setregs(); + + void clearSingleStep(); + void setSingleStep(); + + PCEventQueue *getPcEventQueue(); + + protected: + class HardBreakpoint : public PCEvent + { + private: + RemoteGDB *gdb; + + public: + HardBreakpoint(RemoteGDB *_gdb, Addr addr); + + int refcount; + virtual void process(ExecContext *xc); + }; + friend class HardBreakpoint; + + typedef std::map<Addr, HardBreakpoint *> break_map_t; + typedef break_map_t::iterator break_iter_t; + break_map_t hardBreakMap; + + bool insertSoftBreak(Addr addr, size_t len); + bool removeSoftBreak(Addr addr, size_t len); + bool insertHardBreak(Addr addr, size_t len); + bool removeHardBreak(Addr addr, size_t len); + + protected: + struct TempBreakpoint { + Addr address; // set here + MachInst bkpt_inst; // saved instruction at bkpt + int init_count; // number of times to skip bkpt + int count; // current count + }; + + TempBreakpoint notTakenBkpt; + TempBreakpoint takenBkpt; + + void clearTempBreakpoint(TempBreakpoint &bkpt); + void setTempBreakpoint(TempBreakpoint &bkpt, Addr addr); +}; + +template <class T> +inline T +RemoteGDB::read(Addr addr) +{ + T temp; + read(addr, sizeof(T), (char *)&temp); + return temp; +} + +template <class T> +inline void +RemoteGDB::write(Addr addr, T data) +{ write(addr, sizeof(T), (const char *)&data); } + +class GDBListener +{ + protected: + class Event : public PollEvent + { + protected: + GDBListener *listener; + + public: + Event(GDBListener *l, int fd, int e); + void process(int revent); + }; + + friend class Event; + Event *event; + + protected: + ListenSocket listener; + RemoteGDB *gdb; + int port; + + public: + GDBListener(RemoteGDB *g, int p); + ~GDBListener(); + + void accept(); + void listen(); +}; + +#endif /* __REMOTE_GDB_H__ */ diff --git a/base/res_list.hh b/base/res_list.hh new file mode 100644 index 000000000..b5eb209c9 --- /dev/null +++ b/base/res_list.hh @@ -0,0 +1,756 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __RES_LIST_HH__ +#define __RES_LIST_HH__ + +#include "cprintf.hh" +#include "std_types.hh" +#include <assert.h> + +#define DEBUG_REMOVE 0 + +#define DEBUG_MEMORY 0 +//#define DEBUG_MEMORY DEBUG + +class res_list_base +{ +#if DEBUG_MEMORY + protected: + static long long allocated_elements; + static long long allocated_lists; + + public: + long long get_elements(void) { + return allocated_elements; + } + long long get_lists(void) { + return allocated_lists; + } + +#endif +}; + +#if DEBUG_MEMORY +extern void what_the(void); +#endif + +template<class T> +class res_list : public res_list_base +{ + public: + class iterator; + + class res_element + { + res_element *next; + res_element *prev; + T *data; + bool allocate_data; + + public: + // always adds to the END of the list + res_element(res_element *_prev, bool allocate); + ~res_element(); + void dump(void); + + friend class res_list<T>; + friend class res_list<T>::iterator; + }; + + class iterator + { + private: + res_element *p; + + friend class res_list<T>; + + public: + // Constructors + iterator(res_element *q) : p(q) {} + iterator(void) { p=0; }; + + void dump(void); + T* data_ptr(void); + res_element *res_el_ptr(void) { return p;} + void point_to(T &d) { p->data = &d; } + + iterator next(void) { return iterator(p->next); } + iterator prev(void) { return iterator(p->prev); } + bool operator== (iterator x) { return (x.p == this->p); } + bool operator != (iterator x) { return (x.p != this->p); } + T& operator * (void) { return *(p->data); } + T* operator -> (void) { return p->data; } + bool isnull(void) { return (p==0); } + bool notnull(void) { return (p!=0); } + }; + + private: + iterator unused_elements; + iterator head_ptr; + iterator tail_ptr; + + unsigned base_elements; + unsigned extra_elements; + unsigned active_elements; + bool allocate_storage; + unsigned build_size; + + int remove_count; + + // + // Allocate new elements, and assign them to the unused_elements + // list. + // + unsigned allocate_elements(unsigned num, bool allocate_storage); + + public: + // + // List Constructor + // + res_list(unsigned size, bool alloc_storage = false, + unsigned build_sz = 5); + + // + // List Destructor + // + ~res_list(); + + iterator head(void) {return head_ptr;}; + iterator tail(void) {return tail_ptr;}; + + unsigned num_free(void) { return size() - count(); } + unsigned size(void) { return base_elements + extra_elements; } + unsigned count(void) { return active_elements; } + bool empty(void) { return count() == 0; } + bool full(void); + + // + // Insert with data copy + // + iterator insert_after(iterator prev, T *d); + iterator insert_after(iterator prev, T &d); + iterator insert_before(iterator prev, T *d); + iterator insert_before(iterator prev, T &d); + + // + // Insert new list element (no data copy) + // + iterator insert_after(iterator prev); + iterator insert_before(iterator prev); + + iterator add_tail(T *d) { return insert_after(tail_ptr, d); } + iterator add_tail(T &d) { return insert_after(tail_ptr, d); } + iterator add_tail(void) { return insert_after(tail_ptr); } + iterator add_head(T *d) { return insert_before(head_ptr, d); } + iterator add_head(T &d) { return insert_before(head_ptr, d); } + iterator add_head(void) { return insert_before(head_ptr); } + + iterator remove(iterator q); + iterator remove_head(void) {return remove(head_ptr);} + iterator remove_tail(void) {return remove(tail_ptr);} + + bool in_list(iterator j); + void free_extras(void); + void clear(void); + void dump(void); + void raw_dump(void); +}; + +template <class T> +inline +res_list<T>::res_element::res_element(res_element *_prev, bool allocate) +{ + allocate_data = allocate; + prev = _prev; + next = 0; + + if (prev) + prev->next = this; + + if (allocate) + data = new T; + else + data = 0; + +#if DEBUG_MEMORY + ++allocated_elements; +#endif +} + +template <class T> +inline +res_list<T>::res_element::~res_element(void) +{ + if (prev) + prev->next = next; + + if (next) + next->prev = prev; + + if (allocate_data) + delete data; + +#if DEBUG_MEMORY + --allocated_elements; +#endif +} + +template <class T> +inline void +res_list<T>::res_element::dump(void) +{ + cprintf(" prev = %#x\n", prev); + cprintf(" next = %#x\n", next); + cprintf(" data = %#x\n", data); +} + +template <class T> +inline void +res_list<T>::iterator::dump(void) +{ + if (p && p->data) + p->data->dump(); + else { + if (!p) + cprintf(" Null Pointer\n"); + else + cprintf(" Null 'data' Pointer\n"); + } +} + +template <class T> +inline T * +res_list<T>::iterator::data_ptr(void) +{ + if (p) + return p->data; + else + return 0; +} + + +// +// Allocate new elements, and assign them to the unused_elements +// list. +// +template <class T> +inline unsigned +res_list<T>::allocate_elements(unsigned num, bool allocate_storage) +{ + res_element *pnew, *plast = 0, *pfirst=0; + + for (int i=0; i<num; ++i) { + pnew = new res_element(plast, allocate_storage); + if (i==0) + pfirst = pnew; + plast = pnew; + } + + if (unused_elements.notnull()) { + // Add these new elements to the front of the list + plast->next = unused_elements.res_el_ptr(); + unused_elements.res_el_ptr()->prev = plast; + } + + unused_elements = iterator(pfirst); + + return num; +} + +template <class T> +inline +res_list<T>::res_list(unsigned size, bool alloc_storage, unsigned build_sz) +{ +#if DEBUG_MEMORY + ++allocated_lists; +#endif + extra_elements = 0; + active_elements = 0; + build_size = build_sz; + allocate_storage = alloc_storage; + remove_count = 0; + + // Create the new elements + base_elements = allocate_elements(size, alloc_storage); + + // The list of active elements + head_ptr = iterator(0); + tail_ptr = iterator(0); +} + +// +// List Destructor +// +template <class T> +inline +res_list<T>::~res_list(void) +{ + iterator n; + +#if DEBUG_MEMORY + --allocated_lists; +#endif + + // put everything into the unused list + clear(); + + // rudely delete all the res_elements + for (iterator p = unused_elements; + p.notnull(); + p = n) { + + n = p.next(); + + // delete the res_element + // (it will take care of deleting the data) + delete p.res_el_ptr(); + } +} + +template <class T> +inline bool +res_list<T>::full(void) +{ + if (build_size) + return false; + else + return unused_elements.isnull(); +} + +// +// Insert with data copy +// +template <class T> +inline typename res_list<T>::iterator +res_list<T>::insert_after(iterator prev, T *d) +{ + iterator p; + + if (!allocate_storage) + panic("Can't copy data... not allocating storage"); + + p = insert_after(prev); + if (p.notnull()) + *p = *d; + + return p; +} + + +template <class T> +inline typename res_list<T>::iterator +res_list<T>::insert_after(iterator prev, T &d) +{ + iterator p; + + p = insert_after(prev); + if (p.notnull()) { + + if (allocate_storage) { + // if we allocate storage, then copy the contents of the + // specified object to our object + *p = d; + } + else { + // if we don't allocate storage, then we just want to + // point to the specified object + p.point_to(d); + } + } + + return p; +} + + +template <class T> +inline typename res_list<T>::iterator +res_list<T>::insert_after(iterator prev) +{ + +#if DEBUG_MEMORY + if (active_elements > 2*base_elements) { + what_the(); + } +#endif + + // If we have no unused elements, make some more + if (unused_elements.isnull()) { + + if (build_size == 0) { + return 0; // No space left, and can't allocate more.... + } + + extra_elements += allocate_elements(build_size, allocate_storage); + } + + // grab the first unused element + res_element *p = unused_elements.res_el_ptr(); + + unused_elements = unused_elements.next(); + + ++active_elements; + + // Insert the new element + if (head_ptr.isnull()) { + // + // Special case #1: Empty List + // + head_ptr = p; + tail_ptr = p; + p->prev = 0; + p->next = 0; + } + else if (prev.isnull()) { + // + // Special case #2: Insert at head + // + + // our next ptr points to old head element + p->next = head_ptr.res_el_ptr(); + + // our element becomes the new head element + head_ptr = p; + + // no previous element for the head + p->prev = 0; + + // old head element points back to this element + p->next->prev = p; + } + else if (prev.next().isnull()) { + // + // Special case #3 Insert at tail + // + + // our prev pointer points to old tail element + p->prev = tail_ptr.res_el_ptr(); + + // our element becomes the new tail + tail_ptr = p; + + // no next element for the tail + p->next = 0; + + // old tail element point to this element + p->prev->next = p; + } + else { + // + // Normal insertion (after prev) + // + p->prev = prev.res_el_ptr(); + p->next = prev.next().res_el_ptr(); + + prev.res_el_ptr()->next = p; + p->next->prev = p; + } + + return iterator(p); +} + +template <class T> +inline typename res_list<T>::iterator +res_list<T>::insert_before(iterator next, T &d) +{ + iterator p; + + p = insert_before(next); + if (p.notnull()) { + + if (allocate_storage) { + // if we allocate storage, then copy the contents of the + // specified object to our object + *p = d; + } + else { + // if we don't allocate storage, then we just want to + // point to the specified object + p.point_to(d); + } + } + + return p; +} + + +template <class T> +inline typename res_list<T>::iterator +res_list<T>::insert_before(iterator next) +{ + +#if DEBUG_MEMORY + if (active_elements > 2*base_elements) { + what_the(); + } +#endif + + // If we have no unused elements, make some more + if (unused_elements.isnull()) { + + if (build_size == 0) { + return 0; // No space left, and can't allocate more.... + } + + extra_elements += allocate_elements(build_size, allocate_storage); + } + + // grab the first unused element + res_element *p = unused_elements.res_el_ptr(); + + unused_elements = unused_elements.next(); + + ++active_elements; + + // Insert the new element + if (head_ptr.isnull()) { + // + // Special case #1: Empty List + // + head_ptr = p; + tail_ptr = p; + p->prev = 0; + p->next = 0; + } + else if (next.isnull()) { + // + // Special case #2 Insert at tail + // + + // our prev pointer points to old tail element + p->prev = tail_ptr.res_el_ptr(); + + // our element becomes the new tail + tail_ptr = p; + + // no next element for the tail + p->next = 0; + + // old tail element point to this element + p->prev->next = p; + } + else if (next.prev().isnull()) { + // + // Special case #3: Insert at head + // + + // our next ptr points to old head element + p->next = head_ptr.res_el_ptr(); + + // our element becomes the new head element + head_ptr = p; + + // no previous element for the head + p->prev = 0; + + // old head element points back to this element + p->next->prev = p; + } + else { + // + // Normal insertion (before next) + // + p->next = next.res_el_ptr(); + p->prev = next.prev().res_el_ptr(); + + next.res_el_ptr()->prev = p; + p->prev->next = p; + } + + return iterator(p); +} + + +template <class T> +inline typename res_list<T>::iterator +res_list<T>::remove(iterator q) +{ + res_element *p = q.res_el_ptr(); + iterator n = 0; + + // Handle the special cases + if (active_elements == 1) { // This is the only element + head_ptr = 0; + tail_ptr = 0; + } + else if (q == head_ptr) { // This is the head element + head_ptr = q.next(); + head_ptr.res_el_ptr()->prev = 0; + + n = head_ptr; + } + else if (q == tail_ptr) { // This is the tail element + tail_ptr = q.prev(); + tail_ptr.res_el_ptr()->next = 0; + } + else { // This is between two elements + p->prev->next = p->next; + p->next->prev = p->prev; + + // Get the "next" element for return + n = p->next; + } + + --active_elements; + + // Put this element back onto the unused list + p->next = unused_elements.res_el_ptr(); + p->prev = 0; + if (p->next) { // NULL if unused list is empty + p->next->prev = p; + } + + if (!allocate_storage) { + p->data = 0; + } + + unused_elements = q; + + // A little "garbage collection" + if (++remove_count > 10) { + // free_extras(); + remove_count = 0; + } + +#if DEBUG_REMOVE + unsigned unused_count = 0; + for (iterator i=unused_elements; + i.notnull(); + i = i.next()) { + + ++unused_count; + } + + assert((active_elements+unused_count) == (base_elements+extra_elements)); +#endif + + return iterator(n); +} + + +template <class T> +inline bool +res_list<T>::in_list(iterator j) +{ + iterator i; + + for (i=head(); i.notnull(); i=i.next()) { + if (j.res_el_ptr() == i.res_el_ptr()) { + return true; + } + } + + return false; +} + +template <class T> +inline void +res_list<T>::free_extras(void) +{ + unsigned num_unused = base_elements + extra_elements - active_elements; + unsigned to_free = extra_elements; + res_element *p; + + + if (extra_elements != 0) { + // + // Free min(extra_elements, # unused elements) + // + if (extra_elements > num_unused) { + to_free = num_unused; + } + + p = unused_elements.res_el_ptr(); + for(int i=0; i<to_free; ++i) { + res_element *q = p->next; + + delete p; + + p = q; + } + + // update the unused element pointer to point to the first + // element that wasn't deleted. + unused_elements = iterator(p); + + // Update the number of extra elements + extra_elements -= to_free; + } + + return; +} + + +template <class T> +inline void +res_list<T>::clear(void) +{ + iterator i,n; + + for (i=head_ptr; i.notnull(); i=n) { + n = i.next(); + remove(i); + } + + free_extras(); +} + +template <class T> +inline void +res_list<T>::dump(void) +{ + for (iterator i=head(); !i.isnull(); i=i.next()) + i->dump(); +} + +template <class T> +inline void +res_list<T>::raw_dump(void) +{ + int j = 0; + res_element *p; + for (iterator i=head(); !i.isnull(); i=i.next()) { + cprintf("Element %d:\n", j); + + if (i.notnull()) { + p = i.res_el_ptr(); + cprintf(" points to res_element @ %#x\n", p); + p->dump(); + cprintf(" Data Element:\n"); + i->dump(); + } + else { + cprintf(" NULL iterator!\n"); + } + + ++j; + } + +} + +#endif // __RES_LIST_HH__ diff --git a/base/sched_list.hh b/base/sched_list.hh new file mode 100644 index 000000000..f5b90f571 --- /dev/null +++ b/base/sched_list.hh @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SCHED_LIST_HH +#define SCHED_LIST_HH + +#include <list> +#include "misc.hh" + +// Any types you use this class for must be covered here... +namespace { + void ClearEntry(int &i) { i = 0; }; + void ClearEntry(unsigned &i) { i = 0; }; + void ClearEntry(double &i) { i = 0; }; + template <class T> void ClearEntry(std::list<T> &l) { l.clear(); }; +}; + + +// +// this is a special list type that allows the user to insert elements at a +// specified positive offset from the "current" element, but only allow them +// be extracted from the "current" element +// + + +template <class T> +class SchedList +{ + T *data_array; + unsigned position; + unsigned size; + unsigned mask; + + public: + SchedList(unsigned size); + SchedList(void); + + void init(unsigned size); + + T &operator[](unsigned offset); + + void advance(void); + + void clear(void); +}; + + + +// +// Constructor +// +template<class T> +SchedList<T>::SchedList(unsigned _size) +{ + size = _size; + + // size must be a power of two + if (size & (size-1)) { + panic("SchedList: size must be a power of two"); + } + + if (size < 2) { + panic("SchedList: you don't want a list that small"); + } + + // calculate the bit mask for the modulo operation + mask = size - 1; + + data_array = new T[size]; + + if (!data_array) { + panic("SchedList: could not allocate memory"); + } + + clear(); +} + +template<class T> +SchedList<T>::SchedList(void) +{ + data_array = 0; + size = 0; +} + + +template<class T> void +SchedList<T>::init(unsigned _size) +{ + size = _size; + + if (!data_array) { + // size must be a power of two + if (size & (size-1)) { + panic("SchedList: size must be a power of two"); + } + + if (size < 2) { + panic("SchedList: you don't want a list that small"); + } + + // calculate the bit mask for the modulo operation + mask = size - 1; + + data_array = new T[size]; + + if (!data_array) { + panic("SchedList: could not allocate memory"); + } + + clear(); + } +} + + +template<class T> void +SchedList<T>::advance(void) +{ + ClearEntry(data_array[position]); + + // position = (++position % size); + position = ++position & mask; +} + + +template<class T> void +SchedList<T>::clear(void) +{ + for (unsigned i=0; i<size; ++i) { + ClearEntry(data_array[i]); + } + + position = 0; +} + + +template<class T> T& +SchedList<T>::operator[](unsigned offset) +{ + if (offset >= size) { + panic("SchedList: can't access element beyond current pointer"); + } + + // unsigned p = (position + offset) % size; + unsigned p = (position + offset) & mask; + + return data_array[p]; +} + + + +#endif diff --git a/base/socket.cc b/base/socket.cc new file mode 100644 index 000000000..00fdf1ba3 --- /dev/null +++ b/base/socket.cc @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> + +#include <errno.h> +#include <unistd.h> + +#include "host.hh" +#include "misc.hh" +#include "socket.hh" + +using namespace std; + +//////////////////////////////////////////////////////////////////////// +// +// + +ListenSocket::ListenSocket() + : listening(false), fd(-1) +{} + +ListenSocket::~ListenSocket() +{ + if (fd != -1) + close(fd); +} + +// Create a socket and configure it for listening +bool +ListenSocket::listen(int port, bool reuse) +{ + if (listening) + panic("Socket already listening!"); + + fd = ::socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) + panic("Can't create socket!"); + + if (reuse) { + int i = 1; + if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&i, + sizeof(i)) < 0) + panic("ListenSocket(listen): setsockopt() SO_REUSEADDR failed!"); + } + + struct sockaddr_in sockaddr; + sockaddr.sin_family = PF_INET; + sockaddr.sin_addr.s_addr = INADDR_ANY; + + sockaddr.sin_port = htons(port); + int ret = ::bind(fd, (struct sockaddr *)&sockaddr, sizeof (sockaddr)); + if (ret != 0) { + if (ret == -1 && errno != EADDRINUSE) + panic("ListenSocket(listen): bind() failed!"); + return false; + } + + if (::listen(fd, 1) == -1) + panic("ListenSocket(listen): listen() failed!"); + + listening = true; + + return true; +} + +#if !defined(__OpenBSD__) && !defined(linux) +typedef int socklen_t; +#endif + +// Open a connection. Accept will block, so if you don't want it to, +// make sure a connection is ready before you call accept. +int +ListenSocket::accept(bool nodelay) +{ + struct sockaddr_in sockaddr; + socklen_t slen = sizeof (sockaddr); + int sfd = ::accept(fd, (struct sockaddr *)&sockaddr, &slen); + if (sfd != -1 && nodelay) { + int i = 1; + ::setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)); + } + + return sfd; +} diff --git a/base/socket.hh b/base/socket.hh new file mode 100644 index 000000000..39bacba94 --- /dev/null +++ b/base/socket.hh @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SOCKET_HH__ +#define __SOCKET_HH__ + +class ListenSocket +{ + protected: + bool listening; + int fd; + + public: + ListenSocket(); + virtual ~ListenSocket(); + + virtual int accept(bool nodelay = false); + virtual bool listen(int port, bool reuse = true); + + int getfd() const { return fd; } + bool islistening() const { return listening; } +}; + +#endif //__SOCKET_HH__ diff --git a/base/statistics.cc b/base/statistics.cc new file mode 100644 index 000000000..1e8cd2565 --- /dev/null +++ b/base/statistics.cc @@ -0,0 +1,823 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <iomanip> +#include <iostream> +#include <list> +#include <map> +#include <string> +#include <sstream> + +#include <math.h> + +#include "cprintf.hh" +#include "intmath.h" +#include "misc.hh" +#include "statistics.hh" +#include "str.hh" +#include "universe.hh" + +#ifdef __M5_NAN +float +__nan() +{ + union { + uint32_t ui; + float f; + } nan; + + nan.ui = 0x7fc00000; + return nan.f; +} +#endif + +#ifdef STAT_DEBUG +static int total_stats = 0; +#endif + +using namespace std; + +// This is a hack to get this parameter from the old stats package. +namespace Statistics { +bool PrintDescriptions = true; + +namespace Detail { +struct SubData +{ + string name; + string desc; +}; + +struct StatData +{ + StatData(); + ~StatData(); + + bool init; + bool print; + string name; + vector<SubData> *subdata; + string desc; + int precision; + FormatFlags flags; + const Stat *prereq; +}; + +StatData::StatData() + : init(false), print(false), subdata(NULL), precision(-1), flags(none), + prereq(NULL) +{ +} + +StatData::~StatData() +{ + if (subdata) + delete subdata; +} + +class Database +{ + private: + Database(const Database &) {} + + private: + typedef list<Stat *> list_t; + typedef map<const Stat *, StatData *> map_t; + + list_t allStats; + list_t printStats; + map_t map; + + public: + Database(); + ~Database(); + + void dump(ostream &stream); + + StatData *find(const Stat *stat); + void check(); + void regStat(Stat *stat); + StatData *print(Stat *stat); +}; + +Database::Database() +{} + +Database::~Database() +{} + +void +Database::dump(ostream &stream) +{ + list_t::iterator i = printStats.begin(); + list_t::iterator end = printStats.end(); + + while (i != end) { + Stat *stat = *i; + if (stat->dodisplay()) + stat->display(stream); + ++i; + } +} + +StatData * +Database::find(const Stat *stat) +{ + map_t::const_iterator i = map.find(stat); + + if (i == map.end()) + return NULL; + + return (*i).second; +} + +void +Database::check() +{ + list_t::iterator i = allStats.begin(); + list_t::iterator end = allStats.end(); + + while (i != end) { + Stat *stat = *i; + StatData *data = find(stat); + if (!data || !data->init) { +#ifdef STAT_DEBUG + cprintf("this is stat number %d\n",(*i)->number); +#endif + panic("Not all stats have been initialized"); + } + + if (data->print) { + if (data->name.empty()) + panic("all printable stats must be named"); + + list_t::iterator j = printStats.insert(printStats.end(), *i); + inplace_merge(printStats.begin(), j, + printStats.end(), Stat::less); + } + + ++i; + } +} + +void +Database::regStat(Stat *stat) +{ + if (map.find(stat) != map.end()) + panic("shouldn't register stat twice!"); + + allStats.push_back(stat); + + StatData *data = new StatData; + bool success = (map.insert(make_pair(stat, data))).second; + assert(map.find(stat) != map.end()); + assert(success && "this should never fail"); +} + +bool +Stat::less(Stat *stat1, Stat *stat2) +{ + const string &name1 = stat1->myname(); + const string &name2 = stat2->myname(); + + vector<string> v1; + vector<string> v2; + + tokenize(v1, name1, '.'); + tokenize(v2, name2, '.'); + + int last = min(v1.size(), v2.size()) - 1; + for (int i = 0; i < last; ++i) + if (v1[i] != v2[i]) + return v1[i] < v2[i]; + + // Special compare for last element. + if (v1[last] == v2[last]) + return v1.size() < v2.size(); + else + return v1[last] < v2[last]; + + return false; +} + +StatData * +Database::print(Stat *stat) +{ + StatData *data = find(stat); + assert(data); + + data->print = true; + + return data; +} + +Database & +StatDB() +{ + static Database db; + return db; +} + +Stat::Stat(bool reg) +{ +#if 0 + // This assert can help you find that pesky stat. + assert(this != (void *)0xbffff5c0); +#endif + + if (reg) + StatDB().regStat(this); +#ifdef STAT_DEBUG + number = ++total_stats; + cprintf("I'm stat number %d\n",number); +#endif +} + +void +Stat::setInit() +{ mydata()->init = true; } + +StatData * +Stat::mydata() +{ + StatData *data = StatDB().find(this); + assert(data); + + return data; +} + +const StatData * +Stat::mydata() const +{ + StatData *data = StatDB().find(this); + assert(data); + + return data; +} + +const SubData * +Stat::mysubdata(int index) const +{ + assert(index >= 0); + if (index >= size()) + return NULL; + + const StatData *data = this->mydata(); + if (!data->subdata || data->subdata->size() <= index) + return NULL; + + return &(*data->subdata)[index]; +} + +SubData * +Stat::mysubdata_create(int index) +{ + int size = this->size(); + assert(index >= 0 && (size == 0 || size > 0 && index < size)); + + StatData *data = this->mydata(); + if (!data->subdata) { + if (!data->subdata) { + if (size == 0) + size = index + 1; + + data->subdata = new vector<SubData>(size); + } + } else if (data->subdata->size() <= index) + data->subdata->resize(index + 1); + + SubData *sd = &(*data->subdata)[index]; + assert(sd); + + return sd; +} + +string +Stat::myname() const +{ return mydata()->name; } + +string +Stat::mysubname(int index) const +{ + const SubData *sd = mysubdata(index); + return sd ? sd->name : ""; +} + +string +Stat::mydesc() const +{ return mydata()->desc; } + +string +Stat::mysubdesc(int index) const +{ + const SubData *sd = mysubdata(index); + return sd ? sd->desc : ""; +} + +int +Stat::myprecision() const +{ return mydata()->precision; } + +FormatFlags +Stat::myflags() const +{ return mydata()->flags; } + +bool +Stat::dodisplay() const +{ return !mydata()->prereq || !mydata()->prereq->zero(); } + +StatData * +Stat::print() +{ + StatData *data = StatDB().print(this); + assert(data && data->init); + + return data; +} + +Stat & +Stat::name(const string &name) +{ + print()->name = name; + return *this; +} + +Stat & +Stat::desc(const string &desc) +{ + print()->desc = desc; + return *this; +} + +Stat & +Stat::precision(int precision) +{ + print()->precision = precision; + return *this; +} + +Stat & +Stat::flags(FormatFlags flags) +{ + if (flags & __reserved) + panic("Cannot set reserved flags!\n"); + + print()->flags |= flags; + return *this; +} + +Stat & +Stat::prereq(const Stat &prereq) +{ + print()->prereq = &prereq; + return *this; +} + +Stat & +Stat::subname(int index, const string &name) +{ + print(); + mysubdata_create(index)->name = name; + return *this; +} +Stat & +Stat::subdesc(int index, const string &desc) +{ + print(); + mysubdata_create(index)->desc = desc; + return *this; +} + +bool +ScalarStat::zero() const +{ + return val() == 0.0; +} + +bool +VectorStat::zero() const +{ + return val()[0] == 0.0; +} + +string +ValueToString(result_t value, int precision) +{ + stringstream val; + + if (!isnan(value)) { + if (precision != -1) + val.precision(precision); + else if (value == rint(value)) + val.precision(0); + + val.unsetf(ios::showpoint); + val.setf(ios::fixed); + val << value; + } else { +#ifndef STAT_DISPLAY_COMPAT + val << "no value"; +#else + val << "<err: div-0>"; +#endif + } + + return val.str(); +} + +void +PrintOne(ostream &stream, result_t value, + const string &name, const string &desc, int precision, + FormatFlags flags, result_t pdf = NAN, result_t cdf = NAN) +{ + if (flags & nozero && value == 0.0 || + flags & nonan && isnan(value)) + return; + + stringstream pdfstr, cdfstr; + + if (!isnan(pdf)) + ccprintf(pdfstr, "%.2f%%", pdf * 100.0); + + if (!isnan(cdf)) + ccprintf(cdfstr, "%.2f%%", cdf * 100.0); + +#ifdef STAT_DISPLAY_COMPAT + if (flags & __substat) { + ccprintf(stream, "%32s%12s%10s%10s", name, + ValueToString(value, precision), + pdfstr, cdfstr); + } else +#endif + { + ccprintf(stream, "%-40s%12s%10s%10s", name, + ValueToString(value, precision), pdfstr, cdfstr); + } + + if (PrintDescriptions) { + if (!desc.empty()) + ccprintf(stream, " # %s", desc); + } + stream << endl; +} + +void +ScalarStat::display(ostream &stream) const +{ + PrintOne(stream, val(), myname(), mydesc(), myprecision(), myflags()); +} + +void +VectorStat::display(ostream &stream) const +{ + bool have_subname = false; + bool have_subdesc = false; + int size = this->size(); + for (int i = 0; i < size; ++i) { + if (!mysubname(i).empty()) + have_subname = true; + if (!mysubdesc(i).empty()) + have_subdesc = true; + } + + vector<string> *subnames = 0; + vector<string> *subdescs = 0; + if (have_subname) { + subnames = new vector<string>(size); + for (int i = 0; i < size; ++i) + (*subnames)[i] = mysubname(i); + } + if (have_subdesc) { + subdescs = new vector<string>(size); + for (int i = 0; i < size; ++i) + (*subdescs)[i] = mysubdesc(i); + } + + VectorDisplay(stream, myname(), subnames, mydesc(), subdescs, + myprecision(), myflags(), val(), total()); +} + +#ifndef STAT_DISPLAY_COMPAT +#define NAMESEP "::" +#else +#define NAMESEP "_" +#endif + +#ifndef STAT_DISPLAY_COMPAT +void +VectorDisplay(std::ostream &stream, + const std::string &myname, + const std::vector<std::string> *mysubnames, + const std::string &mydesc, + const std::vector<std::string> *mysubdescs, + int myprecision, FormatFlags myflags, + const rvec_t &vec, result_t mytotal) +{ + int _size = vec.size(); + result_t _total = 0.0; + result_t _pdf, _cdf = 0.0; + + if (myflags & (pdf | cdf)) { + for (int i = 0; i < _size; ++i) { + _total += vec[i]; + } + } + + if (_size == 1) { + PrintOne(stream, vec[0], myname, mydesc, myprecision, myflags); + } else { + for (int i = 0; i < _size; ++i) { + string subname; + if (mysubnames) { + subname = (*mysubnames)[i]; + if (subname.empty()) + continue; + } else { + subname = to_string(i); + } + + string name = myname + NAMESEP + subname; + if (!(myflags & pdf)) + PrintOne(stream, vec[i], name, mydesc, myprecision, myflags); + else { + _pdf = vec[i] / _total; + _cdf += _pdf; + PrintOne(stream, vec[i], name, mydesc, myprecision, myflags, + _pdf, _cdf); + } + } + + if (myflags & total) + PrintOne(stream, mytotal, myname + NAMESEP + "total", + mydesc, myprecision, myflags); + } +} +#else +void +VectorDisplay(std::ostream &stream, + const std::string &myname, + const std::vector<std::string> *mysubnames, + const std::string &mydesc, + const std::vector<std::string> *mysubdescs, + int myprecision, FormatFlags myflags, + const rvec_t &vec, result_t mytotal) +{ + int _size = vec.size(); + result_t _total = 0.0; + result_t _pdf, _cdf = 0.0; + + if (myflags & (pdf | cdf)) { + for (int i = 0; i < _size; ++i) { + _total += vec[i]; + } + } + + if (_size == 1) { + PrintOne(stream, vec[0], myname, mydesc, myprecision, myflags); + } else { + if (myflags & total) + PrintOne(stream, mytotal, myname, mydesc, myprecision, myflags); + + if (myflags & dist) { + ccprintf(stream, "%s.start_dist\n", myname); + for (int i = 0; i < _size; ++i) { + string subname, subdesc; + subname = to_string(i); + if (mysubnames) { + if (!subname.empty()) { + subname = (*mysubnames)[i]; + } + } + if (mysubdescs) { + subdesc = (*mysubdescs)[i]; + } + if (!(myflags & (pdf | cdf))) { + PrintOne(stream, vec[i], subname, subdesc, myprecision, + myflags | __substat); + } else { + if (_total) { + _pdf = vec[i] / _total; + _cdf += _pdf; + } else { + _pdf = _cdf = 0.0; + } + if (!(myflags & cdf)) { + PrintOne(stream, vec[i], subname, subdesc, myprecision, + myflags | __substat, _pdf); + } else { + PrintOne(stream, vec[i], subname, subdesc, myprecision, + myflags | __substat, _pdf, _cdf); + } + } + } + ccprintf(stream, "%s.end_dist\n", myname); + } else { + for (int i = 0; i < _size; ++i) { + string subname; + if (mysubnames) { + subname = (*mysubnames)[i]; + if (subname.empty()) + continue; + } else { + subname = to_string(i); + } + + string name = myname + NAMESEP + subname; + if (!(myflags & pdf)) { + PrintOne(stream, vec[i], name, mydesc, myprecision, + myflags); + } else { + if (_total) { + _pdf = vec[i] / _total; + _cdf += _pdf; + } else { + _pdf = _cdf = 0.0; + } + _pdf = vec[i] / _total; + _cdf += _pdf; + PrintOne(stream, vec[i], name, mydesc, myprecision, + myflags, _pdf, _cdf); + } + } + } + } +} +#endif + +#ifndef STAT_DISPLAY_COMPAT +void +DistDisplay(ostream &stream, const string &name, const string &desc, + int precision, FormatFlags flags, + result_t min_val, result_t max_val, + result_t underflow, result_t overflow, + const rvec_t &vec, int min, int max, int bucket_size, int size); +{ + assert(size == vec.size()); + + result_t total = 0.0; + result_t pdf, cdf = 0.0; + + total += underflow; + for (int i = 0; i < size; ++i) + total += vec[i]; + total += overflow; + + pdf = underflow / total; + cdf += pdf; + + PrintOne(stream, underflow, name + NAMESEP + "underflow", desc, + precision, myflags, pdf, cdf); + + for (int i = 0; i < size; ++i) { + stringstream namestr; + namestr << name; + + int low = i * bucket_size + min; + int high = ::std::min((i + 1) * bucket_size + min - 1, max); + namestr << low; + if (low < high) + namestr << "-" << high; + + pdf = vec[i] / total; + cdf += pdf; + PrintOne(stream, vec[i], namestr.str(), desc, precision, myflags, + pdf, cdf); + } + + pdf = overflow / total; + cdf += pdf; + PrintOne(stream, overflow, name + NAMESEP + "overflow", desc, + precision, myflags, pdf, cdf); + PrintOne(stream, total, name + NAMESEP + "total", desc, + precision, myflags); +} +#else +void +DistDisplay(ostream &stream, const string &name, const string &desc, + int precision, FormatFlags flags, + result_t min_val, result_t max_val, + result_t underflow, result_t overflow, + const rvec_t &vec, int min, int max, int bucket_size, int size) +{ + assert(size == vec.size()); + string blank; + + result_t total = 0.0; + + total += underflow; + for (int i = 0; i < size; ++i) + total += vec[i]; + total += overflow; + + ccprintf(stream, "%-42s", name + ".start_dist"); + if (PrintDescriptions && !desc.empty()) + ccprintf(stream, " # %s", desc); + stream << endl; + + PrintOne(stream, total, name + ".samples", blank, precision, flags); + PrintOne(stream, min_val, name + ".min_value", blank, precision, flags); + + if (underflow > 0) + PrintOne(stream, min_val, name + ".underflows", blank, precision, + flags); + + int _min; + result_t _pdf, _cdf, mypdf, mycdf; + + _cdf = 0.0; + for (int i = 0; i < size; ++i) { + if (flags & nozero && vec[i] == 0.0 || + flags & nonan && isnan(vec[i])) + return; + + _min = i * bucket_size + min; + _pdf = vec[i] / total * 100.0; + _cdf += _pdf; + + mypdf = (flags & pdf) ? _pdf : NAN; + mycdf = (flags & cdf) ? _cdf : NAN; + + PrintOne(stream, vec[i], ValueToString(_min, 0), blank, precision, + flags | __substat, mypdf, mycdf); + } + + if (overflow > 0) + PrintOne(stream, overflow, name + ".overflows", blank, precision, + flags); + PrintOne(stream, max_val, name + ".max_value", blank, precision, flags); + ccprintf(stream, "%s.end_dist\n\n", name); +} +#endif + +void +FancyDisplay(ostream &stream, const string &name, const string &desc, + int precision, FormatFlags flags, result_t mean, + result_t variance) +{ + result_t stdev = isnan(variance) ? NAN : sqrt(variance); + PrintOne(stream, mean, name + NAMESEP + "mean", desc, precision, flags); + PrintOne(stream, stdev, name + NAMESEP + "stdev", desc, precision, flags); +} + +BinBase::BinBase(size_t size) + : memsize(CeilPow2(size)), mem(NULL) +{ +} + +BinBase::~BinBase() +{ + if (mem) + delete [] mem; +} + +char * +BinBase::memory() +{ + if (!mem) { + mem = new char[memsize]; + memset(mem, 0, memsize); + } + + return mem; +} + +} // namespace Detail + +void +check() +{ + Detail::StatDB().check(); +} + +void +dump(ostream &stream) +{ + Detail::StatDB().dump(stream); +} + +} // namespace Statistics diff --git a/base/statistics.hh b/base/statistics.hh new file mode 100644 index 000000000..3d9d654ed --- /dev/null +++ b/base/statistics.hh @@ -0,0 +1,1682 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * @todo + * + * Generalized N-dimensinal vector + * documentation + * fix AvgStor + * key stats + * interval stats + * -- these both can use the same function that prints out a + * specific set of stats + * VectorStandardDeviation totals + * + */ +#ifndef __STATISTICS_HH__ +#define __STATISTICS_HH__ + +#include <algorithm> +#include <functional> +#include <iosfwd> +#include <sstream> +#include <string> +#include <vector> + +#include <assert.h> + +#include "host.hh" +#include "refcnt.hh" +#include "str.hh" + +#ifndef NAN +float __nan(); +#define NAN (__nan()) +#define __M5_NAN +#endif + +#define STAT_DISPLAY_COMPAT + +extern Tick curTick; + +namespace Statistics { +typedef double result_t; +typedef std::vector<result_t> rvec_t; + +typedef u_int32_t FormatFlags; +const FormatFlags none = 0x0000; +const FormatFlags total = 0x0001; +const FormatFlags pdf = 0x0002; +const FormatFlags nozero = 0x0004; +const FormatFlags nonan = 0x0008; +const FormatFlags cdf = 0x0010; +const FormatFlags dist = 0x0020; +const FormatFlags __substat = 0x8000; +const FormatFlags __reserved = __substat; + +namespace Detail { +////////////////////////////////////////////////////////////////////// +// +// Statistics Framework Base classes +// +////////////////////////////////////////////////////////////////////// +struct StatData; +struct SubData; + +class Stat +{ + protected: + void setInit(); + StatData *mydata(); + const StatData *mydata() const; + StatData *print(); + const SubData *mysubdata(int index) const; + SubData *mysubdata_create(int index); + + public: + virtual std::string myname() const; + virtual std::string mysubname(int index) const; + virtual std::string mydesc() const; + virtual std::string mysubdesc(int index) const; + virtual FormatFlags myflags() const; + virtual bool dodisplay() const; + virtual int myprecision() const; + + public: + Stat(bool reg); + virtual ~Stat() {} + + virtual void display(std::ostream &stream) const = 0; + virtual size_t size() const = 0; + virtual bool zero() const = 0; + + Stat &name(const std::string &name); + Stat &desc(const std::string &desc); + Stat &precision(int p); + Stat &flags(FormatFlags f); + Stat &prereq(const Stat &prereq); + Stat &subname(int index, const std::string &name); + Stat &subdesc(int index, const std::string &name); + + public: + static bool less(Stat *stat1, Stat *stat2); + +#ifdef STAT_DEBUG + int number; +#endif +}; + +// Scalar stats involved in formulas +class ScalarStat : public Stat +{ + public: + ScalarStat(bool reg) : Stat(reg) {} + virtual result_t val() const = 0; + virtual bool zero() const; + virtual void display(std::ostream &stream) const; +}; + +void +VectorDisplay(std::ostream &stream, const std::string &myname, + const std::vector<std::string> *mysubnames, + const std::string &mydesc, + const std::vector<std::string> *mysubdescs, + int myprecision, FormatFlags myflags, const rvec_t &vec, + result_t mytotal); + +// Vector stats involved in formulas +class VectorStat : public Stat +{ + public: + VectorStat(bool reg) : Stat(reg) {} + virtual const rvec_t &val() const = 0; + virtual result_t total() const = 0; + virtual bool zero() const; + virtual void display(std::ostream &stream) const; +}; + +////////////////////////////////////////////////////////////////////// +// +// Simple Statistics +// +////////////////////////////////////////////////////////////////////// +template <typename T> +struct StatStor +{ + public: + struct Params { }; + + private: + T data; + + public: + StatStor(const Params &) : data(T()) {} + + void set(T val, const Params &p) { data = val; } + void inc(T val, const Params &p) { data += val; } + void dec(T val, const Params &p) { data -= val; } + result_t val(const Params &p) const { return (result_t)data; } + T value(const Params &p) const { return data; } +}; + +template <typename T> +struct AvgStor +{ + public: + struct Params { }; + + private: + T current; + mutable result_t total; + mutable Tick last; + + public: + AvgStor(const Params &) : current(T()), total(0), last(0) { } + + void set(T val, const Params &p) { + total += current * (curTick - last); + last = curTick; + current = val; + } + void inc(T val, const Params &p) { set(current + val, p); } + void dec(T val, const Params &p) { set(current - val, p); } + result_t val(const Params &p) const { + total += current * (curTick - last); + last = curTick; + return (result_t)(total + current) / (result_t)(curTick + 1); + } + T value(const Params &p) const { return current; } +}; + +template <typename T, template <typename T> class Storage, class Bin> +class ScalarBase : public ScalarStat +{ + protected: + typedef Storage<T> storage_t; + typedef typename storage_t::Params params_t; + typedef typename Bin::Bin<storage_t> bin_t; + + protected: + bin_t bin; + params_t params; + + protected: + storage_t *data() { return bin.data(params); } + const storage_t *data() const { + return (const_cast<bin_t *>(&bin))->data(params); + } + + protected: + // Copying stats is not allowed + ScalarBase(const ScalarBase &stat); + const ScalarBase &operator=(const ScalarBase &); + + public: + result_t val() const { return data()->val(params); } + T value() const { return data()->value(params); } + + public: + ScalarBase() : ScalarStat(true) { + bin.init(params); + setInit(); + } + + public: + // Common operators for stats + void operator++() { data()->inc(1, params); } + void operator--() { data()->dec(1, params); } + + void operator++(int) { ++*this; } + void operator--(int) { --*this; } + + template <typename U> + void operator=(const U& v) { data()->set(v, params); } + + template <typename U> + void operator+=(const U& v) { data()->inc(v, params); } + + template <typename U> + void operator-=(const U& v) { data()->dec(v, params); } + + virtual size_t size() const { return 1; } +}; + +////////////////////////////////////////////////////////////////////// +// +// Vector Statistics +// +////////////////////////////////////////////////////////////////////// +template <typename T, template <typename T> class Storage, class Bin> +class ScalarProxy; + +template <typename T, template <typename T> class Storage, class Bin> +class VectorBase : public VectorStat +{ + protected: + typedef Storage<T> storage_t; + typedef typename storage_t::Params params_t; + typedef typename Bin::VectorBin<storage_t> bin_t; + + private: + mutable rvec_t *vec; + + protected: + bin_t bin; + params_t params; + + protected: + storage_t *data(int index) { return bin.data(index, params); } + const storage_t *data(int index) const { + return (const_cast<bin_t *>(&bin))->data(index, params); + } + + protected: + // Copying stats is not allowed + VectorBase(const VectorBase &stat); + const VectorBase &operator=(const VectorBase &); + + public: + const rvec_t &val() const { + if (vec) + vec->resize(size()); + else + vec = new rvec_t(size()); + + for (int i = 0; i < size(); ++i) + (*vec)[i] = data(i)->val(params); + + return *vec; + } + + result_t total() const { + result_t total = 0.0; + for (int i = 0; i < size(); ++i) + total += data(i)->val(params); + return total; + } + + public: + VectorBase() : VectorStat(true), vec(NULL) {} + ~VectorBase() { if (vec) delete vec; } + + VectorBase &init(size_t size) { + bin.init(size, params); + setInit(); + + return *this; + } + + friend class ScalarProxy<T, Storage, Bin>; + ScalarProxy<T, Storage, Bin> operator[](int index); + + virtual size_t size() const { return bin.size(); } +}; + +template <typename T, template <typename T> class Storage, class Bin> +class ScalarProxy : public ScalarStat +{ + protected: + typedef Storage<T> storage_t; + typedef typename storage_t::Params params_t; + typedef typename Bin::VectorBin<storage_t> bin_t; + + private: + bin_t *bin; + params_t *params; + int index; + + protected: + storage_t *data() { return bin->data(index, *params); } + const storage_t *data() const { return bin->data(index, *params); } + + public: + result_t val() const { return data()->val(*params); } + T value() const { return data()->value(*params); } + + public: + ScalarProxy(bin_t &b, params_t &p, int i) + : ScalarStat(false), bin(&b), params(&p), index(i) {} + ScalarProxy(const ScalarProxy &sp) + : ScalarStat(false), bin(sp.bin), params(sp.params), index(sp.index) {} + const ScalarProxy &operator=(const ScalarProxy &sp) { + bin = sp.bin; + params = sp.params; + index = sp.index; + return *this; + } + + public: + // Common operators for stats + void operator++() { data()->inc(1, *params); } + void operator--() { data()->dec(1, *params); } + + void operator++(int) { ++*this; } + void operator--(int) { --*this; } + + template <typename U> + void operator=(const U& v) { data()->set(v, *params); } + + template <typename U> + void operator+=(const U& v) { data()->inc(v, *params); } + + template <typename U> + void operator-=(const U& v) { data()->dec(v, *params); } + + virtual size_t size() const { return 1; } +}; + +template <typename T, template <typename T> class Storage, class Bin> +inline ScalarProxy<T, Storage, Bin> +VectorBase<T, Storage, Bin>::operator[](int index) +{ + assert (index >= 0 && index < size()); + return ScalarProxy<T, Storage, Bin>(bin, params, index); +} + +template <typename T, template <typename T> class Storage, class Bin> +class VectorProxy; + +template <typename T, template <typename T> class Storage, class Bin> +class Vector2dBase : public Stat +{ + protected: + typedef Storage<T> storage_t; + typedef typename storage_t::Params params_t; + typedef typename Bin::VectorBin<storage_t> bin_t; + + protected: + size_t x; + size_t y; + bin_t bin; + params_t params; + std::vector<std::string> *y_subnames; + + protected: + storage_t *data(int index) { return bin.data(index, params); } + const storage_t *data(int index) const { + return (const_cast<bin_t *>(&bin))->data(index, params); + } + + protected: + // Copying stats is not allowed + Vector2dBase(const Vector2dBase &stat); + const Vector2dBase &operator=(const Vector2dBase &); + + public: + Vector2dBase() : Stat(true) {} + ~Vector2dBase() { } + + Vector2dBase &init(size_t _x, size_t _y) { + x = _x; + y = _y; + bin.init(x * y, params); + setInit(); + y_subnames = new std::vector<std::string>(y); + + return *this; + } + + /** + * This makes the assumption that if you're gonna subnames a 2d vector, + * you're subnaming across all y + */ + Vector2dBase &ysubnames(const char **names) + { + for (int i=0; i < y; ++i) { + (*y_subnames)[i] = names[i]; + } + return *this; + } + Vector2dBase &ysubname(int index, const std::string subname) + { + (*y_subnames)[i] = subname.c_str(); + return *this; + } + std::string ysubname(int i) const { return (*y_subnames)[i]; } + + friend class VectorProxy<T, Storage, Bin>; + VectorProxy<T, Storage, Bin> operator[](int index); + + virtual size_t size() const { return bin.size(); } + virtual bool zero() const { return data(0)->value(params) == 0.0; } + + virtual void + display(std::ostream &out) const + { + bool have_subname = false; + for (int i = 0; i < x; ++i) { + if (!mysubname(i).empty()) + have_subname = true; + } + + rvec_t tot_vec(y); + result_t super_total = 0.0; + for (int i = 0; i < x; ++i) { + std::string subname; + if (have_subname) { + subname = mysubname(i); + if (subname.empty()) + continue; + } else + subname = to_string(i); + + int iy = i * y; + rvec_t vec(y); + + result_t total = 0.0; + for (int j = 0; j < y; ++j) { + vec[j] = data(iy + j)->val(params); + tot_vec[j] += vec[j]; + total += vec[j]; + super_total += vec[j]; + } + + std::string desc; + if (mysubdesc(i).empty()) { + desc = mydesc(); + } else { + desc = mysubdesc(i); + } + + VectorDisplay(out, myname() + "_" + subname, y_subnames, desc, 0, + myprecision(), myflags(), vec, total); + + } + if ((myflags() & ::Statistics::total) && (x > 1)) { + VectorDisplay(out, myname(), y_subnames, mydesc(), 0, + myprecision(), myflags(), tot_vec, super_total); + + } + } +}; + +template <typename T, template <typename T> class Storage, class Bin> +class VectorProxy : public VectorStat +{ + protected: + typedef Storage<T> storage_t; + typedef typename storage_t::Params params_t; + typedef typename Bin::VectorBin<storage_t> bin_t; + + private: + bin_t *bin; + params_t *params; + int offset; + int len; + + private: + mutable rvec_t *vec; + + storage_t *data(int index) { + assert(index < len); + return bin->data(offset + index, *params); + } + + const storage_t *data(int index) const { + return (const_cast<bin_t *>(bin))->data(offset + index, *params); + } + + public: + const rvec_t &val() const { + if (vec) + vec->resize(size()); + else + vec = new rvec_t(size()); + + for (int i = 0; i < size(); ++i) + (*vec)[i] = data(i)->val(*params); + + return *vec; + } + + result_t total() const { + result_t total = 0.0; + for (int i = 0; i < size(); ++i) + total += data(i)->val(*params); + return total; + } + + public: + VectorProxy(bin_t &b, params_t &p, int o, int l) + : VectorStat(false), bin(&b), params(&p), offset(o), len(l), vec(NULL) + { } + VectorProxy(const VectorProxy &sp) + : VectorStat(false), bin(sp.bin), params(sp.params), offset(sp.offset), + len(sp.len), vec(NULL) + { } + ~VectorProxy() { + if (vec) + delete vec; + } + + const VectorProxy &operator=(const VectorProxy &sp) { + bin = sp.bin; + params = sp.params; + offset = sp.offset; + len = sp.len; + if (vec) + delete vec; + vec = NULL; + return *this; + } + + virtual size_t size() const { return len; } + + ScalarProxy<T, Storage, Bin> operator[](int index) { + assert (index >= 0 && index < size()); + return ScalarProxy<T, Storage, Bin>(*bin, *params, offset + index); + } +}; + +template <typename T, template <typename T> class Storage, class Bin> +inline VectorProxy<T, Storage, Bin> +Vector2dBase<T, Storage, Bin>::operator[](int index) +{ + int offset = index * y; + assert (index >= 0 && offset < size()); + return VectorProxy<T, Storage, Bin>(bin, params, offset, y); +} + +////////////////////////////////////////////////////////////////////// +// +// Non formula statistics +// +////////////////////////////////////////////////////////////////////// + +void DistDisplay(std::ostream &stream, const std::string &name, + const std::string &desc, int precision, FormatFlags flags, + result_t min_val, result_t max_val, + result_t underflow, result_t overflow, + const rvec_t &vec, int min, int max, int bucket_size, + int size); + +template <typename T> +struct DistStor +{ + public: + struct Params + { + int min; + int max; + int bucket_size; + int size; + }; + + private: + T min_val; + T max_val; + T underflow; + T overflow; + std::vector<T> vec; + + public: + DistStor(const Params ¶ms) + : min_val(INT_MAX), max_val(INT_MIN), underflow(0), overflow(0), + vec(params.size) { + } + void sample(T val, int number, const Params ¶ms) { + if (val < params.min) + underflow += number; + else if (val > params.max) + overflow += number; + else { + int index = (val - params.min) / params.bucket_size; + assert(index < size(params)); + vec[index] += number; + } + + if (val < min_val) + min_val = val; + + if (val > max_val) + max_val = val; + } + + size_t size(const Params &) const { return vec.size(); } + + bool zero(const Params ¶ms) const { + if (underflow != 0 || overflow != 0) + return true; + + int s = size(params); + for (int i = 0; i < s; i++) + if (vec[i] != 0) + return true; + + return false; + } + + void display(std::ostream &stream, const std::string &name, + const std::string &desc, int precision, FormatFlags flags, + const Params ¶ms) const { + +#ifdef STAT_DISPLAY_COMPAT + result_t min = params.min; +#else + result_t min = (min_val == INT_MAX) ? params.min : min_val; +#endif + result_t max = (max_val == INT_MIN) ? 0 : max_val; + + rvec_t rvec(params.size); + for (int i = 0; i < params.size; ++i) + rvec[i] = vec[i]; + + DistDisplay(stream, name, desc, precision, flags, + (result_t)min, (result_t)max, + (result_t)underflow, (result_t)overflow, + rvec, params.min, params.max, params.bucket_size, + params.size); + } +}; + +void FancyDisplay(std::ostream &stream, const std::string &name, + const std::string &desc, int precision, FormatFlags flags, + result_t mean, result_t variance); +template <typename T> +struct FancyStor +{ + public: + struct Params {}; + + private: + T sum; + T squares; + int total; + + public: + FancyStor(const Params &) : sum(0), squares(0), total(0) {} + + void sample(T val, int number, const Params &) { + T value = val * number; + sum += value; + squares += value * value; + total += number; + } + void display(std::ostream &stream, const std::string &name, + const std::string &desc, int precision, FormatFlags flags, + const Params &) const { + + result_t mean = NAN; + result_t variance = NAN; + + if (total != 0) { + result_t fsum = sum; + result_t fsq = squares; + result_t ftot = total; + + mean = fsum / ftot; + variance = (ftot * fsq - (fsum * fsum)) / (ftot * (ftot - 1.0)); + } + + FancyDisplay(stream, name, desc, precision, flags, mean, variance); + } + + size_t size(const Params &) const { return 1; } + bool zero(const Params &) const { return total == 0; } +}; + +template <typename T> +struct AvgFancy +{ + public: + struct Params {}; + + private: + T sum; + T squares; + + public: + AvgFancy(const Params &) : sum(0), squares(0) {} + + void sample(T val, int number, const Params& p) { + T value = val * number; + sum += value; + squares += value * value; + } + void display(std::ostream &stream, const std::string &name, + const std::string &desc, int precision, FormatFlags flags, + const Params ¶ms) const { + result_t mean = sum / curTick; + result_t variance = (squares - sum * sum) / curTick; + + FancyDisplay(stream, name, desc, precision, flags, mean, variance); + } + + size_t size(const Params ¶ms) const { return 1; } + bool zero(const Params ¶ms) const { return sum == 0; } +}; + +template <typename T, template <typename T> class Storage, class Bin> +class DistBase : public Stat +{ + protected: + typedef Storage<T> storage_t; + typedef typename storage_t::Params params_t; + typedef typename Bin::Bin<storage_t> bin_t; + + protected: + bin_t bin; + params_t params; + + protected: + storage_t *data() { return bin.data(params); } + const storage_t *data() const { + return (const_cast<bin_t *>(&bin))->data(params); + } + + protected: + // Copying stats is not allowed + DistBase(const DistBase &stat); + const DistBase &operator=(const DistBase &); + + public: + DistBase() : Stat(true) { } + ~DistBase() { } + + template <typename U> + void sample(const U& v, int n = 1) { data()->sample(v, n, params); } + + virtual size_t size() const { return data()->size(params); } + virtual bool zero() const { return data()->zero(params); } + virtual void display(std::ostream &stream) const { + data()->display(stream, myname(), mydesc(), myprecision(), myflags(), + params); + } +}; + +template <typename T, template <typename T> class Storage, class Bin> +class VectorDistProxy; + +template <typename T, template <typename T> class Storage, class Bin> +class VectorDistBase : public Stat +{ + protected: + typedef Storage<T> storage_t; + typedef typename storage_t::Params params_t; + typedef typename Bin::VectorBin<storage_t> bin_t; + + protected: + bin_t bin; + params_t params; + + protected: + storage_t *data(int index) { return bin.data(index, params); } + const storage_t *data(int index) const { + return (const_cast<bin_t *>(&bin))->data(index, params); + } + + protected: + // Copying stats is not allowed + VectorDistBase(const VectorDistBase &stat); + const VectorDistBase &operator=(const VectorDistBase &); + + public: + VectorDistBase() : Stat(true) { } + ~VectorDistBase() { } + + friend class VectorDistProxy<T, Storage, Bin>; + VectorDistProxy<T, Storage, Bin> operator[](int index); + const VectorDistProxy<T, Storage, Bin> operator[](int index) const; + + virtual size_t size() const { return bin.size(); } + virtual bool zero() const { return false; } + virtual void display(std::ostream &stream) const; +}; + +template <typename T, template <typename T> class Storage, class Bin> +class VectorDistProxy : public Stat +{ + protected: + typedef Storage<T> storage_t; + typedef typename storage_t::Params params_t; + typedef typename Bin::Bin<storage_t> bin_t; + typedef VectorDistBase<T, Storage, Bin> base_t; + + private: + union { + base_t *stat; + const base_t *cstat; + }; + int index; + + protected: + storage_t *data() { return stat->data(index); } + const storage_t *data() const { return cstat->data(index); } + + public: + VectorDistProxy(const VectorDistBase<T, Storage, Bin> &s, int i) + : Stat(false), cstat(&s), index(i) {} + VectorDistProxy(const VectorDistProxy &sp) + : Stat(false), cstat(sp.cstat), index(sp.index) {} + const VectorDistProxy &operator=(const VectorDistProxy &sp) { + cstat = sp.cstat; index = sp.index; return *this; + } + + public: + template <typename U> + void sample(const U& v, int n = 1) { data()->sample(v, n, cstat->params); } + + virtual size_t size() const { return 1; } + virtual bool zero() const { + return data()->zero(cstat->params); + } + virtual void display(std::ostream &stream) const { + std::stringstream name, desc; + + if (!(cstat->mysubname(index).empty())) { + name << cstat->myname() << cstat->mysubname(index); + } else { + name << cstat->myname() << "_" << index; + } + if (!(cstat->mysubdesc(index).empty())) { + desc << cstat->mysubdesc(index); + } else { + desc << cstat->mydesc(); + } + + data()->display(stream, name.str(), desc.str(), + cstat->myprecision(), cstat->myflags(), cstat->params); + } +}; + +template <typename T, template <typename T> class Storage, class Bin> +inline VectorDistProxy<T, Storage, Bin> +VectorDistBase<T, Storage, Bin>::operator[](int index) +{ + assert (index >= 0 && index < size()); + return VectorDistProxy<T, Storage, Bin>(*this, index); +} + +template <typename T, template <typename T> class Storage, class Bin> +inline const VectorDistProxy<T, Storage, Bin> +VectorDistBase<T, Storage, Bin>::operator[](int index) const +{ + assert (index >= 0 && index < size()); + return VectorDistProxy<T, Storage, Bin>(*this, index); +} + +/** + * @todo Need a way to print Distribution totals across the Vector + */ +template <typename T, template <typename T> class Storage, class Bin> +void +VectorDistBase<T, Storage, Bin>::display(std::ostream &stream) const +{ + for (int i = 0; i < size(); ++i) { + VectorDistProxy<T, Storage, Bin> proxy(*this, i); + proxy.display(stream); + } +} + +#if 0 +result_t +VectorDistBase<T, Storage, Bin>::total(int index) const +{ + int total = 0; + for (int i=0; i < x_size(); ++i) { + total += data(i)->val(*params); + } +} +#endif + +////////////////////////////////////////////////////////////////////// +// +// Formula Details +// +////////////////////////////////////////////////////////////////////// +class Node : public RefCounted +{ + public: + virtual size_t size() const = 0; + virtual const rvec_t &val() const = 0; + virtual result_t total() const = 0; +}; + +typedef RefCountingPtr<Node> NodePtr; + +class ScalarStatNode : public Node +{ + private: + const ScalarStat &stat; + mutable rvec_t result; + + public: + ScalarStatNode(const ScalarStat &s) : stat(s), result(1) {} + const rvec_t &val() const { result[0] = stat.val(); return result; } + virtual result_t total() const { return stat.val(); }; + + virtual size_t size() const { return 1; } +}; + +template <typename T, template <typename T> class Storage, class Bin> +class ScalarProxyNode : public Node +{ + private: + const ScalarProxy<T, Storage, Bin> proxy; + mutable rvec_t result; + + public: + ScalarProxyNode(const ScalarProxy<T, Storage, Bin> &p) + : proxy(p), result(1) { } + const rvec_t &val() const { result[0] = proxy.val(); return result; } + virtual result_t total() const { return proxy.val(); }; + + virtual size_t size() const { return 1; } +}; + +class VectorStatNode : public Node +{ + private: + const VectorStat &stat; + + public: + VectorStatNode(const VectorStat &s) : stat(s) {} + const rvec_t &val() const { return stat.val(); } + virtual result_t total() const { return stat.total(); }; + + virtual size_t size() const { return stat.size(); } +}; + +template <typename T> +class ConstNode : public Node +{ + private: + rvec_t data; + + public: + ConstNode(T s) : data(1, (result_t)s) {} + const rvec_t &val() const { return data; } + virtual result_t total() const { return data[0]; }; + + virtual size_t size() const { return 1; } +}; + +template <typename T> +class FunctorNode : public Node +{ + private: + T &functor; + mutable rvec_t result; + + public: + FunctorNode(T &f) : functor(f) { result.resize(1); } + const rvec_t &val() const { + result[0] = (result_t)functor(); + return result; + } + virtual result_t total() const { return (result_t)functor(); }; + + virtual size_t size() const { return 1; } +}; + +template <typename T> +class ScalarNode : public Node +{ + private: + T &scalar; + mutable rvec_t result; + + public: + ScalarNode(T &s) : scalar(s) { result.resize(1); } + const rvec_t &val() const { + result[0] = (result_t)scalar; + return result; + } + virtual result_t total() const { return (result_t)scalar; }; + + virtual size_t size() const { return 1; } +}; + +template <class Op> +class UnaryNode : public Node +{ + public: + NodePtr l; + mutable rvec_t result; + + public: + UnaryNode(NodePtr p) : l(p) {} + + const rvec_t &val() const { + const rvec_t &lvec = l->val(); + int size = lvec.size(); + + assert(size > 0); + + result.resize(size); + Op op; + for (int i = 0; i < size; ++i) + result[i] = op(lvec[i]); + + return result; + } + + result_t total() const { + Op op; + return op(l->total()); + } + + virtual size_t size() const { return l->size(); } +}; + +template <class Op> +class BinaryNode : public Node +{ + public: + NodePtr l; + NodePtr r; + mutable rvec_t result; + + public: + BinaryNode(NodePtr a, NodePtr b) : l(a), r(b) {} + + const rvec_t &val() const { + Op op; + const rvec_t &lvec = l->val(); + const rvec_t &rvec = r->val(); + + assert(lvec.size() > 0 && rvec.size() > 0); + + if (lvec.size() == 1 && rvec.size() == 1) { + result.resize(1); + result[0] = op(lvec[0], rvec[0]); + } else if (lvec.size() == 1) { + int size = rvec.size(); + result.resize(size); + for (int i = 0; i < size; ++i) + result[i] = op(lvec[0], rvec[i]); + } else if (rvec.size() == 1) { + int size = lvec.size(); + result.resize(size); + for (int i = 0; i < size; ++i) + result[i] = op(lvec[i], rvec[0]); + } else if (rvec.size() == lvec.size()) { + int size = rvec.size(); + result.resize(size); + for (int i = 0; i < size; ++i) + result[i] = op(lvec[i], rvec[i]); + } + + return result; + } + + result_t total() const { + Op op; + return op(l->total(), r->total()); + } + + virtual size_t size() const { + int ls = l->size(); + int rs = r->size(); + if (ls == 1) + return rs; + else if (rs == 1) + return ls; + else { + assert(ls == rs && "Node vector sizes are not equal"); + return ls; + } + } +}; + +template <class Op> +class SumNode : public Node +{ + public: + NodePtr l; + mutable rvec_t result; + + public: + SumNode(NodePtr p) : l(p), result(1) {} + + const rvec_t &val() const { + const rvec_t &lvec = l->val(); + int size = lvec.size(); + assert(size > 0); + + result[0] = 0.0; + + Op op; + for (int i = 0; i < size; ++i) + result[0] = op(result[0], lvec[i]); + + return result; + } + + result_t total() const { + const rvec_t &lvec = l->val(); + int size = lvec.size(); + assert(size > 0); + + result_t result = 0.0; + + Op op; + for (int i = 0; i < size; ++i) + result = op(result, lvec[i]); + + return result; + } + + virtual size_t size() const { return 1; } +}; + +class Temp +{ + private: + NodePtr node; + + public: + Temp(NodePtr n) : node(n) {} + Temp(const ScalarStat &s) : node(new ScalarStatNode(s)) {} + template <typename T, template <typename T> class Storage, class Bin> + Temp(const ScalarProxy<T, Storage, Bin> &p) + : node(new ScalarProxyNode<T, Storage, Bin>(p)) {} + Temp(const VectorStat &s) : node(new VectorStatNode(s)) {} + +#define TempSCALAR(T) \ + Temp(T value) : node(new ConstNode<T>(value)) {} + + TempSCALAR( signed char); + TempSCALAR(unsigned char); + TempSCALAR( signed short); + TempSCALAR(unsigned short); + TempSCALAR( signed int); + TempSCALAR(unsigned int); + TempSCALAR( signed long); + TempSCALAR(unsigned long); + TempSCALAR( signed long long); + TempSCALAR(unsigned long long); + TempSCALAR(float); + TempSCALAR(double); +#undef TempSCALAR + + operator NodePtr() { return node;} +}; + + +////////////////////////////////////////////////////////////////////// +// +// Binning Interface +// +////////////////////////////////////////////////////////////////////// + +class BinBase +{ + private: + off_t memsize; + char *mem; + + protected: + off_t size() const { return memsize; } + char *memory(); + + public: + BinBase(size_t size); + ~BinBase(); +}; + +} // namespace Detail + +template <class BinType> +struct StatBin : public Detail::BinBase +{ + static StatBin *&curBin() { + static StatBin *current = NULL; + return current; + } + + static void setCurBin(StatBin *bin) { curBin() = bin; } + static StatBin *current() { assert(curBin()); return curBin(); } + + static off_t &offset() { + static off_t offset = 0; + return offset; + } + + static off_t new_offset(size_t size) { + size_t mask = sizeof(u_int64_t) - 1; + off_t off = offset(); + + // That one is for the last trailing flags byte. + offset() += (size + 1 + mask) & ~mask; + + return off; + } + + explicit StatBin(size_t size = 1024) : Detail::BinBase(size) {} + + char *memory(off_t off) { + assert(offset() <= size()); + return Detail::BinBase::memory() + off; + } + + static void activate(StatBin &bin) { setCurBin(&bin); } + + class BinBase + { + private: + int offset; + + public: + BinBase() : offset(-1) {} + void allocate(size_t size) { + offset = new_offset(size); + } + char *access() { + assert(offset != -1); + return current()->memory(offset); + } + }; + + template <class Storage> + class Bin : public BinBase + { + public: + typedef typename Storage::Params Params; + + public: + Bin() { allocate(sizeof(Storage)); } + bool initialized() const { return true; } + void init(const Params ¶ms) { } + + int size() const { return 1; } + + Storage *data(const Params ¶ms) { + assert(initialized()); + char *ptr = access(); + char *flags = ptr + sizeof(Storage); + if (!(*flags & 0x1)) { + *flags |= 0x1; + new (ptr) Storage(params); + } + return reinterpret_cast<Storage *>(ptr); + } + }; + + template <class Storage> + class VectorBin : public BinBase + { + public: + typedef typename Storage::Params Params; + + private: + int _size; + + public: + VectorBin() : _size(0) {} + + bool initialized() const { return _size > 0; } + void init(int s, const Params ¶ms) { + assert(!initialized()); + assert(s > 0); + _size = s; + allocate(_size * sizeof(Storage)); + } + + int size() const { return _size; } + + Storage *data(int index, const Params ¶ms) { + assert(initialized()); + assert(index >= 0 && index < size()); + char *ptr = access(); + char *flags = ptr + size() * sizeof(Storage); + if (!(*flags & 0x1)) { + *flags |= 0x1; + for (int i = 0; i < size(); ++i) + new (ptr + i * sizeof(Storage)) Storage(params); + } + return reinterpret_cast<Storage *>(ptr + index * sizeof(Storage)); + } + }; +}; + +class MainBinType {}; +typedef StatBin<MainBinType> MainBin; + +struct NoBin +{ + template <class Storage> + struct Bin + { + public: + typedef typename Storage::Params Params; + + private: + char ptr[sizeof(Storage)]; + + public: + bool initialized() const { return true; } + void init(const Params ¶ms) { + new (ptr) Storage(params); + } + int size() const{ return 1; } + Storage *data(const Params ¶ms) { + assert(initialized()); + return reinterpret_cast<Storage *>(ptr); + } + }; + + template <class Storage> + struct VectorBin + { + public: + typedef typename Storage::Params Params; + + private: + char *ptr; + int _size; + + public: + VectorBin() : ptr(NULL) { } + ~VectorBin() { + if (initialized()) + delete [] ptr; + } + bool initialized() const { return ptr != NULL; } + void init(int s, const Params ¶ms) { + assert(s > 0 && "size must be positive!"); + assert(!initialized()); + _size = s; + ptr = new char[_size * sizeof(Storage)]; + for (int i = 0; i < _size; ++i) + new (ptr + i * sizeof(Storage)) Storage(params); + } + + int size() const { return _size; } + + Storage *data(int index, const Params ¶ms) { + assert(initialized()); + assert(index >= 0 && index < size()); + return reinterpret_cast<Storage *>(ptr + index * sizeof(Storage)); + } + }; +}; + +////////////////////////////////////////////////////////////////////// +// +// Visible Statistics Types +// +////////////////////////////////////////////////////////////////////// +template <typename T = Counter, class Bin = NoBin> +class Scalar : public Detail::ScalarBase<T, Detail::StatStor, Bin> +{ + public: + typedef Detail::ScalarBase<T, Detail::StatStor, Bin> Base; + + template <typename U> + void operator=(const U& v) { Base::operator=(v); } +}; + +template <typename T = Counter, class Bin = NoBin> +class Average : public Detail::ScalarBase<T, Detail::AvgStor, Bin> +{ + public: + typedef Detail::ScalarBase<T, Detail::AvgStor, Bin> Base; + + template <typename U> + void operator=(const U& v) { Base::operator=(v); } +}; + +template <typename T = Counter, class Bin = NoBin> +class Vector : public Detail::VectorBase<T, Detail::StatStor, Bin> +{ }; + +template <typename T = Counter, class Bin = NoBin> +class AverageVector : public Detail::VectorBase<T, Detail::AvgStor, Bin> +{ }; + +template <typename T = Counter, class Bin = NoBin> +class Vector2d : public Detail::Vector2dBase<T, Detail::StatStor, Bin> +{ }; + +template <typename T = Counter, class Bin = NoBin> +class Distribution : public Detail::DistBase<T, Detail::DistStor, Bin> +{ + private: + typedef Detail::DistBase<T, Detail::DistStor, Bin> Base; + typedef typename Detail::DistStor<T>::Params Params; + + public: + Distribution &init(T min, T max, int bkt) { + params.min = min; + params.max = max; + params.bucket_size = bkt; + params.size = (max - min) / bkt + 1; + bin.init(params); + setInit(); + + return *this; + } +}; + +template <typename T = Counter, class Bin = NoBin> +class StandardDeviation : public Detail::DistBase<T, Detail::FancyStor, Bin> +{ + private: + typedef Detail::DistBase<T, Detail::DistStor, Bin> Base; + typedef typename Detail::DistStor<T>::Params Params; + + public: + StandardDeviation() { + bin.init(params); + setInit(); + } +}; + +template <typename T = Counter, class Bin = NoBin> +class AverageDeviation : public Detail::DistBase<T, Detail::AvgFancy, Bin> +{ + private: + typedef Detail::DistBase<T, Detail::DistStor, Bin> Base; + typedef typename Detail::DistStor<T>::Params Params; + + public: + AverageDeviation() { + bin.init(params); + setInit(); + } +}; + +template <typename T = Counter, class Bin = NoBin> +class VectorDistribution + : public Detail::VectorDistBase<T, Detail::DistStor, Bin> +{ + private: + typedef Detail::VectorDistBase<T, Detail::DistStor, Bin> Base; + typedef typename Detail::DistStor<T>::Params Params; + + public: + VectorDistribution &init(int size, T min, T max, int bkt) { + params.min = min; + params.max = max; + params.bucket_size = bkt; + params.size = (max - min) / bkt + 1; + bin.init(size, params); + setInit(); + + return *this; + } +}; + +template <typename T = Counter, class Bin = NoBin> +class VectorStandardDeviation + : public Detail::VectorDistBase<T, Detail::FancyStor, Bin> +{ + private: + typedef Detail::VectorDistBase<T, Detail::FancyStor, Bin> Base; + typedef typename Detail::DistStor<T>::Params Params; + + public: + VectorStandardDeviation &init(int size) { + bin.init(size, params); + setInit(); + + return *this; + } +}; + +template <typename T = Counter, class Bin = NoBin> +class VectorAverageDeviation + : public Detail::VectorDistBase<T, Detail::AvgFancy, Bin> +{ + private: + typedef Detail::VectorDistBase<T, Detail::AvgFancy, Bin> Base; + typedef typename Detail::DistStor<T>::Params Params; + + public: + VectorAverageDeviation &init(int size) { + bin.init(size, params); + setInit(); + + return *this; + } +}; + +class Formula : public Detail::VectorStat +{ + private: + Detail::NodePtr root; + friend class Detail::Temp; + + public: + Formula() : VectorStat(true) { setInit(); } + Formula(Detail::Temp r) : VectorStat(true) { + root = r; + assert(size()); + } + + const Formula &operator=(Detail::Temp r) { + assert(!root && "Can't change formulas"); + root = r; + assert(size()); + return *this; + } + + const Formula &operator+=(Detail::Temp r) { + using namespace Detail; + if (root) + root = NodePtr(new BinaryNode<std::plus<result_t> >(root, r)); + else + root = r; + assert(size()); + return *this; + } + + const rvec_t &val() const { return root->val(); } + result_t total() const { return root->total(); } + + size_t size() const { + if (!root) + return 0; + else + return root->size(); + } +}; + +void check(); +void dump(std::ostream &stream); + +inline Detail::Temp +operator+(Detail::Temp l, Detail::Temp r) +{ + using namespace Detail; + return NodePtr(new BinaryNode<std::plus<result_t> >(l, r)); +} + +inline Detail::Temp +operator-(Detail::Temp l, Detail::Temp r) +{ + using namespace Detail; + return NodePtr(new BinaryNode<std::minus<result_t> >(l, r)); +} + +inline Detail::Temp +operator*(Detail::Temp l, Detail::Temp r) +{ + using namespace Detail; + return NodePtr(new BinaryNode<std::multiplies<result_t> >(l, r)); +} + +inline Detail::Temp +operator/(Detail::Temp l, Detail::Temp r) +{ + using namespace Detail; + return NodePtr(new BinaryNode<std::divides<result_t> >(l, r)); +} + +inline Detail::Temp +operator%(Detail::Temp l, Detail::Temp r) +{ + using namespace Detail; + return NodePtr(new BinaryNode<std::modulus<result_t> >(l, r)); +} + +inline Detail::Temp +operator-(Detail::Temp l) +{ + using namespace Detail; + return NodePtr(new UnaryNode<std::negate<result_t> >(l)); +} + +template <typename T> +inline Detail::Temp +constant(T val) +{ + using namespace Detail; + return NodePtr(new ConstNode<T>(val)); +} + +template <typename T> +inline Detail::Temp +functor(T &val) +{ + using namespace Detail; + return NodePtr(new FunctorNode<T>(val)); +} + +template <typename T> +inline Detail::Temp +scalar(T &val) +{ + using namespace Detail; + return NodePtr(new ScalarNode<T>(val)); +} + +inline Detail::Temp +sum(Detail::Temp val) +{ + using namespace Detail; + return NodePtr(new SumNode<std::plus<result_t> >(val)); +} + +extern bool PrintDescriptions; + +} // namespace statistics + +#endif // __STATISTICS_HH__ diff --git a/base/str.cc b/base/str.cc new file mode 100644 index 000000000..f54729813 --- /dev/null +++ b/base/str.cc @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <iostream> + +#include <string.h> +#include <ctype.h> + +#include <string> +#include <vector> + +#include "intmath.h" +#include "str.hh" + +using namespace std; + +void +tokenize(vector<string>& v, const string &s, char token, bool ignore) +{ + string::size_type first = 0; + string::size_type last = s.find_first_of(token); + + if (ignore) { + if (last == first) { + while (last == first) + last = s.find_first_of(token, ++first); + + if (last == string::npos) { + v.push_back(s); + return; + } + } + } + + while (last != string::npos) { + v.push_back(s.substr(first, last - first)); + + if (ignore) { + first = s.find_first_not_of(token, last + 1); + + if (first == string::npos) + return; + } else + first = last + 1; + + last = s.find_first_of(token, first); + } + + v.push_back(s.substr(first)); +} + +template <class T> +inline bool +__to_number(string value, T &retval) +{ + static const T maxnum = ((T)-1); + static const bool sign = maxnum < 0; + static const T hexmax = maxnum & (((T)1 << (sizeof(T) * 8 - 4)) - 1); + static const T octmax = maxnum & (((T)1 << (sizeof(T) * 8 - 3)) - 1); + static const T signmax = + (sign) ? maxnum & (((T)1 << (sizeof(T) * 8 - 1)) - 1) : maxnum; + static const T decmax = signmax / 10 - 1; + +#if 0 + cout << "maxnum = 0x" << hex << maxnum << "\n" + << "sign = 0x" << hex << sign << "\n" + << "hexmax = 0x" << hex << hexmax << "\n" + << "octmax = 0x" << hex << octmax << "\n" + << "signmax = 0x" << hex << signmax << "\n" + << "decmax = 0x" << hex << decmax << "\n"; +#endif + + eat_white(value); + + bool negative = false; + bool hex = false; + bool oct = false; + int last = value.size() - 1; + retval = 0; + int i = 0; + + char c = value[i]; + if (!IsDec(c)) { + if (c == '-' && sign) + negative = true; + else + return false; + } + else { + retval += c - '0'; + if (last == 0) return true; + } + + if (c == '0') + oct = true; + + c = value[++i]; + if (oct) { + if (sign && negative) + return false; + + if (!IsOct(c)) { + if (c == 'X' || c == 'x') { + hex = true; + oct = false; + } else + return false; + } + else + retval += c - '0'; + } else if (!IsDec(c)) + goto multiply; + else { + if (sign && negative && c == '0') + return false; + + retval *= 10; + retval += c - '0'; + if (last == 1) { + if (sign && negative) retval = -retval; + return true; + } + } + + if (hex) { + if (last == 1) + return false; + + for (i = 2; i <= last ; i++) { + c = value[i]; + if (!IsHex(c)) + return false; + + if (retval > hexmax) return false; + retval *= 16; + retval += Hex2Int(c); + } + return true; + } else if (oct) { + for (i = 2; i <= last ; i++) { + c = value[i]; + if (!IsOct(c)) + return false; + + if (retval > octmax) return false; + retval *= 8; + retval += (c - '0'); + } + return true; + } + + for (i = 2; i < last ; i++) { + c = value[i]; + if (!IsDec(c)) + goto multiply; + + if (retval > decmax) return false; + retval *= 10; + retval += c - '0'; + if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1)))) + return false; + } + + c = value[last]; + if (IsDec(c)) { + + if (retval > decmax) return false; + retval *= 10; + retval += c - '0'; + if (sign && negative) { + if ((retval & ((T)1 << (sizeof(T) * 8 - 1))) && + retval >= (T)-signmax) + return false; + retval = -retval; + } + else + if (sign && (retval & ((T)1 << ((sizeof(T) * 8) - 1)))) + return false; + return true; + } + + multiply: + signed long long mult = 1; + T val; + switch (c) { + case 'k': + case 'K': + if (i != last) return false; + mult = 1024; + val = signmax / mult; + break; + case 'm': + case 'M': + if (i != last) return false; + mult = 1024 * 1024; + val = signmax / mult; + break; + case 'g': + case 'G': + if (i != last) return false; + mult = 1024 * 1024 * 1024; + val = signmax / mult; + break; + case 'e': + case 'E': + if (i >= last) return false; + + mult = 0; + for (i++; i <= last; i++) { + c = value[i]; + if (!IsDec(c)) + return false; + + mult *= 10; + mult += c - '0'; + } + + for (i = 0; i < mult; i++) { + if (retval > signmax / 10) + return false; + retval *= 10; + if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1)))) + return false; + } + if (sign && negative) { + if ((retval & ((T)1 << (sizeof(T) * 8 - 1))) && + retval >= (T)-signmax) + return false; + retval = -retval; + } + else + if (sign && (retval & ((T)1 << ((sizeof(T) * 8) - 1)))) + return false; + + return true; + + default: + return false; + } + + if (sign && negative) + return false; + + if (mult > (unsigned long long)signmax) + return false; + + if (retval > val) + return false; + + retval *= mult; + + return true; +} + +#define STN(type) \ +template<> \ +bool to_number<type>(const string &value, type &retval) \ +{ return __to_number(value, retval); } + +STN(unsigned long long); +STN(signed long long); +STN(unsigned long); +STN(signed long); +STN(unsigned int); +STN(signed int); +STN(unsigned short); +STN(signed short); +STN(unsigned char); +STN(signed char); + +template<> +bool to_number<bool>(const string &value, bool &retval) +{ + string lowered = to_lower(value); + + if (value == "0") { + retval = false; + return true; + } + + if (value == "1"){ + retval = true; + return true; + } + + if (lowered == "false") { + retval = false; + return true; + } + + if (lowered == "true"){ + retval = true; + return true; + } + + if (lowered == "no") { + retval = false; + return true; + } + + if (lowered == "yes"){ + retval = true; + return true; + } + + return false; +} diff --git a/base/str.hh b/base/str.hh new file mode 100644 index 000000000..29d2c03db --- /dev/null +++ b/base/str.hh @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __STR_HH__ +#define __STR_HH__ + +#include <sstream> +#include <string> +#include <vector> + +#include <ctype.h> + +template<class> class Hash; +template<> +class Hash<std::string> { +public: + unsigned operator()(const std::string &s) { + std::string::const_iterator i = s.begin(); + std::string::const_iterator end = s.end(); + unsigned hash = 5381; + + while (i < end) + hash = ((hash << 5) + hash) + *i++; + + return hash; + } +}; + +inline void +eat_lead_white(std::string &s) +{ + std::string::size_type off = s.find_first_not_of(' '); + if (off != std::string::npos) { + std::string::iterator begin = s.begin(); + s.erase(begin, begin + off); + } +} + +inline void +eat_end_white(std::string &s) +{ + std::string::size_type off = s.find_last_not_of(' '); + if (off != std::string::npos) + s.erase(s.begin() + off + 1, s.end()); +} + +inline void +eat_white(std::string &s) +{ + eat_lead_white(s); + eat_end_white(s); +} + +inline std::string +to_lower(const std::string &s) +{ + std::string lower; + int len = s.size(); + + lower.reserve(len); + + for (int i = 0; i < len; ++i) + lower.push_back(tolower(s[i])); + + return lower; +} + +void +tokenize(std::vector<std::string> &vector, const std::string &s, + char token, bool ign = true); + +template <class T> bool +to_number(const std::string &value, T &retval); + +template <class T> +std::string +to_string(const T& value) +{ + std::stringstream str; + str << value; + return str.str(); +} + +// Put quotes around string arg if it contains spaces. +inline std::string +quote(const std::string &s) +{ + std::string ret; + bool quote = s.find(' ') != std::string::npos; + + if (quote) + ret = '"'; + + ret += s; + + if (quote) + ret += '"'; + + return ret; +} + +#endif //__STR_HH__ diff --git a/base/symtab.cc b/base/symtab.cc new file mode 100644 index 000000000..7beee182b --- /dev/null +++ b/base/symtab.cc @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <iostream> +#include <fstream> +#include <string> +#include <vector> + +#include "host.hh" +#include "misc.hh" +#include "str.hh" +#include "symtab.hh" + +using namespace std; + +bool +SymbolTable::insert(Addr address, string symbol) +{ + if (!addrTable.insert(make_pair(address, symbol)).second) + return false; + + if (!symbolTable.insert(make_pair(symbol, address)).second) + return false; + + return true; +} + + +bool +SymbolTable::load(const string &filename) +{ + string buffer; + ifstream file(filename.c_str()); + + if (!file) { + cerr << "Can't open symbol table file " << filename << endl; + fatal("file error"); + } + + while (!file.eof()) { + getline(file, buffer); + if (buffer.empty()) + continue; + + int idx = buffer.find(','); + if (idx == string::npos) + return false; + + string address = buffer.substr(0, idx); + eat_white(address); + if (address.empty()) + return false; + + string symbol = buffer.substr(idx + 1); + eat_white(symbol); + if (symbol.empty()) + return false; + + Addr addr; + if (!to_number(address, addr)) + return false; + + if (!insert(addr, symbol)) + return false; + } + + file.close(); + + return true; +} + +bool +SymbolTable::findSymbol(Addr address, string &symbol) const +{ + ATable::const_iterator i = addrTable.find(address); + if (i == addrTable.end()) + return false; + + symbol = (*i).second; + return true; +} + +bool +SymbolTable::findAddress(const string &symbol, Addr &address) const +{ + STable::const_iterator i = symbolTable.find(symbol); + if (i == symbolTable.end()) + return false; + + address = (*i).second; + return true; +} + +string +SymbolTable::find(Addr addr) const +{ + string s; + findSymbol(addr, s); + return s; +} + +Addr +SymbolTable::find(const string &symbol) const +{ + Addr a = 0; + findAddress(symbol, a); + return a; +} diff --git a/base/symtab.hh b/base/symtab.hh new file mode 100644 index 000000000..073325eba --- /dev/null +++ b/base/symtab.hh @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SYMTAB_HH__ +#define __SYMTAB_HH__ + +#include "hashmap.hh" +#include "isa_traits.hh" // for Addr + +class SymbolTable +{ + private: + typedef m5::hash_map<Addr, std::string> ATable; + typedef m5::hash_map<std::string, Addr> STable; + + ATable addrTable; + STable symbolTable; + + public: + SymbolTable() {} + SymbolTable(const std::string &file) { load(file); } + ~SymbolTable() {} + + bool insert(Addr address, std::string symbol); + bool load(const std::string &file); + + bool findSymbol(Addr address, std::string &symbol) const; + bool findAddress(const std::string &symbol, Addr &address) const; + + std::string find(Addr addr) const; + Addr find(const std::string &symbol) const; +}; + +#endif // __SYMTAB_HH__ diff --git a/base/trace.cc b/base/trace.cc new file mode 100644 index 000000000..d1baf3000 --- /dev/null +++ b/base/trace.cc @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <ctype.h> +#include <fstream> +#include <iostream> +#include <list> +#include <string> +#include <vector> + +#include "misc.hh" +#include "trace.hh" +#include "str.hh" + +using namespace std; + +namespace Trace { +const string DefaultName("global"); +FlagVec flags(NumFlags, false); + +// +// This variable holds the output stream for debug information. Other +// than setting up/redirecting this stream, do *NOT* reference this +// directly; use DebugOut() (see below) to access this stream for +// output. +// +ostream *dprintf_stream = NULL; + +int dprintf_ignore_size; +vector<string> dprintf_ignore; +vector<vector<string> > ignore_tokens; +vector<int> ignore_size; + +bool +dprintf_ignore_name(const string &name) +{ + vector<string> name_tokens; + tokenize(name_tokens, name, '.'); + int ntsize = name_tokens.size(); + + for (int i = 0; i < dprintf_ignore_size; ++i) { + bool match = true; + int jstop = ignore_size[i]; + for (int j = 0; j < jstop; ++j) { + if (j >= ntsize) + break; + + const string &ignore = ignore_tokens[i][j]; + if (ignore != "*" && ignore != name_tokens[j]) { + match = false; + break; + } + } + + if (match == true) + return true; + } + + return false; +} + + +Log theLog; + +Log::Log() +{ + size = 0; + buffer = NULL; +} + + +void +Log::init(int _size) +{ + if (buffer != NULL) { + fatal("Trace::Log::init called twice!"); + } + + size = _size; + + buffer = new (Record *)[size]; + + for (int i = 0; i < size; ++i) { + buffer[i] = NULL; + } + + nextRecPtr = &buffer[0]; + wrapRecPtr = &buffer[size]; +} + + +Log::~Log() +{ + for (int i = 0; i < size; ++i) { + delete buffer[i]; + } + + delete [] buffer; +} + + +void +Log::append(Record *rec) +{ + // dump record to output stream if there's one open + if (dprintf_stream != NULL) { + rec->dump(*dprintf_stream); + } + + // no buffering: justget rid of it now + if (buffer == NULL) { + delete rec; + return; + } + + Record *oldRec = *nextRecPtr; + + if (oldRec != NULL) { + // log has wrapped: overwrite + delete oldRec; + } + + *nextRecPtr = rec; + + if (++nextRecPtr == wrapRecPtr) { + nextRecPtr = &buffer[0]; + } +} + + +void +Log::dump(ostream &os) +{ + if (buffer == NULL) { + return; + } + + Record **bufPtr = nextRecPtr; + + if (*bufPtr == NULL) { + // next record slot is empty: log must not be full yet. + // start dumping from beginning of buffer + bufPtr = buffer; + } + + do { + Record *rec = *bufPtr; + + rec->dump(os); + + if (++bufPtr == wrapRecPtr) { + bufPtr = &buffer[0]; + } + } while (bufPtr != nextRecPtr); +} + +PrintfRecord::~PrintfRecord() +{ + delete &args; +} + + +void +PrintfRecord::dump(ostream &os) +{ + string fmt = ""; + + if (!name.empty()) { + fmt = "%s: " + fmt; + args.prepend(name); + } + + if (cycle != (Tick)-1) { + fmt = "%7d: " + fmt; + args.prepend(cycle); + } + + fmt += format; + + args.dump(os, fmt); + os.flush(); +} + + + +RawDataRecord::RawDataRecord(Tick _cycle, + const uint8_t *_data, int _len) + : Record(_cycle), len(_len) +{ + data = new uint8_t[len]; + memcpy(data, _data, len); +} + + +RawDataRecord::~RawDataRecord() +{ + delete [] data; +} + + +void +RawDataRecord::dump(ostream &os) +{ + int c, i, j; + + for (i = 0; i < len; i += 16) { + ccprintf(os, "%08x ", i); + c = len - i; + if (c > 16) c = 16; + + for (j = 0; j < c; j++) { + ccprintf(os, "%02x ", data[i + j] & 0xff); + if ((j & 0xf) == 7 && j > 0) + ccprintf(os, " "); + } + + for (; j < 16; j++) + ccprintf(os, " "); + ccprintf(os, " "); + + for (j = 0; j < c; j++) { + int ch = data[i + j] & 0x7f; + ccprintf(os, + "%c", (char)(isprint(ch) ? ch : ' ')); + } + + ccprintf(os, "\n"); + + if (c < 16) + break; + } +} +} // namespace Trace + +// +// Returns the current output stream for debug information. As a +// wrapper around Trace::dprintf_stream, this handles cases where debug +// information is generated in the process of parsing .ini options, +// before we process the option that sets up the debug output stream +// itself. +// +std::ostream & +DebugOut() +{ + if (Trace::dprintf_stream) + return *Trace::dprintf_stream; + else + return cerr; +} + +///////////////////////////////////////////// +// +// C-linkage functions for invoking from gdb +// +///////////////////////////////////////////// + +// +// Dump trace buffer to specified file (cout if NULL) +// +extern "C" +void +dumpTrace(const char *filename) +{ + if (filename != NULL) { + ofstream out(filename); + Trace::theLog.dump(out); + out.close(); + } + else { + Trace::theLog.dump(cout); + } +} + + +// +// Turn on/off trace output to cerr. Typically used when trace output +// is only going to circular buffer, but you want to see what's being +// sent there as you step through some code in gdb. This uses the +// same facility as the "trace to file" feature, and will print error +// messages rather than clobbering an existing ostream pointer. +// +extern "C" +void +echoTrace(bool on) +{ + if (on) { + if (Trace::dprintf_stream != NULL) { + cerr << "Already echoing trace to a file... go do a 'tail -f'" + << " on that file instead." << endl; + } else { + Trace::dprintf_stream = &cerr; + } + } else { + if (Trace::dprintf_stream != &cerr) { + cerr << "Not echoing trace to cerr." << endl; + } else { + Trace::dprintf_stream = NULL; + } + } +} diff --git a/base/trace.hh b/base/trace.hh new file mode 100644 index 000000000..42cd1722b --- /dev/null +++ b/base/trace.hh @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TRACE_HH__ +#define __TRACE_HH__ + +#include <vector> + +#include "cprintf.hh" +#include "host.hh" +#include "universe.hh" + +#ifndef TRACING_ON +#ifdef DEBUG +#define TRACING_ON 1 +#else +#define TRACING_ON 0 +#endif +#endif + +#include "trace_flags.hh" + +namespace Trace { + + typedef std::vector<bool> FlagVec; + + extern FlagVec flags; + +#if TRACING_ON + const bool On = true; +#else + const bool On = false; +#endif + + inline bool + IsOn(int t) + { + return flags[t]; + + } + + void dump(const uint8_t *data, int count); + + class Record + { + protected: + Tick cycle; + + Record(Tick _cycle) + : cycle(_cycle) + { + } + + public: + virtual ~Record() {} + + virtual void dump(std::ostream &) = 0; + }; + + class PrintfRecord : public Record + { + private: + const char *format; + const std::string &name; + cp::ArgList &args; + + public: + PrintfRecord(const char *_format, cp::ArgList &_args, + Tick cycle, const std::string &_name) + : Record(cycle), format(_format), name(_name), args(_args) + { + } + + virtual ~PrintfRecord(); + + virtual void dump(std::ostream &); + }; + + class RawDataRecord : public Record + { + private: + uint8_t *data; + int len; + + public: + RawDataRecord(Tick cycle, const uint8_t *_data, int _len); + virtual ~RawDataRecord(); + + virtual void dump(std::ostream &); + }; + + class Log + { + private: + int size; // number of records in log + Record **buffer; // array of 'size' Record ptrs (circular buf) + Record **nextRecPtr; // next slot to use in buffer + Record **wrapRecPtr; // &buffer[size], for quick wrap check + + public: + + Log(); + ~Log(); + + void init(int _size); + + void append(Record *); // append trace record to log + void dump(std::ostream &); // dump contents to stream + }; + + extern Log theLog; + + extern int dprintf_ignore_size; + + bool + dprintf_ignore_name(const std::string &name); + + inline void + dprintf(const char *format, cp::ArgList &args, Tick cycle, + const std::string &name) + { + if (!dprintf_ignore_size || name.empty() || !dprintf_ignore_name(name)) + theLog.append(new Trace::PrintfRecord(format, args, cycle, name)); + } + + inline void + rawDump(const uint8_t *data, int len) + { + theLog.append(new Trace::RawDataRecord(curTick, data, len)); + } + + extern const std::string DefaultName; +}; + +inline const std::string &name() { return Trace::DefaultName; } + +std::ostream &DebugOut(); + +// +// DPRINTF is a debugging trace facility that allows one to +// selectively enable tracing statements. To use DPRINTF, there must +// be a function or functor called name() that returns a const +// std::string & in the current scope. +// +// If you desire that the automatic printing not occur, use DPRINTFR +// (R for raw) +// + +#if TRACING_ON + +#define DTRACE(x) (Trace::IsOn(Trace::x)) + +#define DCOUT(x) if (Trace::IsOn(Trace::x)) DebugOut() + +#define DDUMP(x, data, count) \ +do { \ + using namespace Trace; \ + if (Trace::IsOn(Trace::x)) \ + rawDump(data, count); \ +} while (0) + +#define __dprintf(cycle, name, format, args...) \ + Trace::dprintf(format, (*(new cp::ArgList), args), cycle, name) + +#define DPRINTF(x, args...) \ +do { \ + if (Trace::IsOn(Trace::x)) \ + __dprintf(curTick, name(), args, cp::ArgListNull()); \ +} while (0) + +#define DPRINTFR(x, args...) \ +do { \ + if (Trace::IsOn(Trace::x)) \ + __dprintf((Tick)-1, string(), args, cp::ArgListNull()); \ +} while (0) + +#define DPRINTFN(args...) \ +do { \ + __dprintf(curTick, name(), args, cp::ArgListNull()); \ +} while (0) + +#else // !TRACING_ON + +#define DTRACE(x) (false) +#define DCOUT(x) if (0) DebugOut() +#define DPRINTF(x, args...) do {} while(0) +#define DPRINTFR(args...) do {} while(0) +#define DPRINTFN(args...) do {} while(0) +#define DDUMP(x, data, count) do {} while(0) + +#endif // TRACING_ON + +#endif // __TRACE_HH__ |