PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/rlib/debug.py

https://bitbucket.org/pypy/pypy/
Python | 452 lines | 436 code | 14 blank | 2 comment | 10 complexity | 914fc0a65cdf2afd800402fc0188c303 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import sys
  2. import time
  3. from rpython.rtyper.extregistry import ExtRegistryEntry
  4. from rpython.rlib.objectmodel import we_are_translated
  5. from rpython.rlib.rarithmetic import is_valid_int
  6. from rpython.rtyper.extfunc import register_external
  7. from rpython.rtyper.lltypesystem import lltype
  8. from rpython.rtyper.lltypesystem import rffi
  9. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  10. # Expose these here (public interface)
  11. from rpython.rtyper.debug import (
  12. ll_assert, FatalError, fatalerror, fatalerror_notb)
  13. class DebugLog(list):
  14. def debug_print(self, *args):
  15. self.append(('debug_print',) + args)
  16. def debug_start(self, category, time=None):
  17. self.append(('debug_start', category, time))
  18. def debug_stop(self, category, time=None):
  19. for i in xrange(len(self) - 1, -1, -1):
  20. if self[i][0] == 'debug_start':
  21. assert self[i][1] == category, (
  22. "nesting error: starts with %r but stops with %r" %
  23. (self[i][1], category))
  24. starttime = self[i][2]
  25. if starttime is not None or time is not None:
  26. self[i:] = [(category, starttime, time, self[i + 1:])]
  27. else:
  28. self[i:] = [(category, self[i + 1:])]
  29. return
  30. assert False, ("nesting error: no start corresponding to stop %r" %
  31. (category,))
  32. def __repr__(self):
  33. import pprint
  34. return pprint.pformat(list(self))
  35. _log = None # patched from tests to be an object of class DebugLog
  36. # or compatible
  37. def debug_print(*args):
  38. for arg in args:
  39. print >> sys.stderr, arg,
  40. print >> sys.stderr
  41. if _log is not None:
  42. _log.debug_print(*args)
  43. class Entry(ExtRegistryEntry):
  44. _about_ = debug_print
  45. def compute_result_annotation(self, *args_s):
  46. return None
  47. def specialize_call(self, hop):
  48. vlist = hop.inputargs(*hop.args_r)
  49. hop.exception_cannot_occur()
  50. t = hop.rtyper.annotator.translator
  51. if t.config.translation.log:
  52. hop.genop('debug_print', vlist)
  53. if sys.stderr.isatty():
  54. _start_colors_1 = "\033[1m\033[31m"
  55. _start_colors_2 = "\033[31m"
  56. _stop_colors = "\033[0m"
  57. else:
  58. _start_colors_1 = ""
  59. _start_colors_2 = ""
  60. _stop_colors = ""
  61. def debug_start(category):
  62. c = int(time.clock() * 100)
  63. print >> sys.stderr, '%s[%x] {%s%s' % (_start_colors_1, c,
  64. category, _stop_colors)
  65. if _log is not None:
  66. _log.debug_start(category)
  67. def debug_stop(category):
  68. c = int(time.clock() * 100)
  69. print >> sys.stderr, '%s[%x] %s}%s' % (_start_colors_2, c,
  70. category, _stop_colors)
  71. if _log is not None:
  72. _log.debug_stop(category)
  73. class Entry(ExtRegistryEntry):
  74. _about_ = debug_start, debug_stop
  75. def compute_result_annotation(self, s_category):
  76. return None
  77. def specialize_call(self, hop):
  78. from rpython.rtyper.lltypesystem.rstr import string_repr
  79. fn = self.instance
  80. vlist = hop.inputargs(string_repr)
  81. hop.exception_cannot_occur()
  82. t = hop.rtyper.annotator.translator
  83. if t.config.translation.log:
  84. hop.genop(fn.__name__, vlist)
  85. def have_debug_prints():
  86. # returns True if the next calls to debug_print show up,
  87. # and False if they would not have any effect.
  88. return True
  89. def have_debug_prints_for(category_prefix):
  90. # returns True if debug prints are enabled for at least some
  91. # category strings starting with "prefix" (must be a constant).
  92. assert len(category_prefix) > 0
  93. return True
  94. class Entry(ExtRegistryEntry):
  95. _about_ = have_debug_prints, have_debug_prints_for
  96. def compute_result_annotation(self, s_prefix=None):
  97. from rpython.annotator import model as annmodel
  98. t = self.bookkeeper.annotator.translator
  99. if t.config.translation.log:
  100. return annmodel.s_Bool
  101. else:
  102. return self.bookkeeper.immutablevalue(False)
  103. def specialize_call(self, hop):
  104. t = hop.rtyper.annotator.translator
  105. hop.exception_cannot_occur()
  106. if t.config.translation.log:
  107. if hop.args_v:
  108. [c_prefix] = hop.args_v
  109. assert len(c_prefix.value) > 0
  110. args = [hop.inputconst(lltype.Void, c_prefix.value)]
  111. return hop.genop('have_debug_prints_for', args,
  112. resulttype=lltype.Bool)
  113. return hop.genop('have_debug_prints', [], resulttype=lltype.Bool)
  114. else:
  115. return hop.inputconst(lltype.Bool, False)
  116. def debug_offset():
  117. """ Return an offset in log file
  118. """
  119. return -1
  120. class Entry(ExtRegistryEntry):
  121. _about_ = debug_offset
  122. def compute_result_annotation(self):
  123. from rpython.annotator import model as annmodel
  124. return annmodel.SomeInteger()
  125. def specialize_call(self, hop):
  126. hop.exception_cannot_occur()
  127. return hop.genop('debug_offset', [], resulttype=lltype.Signed)
  128. def debug_flush():
  129. """ Flushes the debug file
  130. """
  131. pass
  132. class Entry(ExtRegistryEntry):
  133. _about_ = debug_flush
  134. def compute_result_annotation(self):
  135. return None
  136. def specialize_call(self, hop):
  137. hop.exception_cannot_occur()
  138. return hop.genop('debug_flush', [])
  139. def debug_forked(original_offset):
  140. """ Call after a fork(), passing as argument the result of
  141. debug_offset() called before the fork.
  142. """
  143. pass
  144. class Entry(ExtRegistryEntry):
  145. _about_ = debug_forked
  146. def compute_result_annotation(self, s_original_offset):
  147. return None
  148. def specialize_call(self, hop):
  149. vlist = hop.inputargs(lltype.Signed)
  150. hop.exception_cannot_occur()
  151. return hop.genop('debug_forked', vlist)
  152. def llinterpcall(RESTYPE, pythonfunction, *args):
  153. """When running on the llinterp, this causes the llinterp to call to
  154. the provided Python function with the run-time value of the given args.
  155. The Python function should return a low-level object of type RESTYPE.
  156. This should never be called after translation: use this only if
  157. running_on_llinterp is true.
  158. """
  159. raise NotImplementedError
  160. class Entry(ExtRegistryEntry):
  161. _about_ = llinterpcall
  162. def compute_result_annotation(self, s_RESTYPE, s_pythonfunction, *args_s):
  163. from rpython.annotator import model as annmodel
  164. from rpython.rtyper.llannotation import lltype_to_annotation
  165. assert s_RESTYPE.is_constant()
  166. assert s_pythonfunction.is_constant()
  167. s_result = s_RESTYPE.const
  168. if isinstance(s_result, lltype.LowLevelType):
  169. s_result = lltype_to_annotation(s_result)
  170. assert isinstance(s_result, annmodel.SomeObject)
  171. return s_result
  172. def specialize_call(self, hop):
  173. from rpython.annotator import model as annmodel
  174. RESTYPE = hop.args_s[0].const
  175. if not isinstance(RESTYPE, lltype.LowLevelType):
  176. assert isinstance(RESTYPE, annmodel.SomeObject)
  177. r_result = hop.rtyper.getrepr(RESTYPE)
  178. RESTYPE = r_result.lowleveltype
  179. pythonfunction = hop.args_s[1].const
  180. c_pythonfunction = hop.inputconst(lltype.Void, pythonfunction)
  181. args_v = [hop.inputarg(hop.args_r[i], arg=i)
  182. for i in range(2, hop.nb_args)]
  183. hop.exception_is_here()
  184. return hop.genop('debug_llinterpcall', [c_pythonfunction] + args_v,
  185. resulttype=RESTYPE)
  186. def check_annotation(arg, checker):
  187. """ Function checking if annotation is as expected when translating,
  188. does nothing when just run. Checker is supposed to be a constant
  189. callable which checks if annotation is as expected,
  190. arguments passed are (current annotation, bookkeeper)
  191. """
  192. return arg
  193. class Entry(ExtRegistryEntry):
  194. _about_ = check_annotation
  195. def compute_result_annotation(self, s_arg, s_checker):
  196. if not s_checker.is_constant():
  197. raise ValueError(
  198. "Second argument of check_annotation must be constant")
  199. checker = s_checker.const
  200. checker(s_arg, self.bookkeeper)
  201. return s_arg
  202. def specialize_call(self, hop):
  203. hop.exception_cannot_occur()
  204. return hop.inputarg(hop.args_r[0], arg=0)
  205. def make_sure_not_resized(arg):
  206. """ Function checking whether annotation of SomeList is never resized,
  207. useful for debugging. Does nothing when run directly
  208. """
  209. return arg
  210. class Entry(ExtRegistryEntry):
  211. _about_ = make_sure_not_resized
  212. def compute_result_annotation(self, s_arg):
  213. from rpython.annotator.model import SomeList, s_None
  214. if s_None.contains(s_arg):
  215. return s_arg # only None: just return
  216. assert isinstance(s_arg, SomeList)
  217. # the logic behind it is that we try not to propagate
  218. # make_sure_not_resized, when list comprehension is not on
  219. config = self.bookkeeper.annotator.translator.config
  220. if config.translation.list_comprehension_operations:
  221. s_arg.listdef.never_resize()
  222. else:
  223. from rpython.annotator.annrpython import log
  224. log.WARNING(
  225. "make_sure_not_resized called, but has no effect since "
  226. "list_comprehension is off")
  227. return s_arg
  228. def specialize_call(self, hop):
  229. hop.exception_cannot_occur()
  230. return hop.inputarg(hop.args_r[0], arg=0)
  231. def mark_dict_non_null(d):
  232. """ Mark dictionary as having non-null keys and values. A warning would
  233. be emitted (not an error!) in case annotation disagrees.
  234. """
  235. assert isinstance(d, dict)
  236. return d
  237. class DictMarkEntry(ExtRegistryEntry):
  238. _about_ = mark_dict_non_null
  239. def compute_result_annotation(self, s_dict):
  240. from rpython.annotator.model import SomeDict
  241. assert isinstance(s_dict, SomeDict)
  242. s_dict.dictdef.force_non_null = True
  243. return s_dict
  244. def specialize_call(self, hop):
  245. hop.exception_cannot_occur()
  246. return hop.inputarg(hop.args_r[0], arg=0)
  247. class IntegerCanBeNegative(Exception):
  248. pass
  249. class UnexpectedRUInt(Exception):
  250. pass
  251. class ExpectedRegularInt(Exception):
  252. pass
  253. def check_nonneg(x):
  254. """Give a translation-time error if 'x' is not known to be non-negative.
  255. To help debugging, this also gives a translation-time error if 'x' is
  256. actually typed as an r_uint (in which case the call to check_nonneg()
  257. is a bit strange and probably unexpected).
  258. """
  259. assert type(x)(-1) < 0 # otherwise, 'x' is a r_uint or similar
  260. assert x >= 0
  261. return x
  262. class Entry(ExtRegistryEntry):
  263. _about_ = check_nonneg
  264. def compute_result_annotation(self, s_arg):
  265. from rpython.annotator.model import SomeInteger
  266. if isinstance(s_arg, SomeInteger) and s_arg.unsigned:
  267. raise UnexpectedRUInt("check_nonneg() arg is a %s" % (
  268. s_arg.knowntype,))
  269. s_nonneg = SomeInteger(nonneg=True)
  270. if not s_nonneg.contains(s_arg):
  271. raise IntegerCanBeNegative
  272. return s_arg
  273. def specialize_call(self, hop):
  274. hop.exception_cannot_occur()
  275. return hop.inputarg(hop.args_r[0], arg=0)
  276. def check_regular_int(x):
  277. """Give a translation-time error if 'x' is not a plain int
  278. (e.g. if it's a r_longlong or an r_uint).
  279. """
  280. assert is_valid_int(x)
  281. return x
  282. class Entry(ExtRegistryEntry):
  283. _about_ = check_regular_int
  284. def compute_result_annotation(self, s_arg):
  285. from rpython.annotator.model import SomeInteger
  286. if not SomeInteger().contains(s_arg):
  287. raise ExpectedRegularInt(s_arg)
  288. return s_arg
  289. def specialize_call(self, hop):
  290. hop.exception_cannot_occur()
  291. return hop.inputarg(hop.args_r[0], arg=0)
  292. def check_list_of_chars(l):
  293. if not we_are_translated():
  294. assert isinstance(l, list)
  295. for x in l:
  296. assert isinstance(x, (unicode, str)) and len(x) == 1
  297. return l
  298. class NotAListOfChars(Exception):
  299. pass
  300. class Entry(ExtRegistryEntry):
  301. _about_ = check_list_of_chars
  302. def compute_result_annotation(self, s_arg):
  303. from rpython.annotator.model import SomeList, s_None
  304. from rpython.annotator.model import SomeChar, SomeUnicodeCodePoint
  305. from rpython.annotator.model import SomeImpossibleValue
  306. if s_None.contains(s_arg):
  307. return s_arg # only None: just return
  308. assert isinstance(s_arg, SomeList)
  309. if not isinstance(
  310. s_arg.listdef.listitem.s_value,
  311. (SomeChar, SomeUnicodeCodePoint, SomeImpossibleValue)):
  312. raise NotAListOfChars
  313. return s_arg
  314. def specialize_call(self, hop):
  315. hop.exception_cannot_occur()
  316. return hop.inputarg(hop.args_r[0], arg=0)
  317. def attach_gdb():
  318. import pdb; pdb.set_trace()
  319. if not sys.platform.startswith('win'):
  320. if sys.platform.startswith('linux'):
  321. # Only necessary on Linux
  322. eci = ExternalCompilationInfo(includes=['string.h', 'assert.h',
  323. 'sys/prctl.h'],
  324. post_include_bits=["""
  325. /* If we have an old Linux kernel (or compile with old system headers),
  326. the following two macros are not defined. But we would still like
  327. a pypy translated on such a system to run on a more modern system. */
  328. #ifndef PR_SET_PTRACER
  329. # define PR_SET_PTRACER 0x59616d61
  330. #endif
  331. #ifndef PR_SET_PTRACER_ANY
  332. # define PR_SET_PTRACER_ANY ((unsigned long)-1)
  333. #endif
  334. static void pypy__allow_attach(void) {
  335. prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY);
  336. }
  337. """])
  338. allow_attach = rffi.llexternal(
  339. "pypy__allow_attach", [], lltype.Void,
  340. compilation_info=eci, _nowrapper=True)
  341. else:
  342. # Do nothing, there's no prctl
  343. def allow_attach():
  344. pass
  345. def impl_attach_gdb():
  346. import os
  347. allow_attach()
  348. pid = os.getpid()
  349. gdbpid = os.fork()
  350. if gdbpid == 0:
  351. shell = os.environ.get("SHELL") or "/bin/sh"
  352. sepidx = shell.rfind(os.sep) + 1
  353. if sepidx > 0:
  354. argv0 = shell[sepidx:]
  355. else:
  356. argv0 = shell
  357. try:
  358. os.execv(shell, [argv0, "-c", "gdb -p %d" % pid])
  359. except OSError as e:
  360. os.write(2, "Could not start GDB: %s" % (
  361. os.strerror(e.errno)))
  362. raise SystemExit
  363. else:
  364. time.sleep(1) # give the GDB time to attach
  365. else:
  366. def impl_attach_gdb():
  367. print "Don't know how to attach GDB on Windows"
  368. register_external(attach_gdb, [], result=None,
  369. export_name="impl_attach_gdb", llimpl=impl_attach_gdb)